最近在工作项目中,用到了日期格式化,要求传到后台的日期格式必须是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,表示季度,本来是没有这个日期表示的,加进去只是为了可能要用到的情况。其余字段就是源自已有的格式。
这么多字段看起来好难记,之前我也是记不住的,所以总结了一些小技巧:
- 字段全是小写,除了可能用歧义的(如m可能代表month也可以代表minutes)或多个格式的(如h本来就代表小时,但H表示24小时制)
- 补零的比不补零的多一个字母,如(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表示下午,但我想到还真有人可能需要“凌晨”什么的,所以没有这样加工。
通过自定义,你完全可以把时间格式化成“子时,丑时”这样的。
好了就这样,如果有大的改动我会更新此文。
月份好像是错的