`
hoodng
  • 浏览: 20018 次
社区版块
存档分类
最新评论

Javascript日期的Format与Parse

阅读更多

 

 Javascript日期的Format与Parse

  网上已经有很多文章或代码介绍了如何用javascript格式化一个Date对象,但都和自己的应用与要求有一定的差距。尤其是如何Parse一个字符串的日期,大多依赖Date对象的parse方法,在有些应用中如“2012年3月8日”这样的格式就需要进行特殊处理,甚至于据说IE浏览器对“2012-3-8”的格式似乎都不能直接parse(我没有太多这方面的经验)。

  我一直想仿照Java的SimpleDateFormat做一个javascript版的Formatter和Parser以完善 J$VM 项目。最近学习了javascript的正则表达式,并在用javascript进行HTML转义与反转的实现中对正则表达式的应用有了进一步的熟悉。所以决定用正则表达式来比较彻底地实现一个javascript版的SimpleDateFormat。

  估计发明轮子的感觉是我这个年龄的程序员,如果还在(喜欢)编程的唯一的动力了。

** 一、SimpleDateFormat的功能

  参照Java的SimpleDateFormat,这个javascritp版的主要应有以下功能:

*** 1)符合Java的模式符号

  Java在格式化日期提供了很多模式符号,有些是我们几乎从未用过的,在javascript的版本里,主要支持以下的几个符号就基本够日常的应用了。

|--------+------------------------+--------------+-------------|
| Letter | Date or Time Component | Presentation | Examples    |
|--------+------------------------+--------------+-------------|
| G      | Era designator         | Text         | AD; BC      |
|--------+------------------------+--------------+-------------|
| y      | Year                   | Year         | 2012; 97    |
|--------+------------------------+--------------+-------------|
| M      | Month in year          | Month        | July;Jul;07 |
|--------+------------------------+--------------+-------------|
| d      | Day in month           | Number       | 9; 09       |
|--------+------------------------+--------------+-------------|
| E      | Day in week            | Text         | Tuesday;Tue |
|--------+------------------------+--------------+-------------|
| H      | Hour in day (0-23)     | Number       | 0           |
|--------+------------------------+--------------+-------------|
| h      | Hour in am/pm (1-12)   | Number       | 12          |
|--------+------------------------+--------------+-------------|
| m      | Minute in hour         | Number       | 30          |
|--------+------------------------+--------------+-------------|
| s      | Second in minute       | Number       | 59          |
|--------+------------------------+--------------+-------------|
| S      | Millisecond            | Number       | 999         |
|--------+------------------------+--------------+-------------|
| a      | AM/PM marker           | Text         | AM          |
|--------+------------------------+--------------+-------------|
| z      | Time Zone              | Genral       | CST         |
|--------+------------------------+--------------+-------------|
| Z      | Time Zone              | RFC-822      | +0800       |
|--------+------------------------+--------------+-------------|

*** 2)和Java的SimpleDateFormat类似的使用方式
  
  Java的SimpleDateFormat一般性的使用是非常简单的,常用的也就两个方法,就是format, parse。在javascript版本的SimpleDateFormat里,将会有以下的使用形式。

var sft = new js.text.SimpleDateFormat();

sft.format(new Date()); // Format date to "Sun Mar 11 19:54:02 2012"

var date = sft.parse("Sun Mar 11 19:54:02 2012"); // Parse date string

sft.setPattern("yyyy年MM月dd日"); // Apply new pattern

sft.format(date) // 2012年03月11日

date = sft.parse("2012年03月11日");
 
*** 3)提供多语言支持的接口DateFormatSymbols
  
  尽管在javascript层面上处理多语言支持,似乎还不多见,但对于web应用逐步向编程化方向转换,直接在前端提供多语言的处理能力将会是非常有意义的。Java的SimpleDateFormat里,就使用了一个DateFormatSymbols的接口,从这个接口上就可以get到月份、星期、上午、下午等的多语言支持的符号。那么在javascript版本里,引入这个接口我们就可以实现如下的应用了。

var sft = new js.text.SimpleDateFormat("EEE MMM dd, yyyy", DateFormatSymbols);

sft.format(new Date()); // Format date to "周日 三月 11, 2012"
 

** 二、format和parse的实现设想

  format和parse的功能都和一个东西有关,就是日期格式的pattern,而各种日期格式都可以用上面提到的几个模式符号(y, M, d, H ...)的排列来表示,如pattern

  yyyy-MM-dd

就表示日期可以格式成“2012-03-08”。用正则表达式的思想来做,无非遍历这个模板,替换里面的模式符号,比如把yyyy,用日期的年来替换,等等。

而对于一个形如“2012年3月8日”的字符串,我们使用一个形如下面的pattern
  
  yyyy年M月d日

也应该是可以parse出一个日期来的。比如按照模式符号和其位置,我们可以写出一个正则式来提取和日期有关的数值。比如写一个简单的能提取年、月、日的javascript的正则表达式,将会如下面这样:

var regx_date = /(\d{4})年(\d{1,2})月(\d{1,2})日/;

var m = "2012年3月11日".match(regx_date);
 
    当然上面这个正则式是有很多问题的,比如月份部分\d{1,2}将匹配0到99的数字,99这个数字对于月份来说显然是错误的,所以这部分还需要更复杂的表达式。

*** 1) 构建提取模式符号的正则表达式

  我们需要从日期格式的pattern里提取模式符号,要提取的有:
  
  * 两位数的年yy(还有人在用吗?), 四位数年yyyy。 正则式:/yy(?:yy)?/
  * 月份M, M有一到四位的四钟可能。正则式:/M{1,4}/
  * 日子d (Day in month),正则式: /d{1,2}/
  * 星期E,一般有缩写和完整单词两种,正则式:/E{1,4}/
  * 时分秒,是一位或两位数字,正则式:/([Hhms])\1?/
  * 毫秒S,也有一位或三位的区别,正则式:/S(?:SS)?/
  * 上下午a,时区z/Z,纪元G,正则式: /[azZG]/

  到此,我们可以构建一个完整的正则表达式来提取模式符号了。

var TOKEN = /yy(?:yy)?|M{1,4}|d{1,2}|E{1,4}|([Hhms])\1?|S(?:SS)?|[azZG]/g;

// 对于下面pattern
var pattern = "EEE MMM dd, yyyy hh:mm:ss.SSS a Z";

// 按TOKEN正则式来replace

pattern.replace(TOKEN, function($0){

    //System.out.println($0); // 看看$0是什么? 

    return $0;
});
 
*** 2) 构建用于parse的正则表达式

  上面的正则表达式对于format已经足够了,但对于parse一个日期字符串来说,还要进一步构建可以提取年月日等数值的正则表达式。提取年月日等数值信息,首先需要提取两个信息:

  * 位置信息,比如对于日期串“01/01/2012”来说,里面的两个“01”哪个是月份,哪
    个是日子。
  * 数值信息,比如对于日期串”Mar 11, 2012“,里面的“Mar”是三月份,对于ISO
    格式的日期串"2012-03-11",三月份就是里面的“03”,如何提取到这些数值信息。

  对于位置信息,根据前面提取的pattern中的模式符号,我们只要按找匹配到的顺序进行记录就可以了,比如:

var tIndex = [];

// 对于下面pattern
var pattern = "EEE MMM dd, yyyy hh:mm:ss.SSS a Z";

// 按TOKEN正则式来replace
pattern.replace(TOKEN, function($0){
    
    tIndex.push($0); // 按顺序记录模式符号的位置
    
    return $0;
});

  对于数值信息,我们得先建立一张表,里面有yy, yyyy,M, MM, MMM, MMMM等各种模式的可能对应的数值的正则表达式,比如:

var regx = {
    yy : "(\\d{2})", // 2位数字
    yyyy : "(\\d{4})", // 4位数字
    M : "([1-9]|1[012])", // 1到9和10,11,12
    MM : "(0[1-9]|1[012])",// 01到12
    MMM : "(\\S+)", // 简单处理,非空白字符多个
    MMMM : "(\\S+)", // 简单处理,非空白字符多个
    d : "([1-9]|[12][0-9]|3[01])", // 1到31
    dd : "(0[1-9]|[12][0-9]|3[01])", // 01到31
    //....
};

  然后,用查表发替换模式符号,比如“yyyy年MM月dd日”这个pattern可以替换成
  
  yyyy年MM月dd日

        |
        |
        v

  (\\d{4})年(0[1-9]|1[012])月(0[1-9]|[12][0-9]|3[01])日
  
  代码很好写,改造一下上面的方法:

var pattern = "yyyy年MM月dd日";

// 按TOKEN正则式来replace
var str = pattern.replace(TOKEN, function($0){
    
    tIndex.push($0); // 按顺序记录模式符号的位置
    
    // 查表获得模式符号的数值正则表达式
    if(typeof regx[$0] === "string"){
        return regx[$0];
    }
    
    return $0;
});

// 生成正则表达式
var pRegx = new RegExp(str);
 
*** 3) 实现上的一些设计

   至此,实际上我们已经可以看到format和parse的初步样子了,无非是缺少一些如何get/set年月日等信息从(到)一个Date对象的体力活了。关于这部分如果按OO的思路来设计,程序虽然会略显臃肿,但会比较好维护。

  对于format,我们可以造一个工具类叫Getter,里面有一堆方法,而方法名正好是模式符号,比如:

var Getter = new function(){

    this.yyyy = function(date, symbols){
        return date.getFullYear();
    };

    this.MMM = function(date, symbols){
        return symbols.getShortMonths()[date.getMonth()];
    };

    //...
};

  而对于parse,也可以再造一个工具类叫Setter,里面同样有一堆以模式符号做为方法名的方法,比如:

var Setter = new function(){

    this.yyyy = function(date, value, symbols){
        date.setFullYear(value);
        return date;
    };

    this.MMM = function(date, value, symbols){
        var i = symbols.getShortMonths().indexOf(value);
        date.setMonth(i);
        return i;
    };

    //...
};
 
  那么SimpleDateFormat的format和parse方法的实现就会显得很优雅了。

var SimpleDateFormat = function(pattern, symbols){

    this.format = function(date){

        var datestr = pattern.replace(TOKEN, function($0){
            return Getter[$0](date, symbols);
        });

        return datestr;
    };

    this.parse = function(datestr){
        
        var m = datestr.match(pRegx), $0,
        date = new Date();

        for(var i=1, len=m.length; i<len; i++){
            $0 = tIndex[i-1]; // 从符号顺序表中获得模式符号
            
            date = Setter[$0](date, m[i] ,symbols);
        }
        
        return date;
    };

};

** 三、后记

  不要pattern可以parse日期时间吗? 是不是要收集足够多的pattern,然后一个一个测试能否parse出Date对象来?

  以上的代码在一般情况下是可以工作的,但用于生产环境的话,还需要做一些例外和出错时的处理,具体的就不在这篇技术文章中写了。有兴趣了解的可以到我的开源项目J$VM 去看正式的源代码,主要是js.text.SimpleDateFormat。
分享到:
评论

相关推荐

    javaScript和java中日期相减得出天数方案

    ### JavaScript和Java中日期相减得出天数方案 #### JavaScript中的日期相减方案 在JavaScript中,计算两个日期之间的天数差是一个常见的需求。...掌握这种方法对于处理与日期相关的业务逻辑非常有帮助。

    javascript日期组件

    JavaScript日期组件是Web开发中常用的一种工具,它主要用于在网页上展示、操作和处理日期与时间。在JavaScript中,没有内置的复杂日期选择器或日历功能,因此开发者通常会利用JavaScript库或自定义代码来创建这样的...

    JavaScript实现的SimpleDateFormat

    这个“JavaScript实现的SimpleDateFormat”可能是为了弥补这一空白,提供一个与Java相似的API来格式化和解析日期。 `SimpleDateFormat`在Java中是一个强大的工具,允许我们按照自定义的模式来格式化日期。例如,...

    javascript 日期时间函数(经典+完善+实用)

    在JavaScript中处理日期与时间是常见的需求之一,尤其在开发涉及日期计算、格式化显示等功能的应用时更为常见。本文档将详细介绍一系列实用且功能全面的JavaScript日期时间处理函数,包括判断是否为闰年、日期格式化...

    javaScript和java中日期相减得出天数方案.docx

    ### JavaScript与Java中计算两日期间相差天数的方法 #### JavaScript 实现方法 在JavaScript中,经常需要计算两个日期之间的差距来得出它们相隔的天数。以下是一种常见的实现方式: 1. **`Date.parse()` 方法**:...

    javascript时间戳和日期字符串相互转换代码(超简洁)_.docx

    ### JavaScript时间戳与日期字符串相互转换详解 #### 一、引言 在Web开发中,时间戳和日期字符串之间的转换是非常常见的需求。无论是处理服务器返回的数据还是用户输入的信息,掌握这两种格式之间的转换方法都是...

    moment-parseformat:moment.js插件,用于提取日期时间字符串的格式

    moment.parseFormat – moment.js插件 moment.js插件,用于提取日期/时间字符串的格式安装通过脚本标签加载&lt; script src =" moment.js " &gt; &lt;/ script &gt;&lt; script src =" moment.parseFormat.js " &gt;...

    前端项目-d3-time-format.zip

    3. **d3.utcFormat(pattern)** 和 **d3.utcParse(pattern)**:这两个函数与d3.timeFormat和d3.timeParse类似,但它们处理的是协调世界时间(UTC),而不是本地时间。 4. **d3.localeFormat** 和 **d3.localeParse**...

    javascript时间戳和日期字符串相互转换代码(超简单)

    在JavaScript中,你可以使用`Date.parse()`方法或者`Date`构造函数来从日期字符串创建一个`Date`对象,然后通过调用`getTime()`方法获取以毫秒为单位的时间戳。例如: ```javascript var stringTime = "2014-07-10 ...

    JavaScript中日期函数的相关操作知识

    JavaScript中的日期函数是编程中常用的功能,主要用于处理和展示日期与时间。在JavaScript中,日期对象是通过`Date`类来创建和操作的。本文将深入探讨JavaScript中日期函数的相关操作。 首先,创建日期对象有多种...

    JAVA字符串转日期或日期转字符串.docx

    - 当解析日期字符串时,必须确保字符串与指定的格式匹配,否则会抛出`ParseException`。 了解并熟练掌握`SimpleDateFormat`类的使用,对于处理日期和时间的转换问题至关重要,这在开发中非常常见,尤其是在处理用户...

    ExtJs 日期和时间的整合

    `images`文件夹则可能存储了与日期时间组件相关的图标和图形资源,如日历图标、时钟图标等,用于美化用户界面并提升用户体验。 `datetime.css`文件是样式表,用于定义日期时间组件的样式。这可能包括日期选择器的...

    JavaScript 函数库、工具类.zip

    2. 数字与日期处理:有format、parse、add、subtract等方法,用于格式化数字、日期,进行加减运算,以及日期之间的比较。 3. 链式操作:XEUtils的所有方法都可以链式调用,使得代码更加流畅,易于阅读。 4. 常用...

    JavaWeb中的日期控件示例

    如果使用JSON进行数据交换,可以借助Jackson库的`@JsonFormat`注解来指定日期格式。 此外,为了提高用户体验,还可以在前端添加一些验证逻辑,如检查所选日期是否有效,是否在特定范围内等。这通常通过JavaScript或...

    Node.js-dateformat-一个优秀的node.js日期格化包

    此外,模块还提供了 `parse` 方法,可以解析符合特定格式的日期字符串,转化为 `Date` 对象。 总结一下,`dateformat` 是 Node.js 开发中处理日期和时间的强大工具,它通过简单易用的接口,提供丰富的日期格式化...

    laydate独立版日期控件源码及demo.zip

    在layui官方文档中,你可以找到更多layDate的方法和选项,如`laydate.render()`用于初始化日期控件,`laydate.config()`用于全局配置,以及`laydate.parse()`和`laydate.format()`用于日期解析和格式化等。...

    .NET日期脚本按钮代码

    在给定的".NET日期脚本按钮代码"中,我们可以推测这是一个结合了.NET后端和前端技术,尤其是CSS和JavaScript的实现,用于创建一个与日期相关的交互式按钮。这个按钮可能用于选择日期、展示当前日期或者执行其他与...

    前端开源库-time_format

    - `parseTime(dateString, format)`: 反向操作,将格式化的日期字符串解析回时间戳或Date对象,便于进一步处理。 - `getLocaleFormat()`: 返回当前语言环境下的默认日期格式,对于多语言应用十分有用。 例如,假设...

    前端开源库-alinex-format

    import { parse, format } from 'alinex-format'; // 解析 JSON 数据 const jsonData = '{"name":"John", "age":30, "city":"New York"}'; const dataObject = parse(jsonData, 'json'); // 格式化日期 const date...

    Json_format

    JavaScript 提供了 `JSON.parse()` 和 `JSON.stringify()` 两个内置函数,分别用于将 JSON 字符串转换为 JavaScript 对象,以及将 JavaScript 对象转换为 JSON 字符串。 在实际应用中,JSON 被广泛用于 Web 服务...

Global site tag (gtag.js) - Google Analytics