Javascript:万能的日期格式化函数

最近在工作项目中,用到了日期格式化,要求传到后台的日期格式必须是2012-02-02这样的。蛋疼的是Javascript都没有自己原生的日期格式化函数,只能自己写一个。

写的时候我就想写一个通用的,比如这次要的是2012-02-02,下次说不定就要2012/02/02或2012-2-2,总不能下次又写吧。

在发源代码之前,我要列举一下约定俗成的日期格式(也就是Windows系统日期与时间的格式),如下:

*yyyy 完整年
*yyy 年,只有后两位
*MM 月,补零
*M 月,不补零
*dd 日,补零
*d 日,不补零
*q 季度,如一,二
*HH 24小时制,补零
*H 24小时制,不补零
*hh 12小时制,补零
*h 12小时制,不补零
*tt 上午下午
*mm 分,补零
*m 分,不补零
*ss 秒 补零
*s 秒,不补零
*ssss 毫秒 补零
*sss 毫秒,不补零

其中的q,表示季度,本来是没有这个日期表示的,加进去只是为了可能要用到的情况。其余字段就是源自已有的格式。

这么多字段看起来好难记,之前我也是记不住的,所以总结了一些小技巧:

  1. 字段全是小写,除了可能用歧义的(如m可能代表month也可以代表minutes)或多个格式的(如h本来就代表小时,但H表示24小时制)
  2. 补零的比不补零的多一个字母,如(M,MM)等

我要写的函数,要实现的功能也就是,传入一个Date,传入一个格式,就能把Date格式化成指定的这个格式。功能听起来很简单吧。

Javascript源码

也可以去Github上查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
var DateFormat = function  () {
    var
    dateReg = /y{3,4}|M{1,2}|m{1,2}|d{1,4}|H{1,2}|h{1,2}|s{1,4}|tt|q/g,
    fnLabels = 'yyyy d dddd H m s sss'.split(' '),
    fnNames = 'getFullYear getDate getDay getHours getMinutes getSeconds getMilliseconds'.split(' '),
    bu0Labels = 'MM dd HH hh mm ss'.split(' '),
    plus1 = function (m) {return m-0+1;},
    defaultStrings = {
        dddd :'日 一 二 三 四 五 六'.split(' '),
        M: plus1,
        q: plus1,
        tt: function  (d) {
            alert(d)
            return d>1 ? 'PM' : 'AM';
        }
    },
    defaultFormat = 'yyyy-MM-dd',
    formats = {
        h: function  (d) {
            return d.getHours()%12 || 12;
        },
        M: function  (d) {
            return d.getMonth();
        },
        q: function (d) {
            return Math.floor(d.getMonth()/3);
        },
        tt: function (d) {
            return d.getHours()/12;
        },
        ssss: function (d) {
            return bu0(d.getMilliseconds(),4);
        }
    };
    for(var f = fnLabels.length;f--;){
        var fl = fnLabels[f].split(':');
        (function  (ff,nn) {
            formats[ff] = function  (d) {
                return d[nn]();
            }  
        })(fnLabels[f],fnNames[f])     
    }
    for(var b = bu0Labels.length;b--;) {
        (function  (ff,fn) {
            formats[ff] = function  (d) {
                return bu0(fn(d),2);
            }
        })(bu0Labels[b],formats[bu0Labels[b].slice(0,-1)])
    }
    function bu0(src,num) {
        return (src+'').length < num ? ('0000'+src).slice(-num) : src;
    }
    return function  (date,options) {
        date = date || new Date();
        options = options || {};
        var format = (typeof options == 'string') ? options :
            options.format ? options.format :
            defaultFormat;
        // console.log(date,format)
        return format.replace(dateReg,function  (mt) {

            var res = formats[mt](date),todo = options[mt] || defaultStrings[mt],ok;
            // console.log(mt,todo)
            return todo ?
                typeof todo == 'function' ? todo(res) : todo[res]
                : res;
           
        })
       
    }
}();

源码说明

源码的核心在于用replace结合正则表达式替换格式字符串里的指定字符

源码中在两个循环里都用了闭包,用来直接生成函数。其实直接在formats里定义出所有函数也是可以的。

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
var dateFormat = DateFormat();//当前时间,默认格式
var dateFormat = DateFormat(new Date());//当前时间,默认格式
var dateFormat = DateFormat(null,'yyyy-MM-dd');//当前时间,默认格式
var dateFormat = DateFormat(new Date(),'yyyy-M-dd');//当前时间,另一种格式
var df1 = DateFormat(null,'HH:mm:ss');//只要时分秒
var df = DateFormat(null,{
    format: 'yyyy/M/d q天 周dddd tt hh:mm:ss:ssss',
    q : ['春','夏','秋','冬'],
    tt:function  (t) {
        return t>1 ? ( t> 1.5 ? '晚上' : '下午') : ( t> 0.5 ? '上午' : '凌晨');
    }
});

说明:

基本使用方法就是如前面所说,传入一个日期,一个格式字符串,就得到一个格式化后的日期。如果不传,则使用默认日期(今天),默认格式(yyyy-MM-dd)进行格式化。

复杂点的使用方法,是传入一个日期,及一个对象,这个对象里有个format是用来指定格式的,其余的字段key全都是日期格式字段如yyyy,dd什么的。他们的作用是替换函数中本来的格式化方法(即defaultStrings里的方法)。

而这些字段的值,可以是数组或函数。

当是数组时,如示例中的q(季度),因为原始函数中q只会返回1,2,3,4等数字,如果你想依次显示为“春,夏,秋,冬”,就可以传入一个数组.

当是函数时,如示例中的tt(上午下午),原始函数中的tt只会返回am,pm,如果你想返回上午或下午,可以传入一个函数,这个函数的参数是经过原始计算的t(即小时数/12),你可以判断这个t的值,来返回字符串。示例中我根据t分别返回了“凌晨,上午,下午,晚上”4个结果。

说起来,本来我想把tt的计算值只返回0,1的,0表示上午,1表示下午,但我想到还真有人可能需要“凌晨”什么的,所以没有这样加工。

通过自定义,你完全可以把时间格式化成“子时,丑时”这样的。

好了就这样,如果有大的改动我会更新此文。

发表评论

电子邮件地址不会被公开。