之前发布过一个PHP类库:lv、现在发布一个js的类库:lv-js。类库中第一个类为时间操作类:DateQuery;之前有写过很多时间操作的方法(篇尾提供),经过加工、修改提供。类库的风格和php类库一样,从简、方便使用。
类库git仓库
最近更新日期:2014.11.08,最新稳定版为:0.1.3,点击查看更新说明 >
在说这个类库前,大家先自己想想这么几个问题:
我先提供一个简单的倒计时,如果用原生的JS计算倒计时是一件很复杂的事情,而使用这个类库,那么你可以将其简化如下:
setInterval(function() { lv.date().set('2015-11-12 11:00:20', true).get('g', true); }, 100);
当然,这只是举例,如果需要输出到Dom中,实际还需要添加一些其他方法,下面是一个简单的演示
lv.date();
返回值:lv.date对象
参数:可以包含以下类型参数
为空或null
lv.date();
如果不设置参数,则获取当前时间。注意哦,如果你设置的时间不正确,也默认为当前时间,例如:
lv.date('我就是来捣乱的'); // 返回当前时间的DateQuery对象
UNIX时间戳(number类型)
lv.date(1414725480348); // 直接设置时间戳 lv.date(new Date().valueOf()); // 通过Date设置时间戳
日期格式的字符串(string类型)
// 设置日期格式 lv.date('1986-11-5'); lv.date('11/5/1986'); // 设置时间点,精确到毫秒 lv.date('1986-11-5 3:59:00.032'); // 设置GMT时间 lv.date('Wed, 09 Aug 1995 00:00:00 GMT');
如果传入的是字符型,那么可以接受Date.parse所有支持的参数种类,如:
更多参数见官方文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
为了兼容IE6等低版本浏览器,以及从语义通俗易懂的角度来看,建议尽量使用:2012-11-10 11:00:02这样的字符(见:日期规范 >)。
在0.1.3之后支持一些特殊格式日期,如:
数组(2014.11.7 新增)
lv.date([2014, 11, 12, 11, 02, 34]);
数组值从前到后,分别为:年、月、日、小时、分、秒;不支持:毫秒、周这类时间,也可以单独设置一段时间,例如:
// 输出:Tue Dec 31 2013 00:00:00 GMT+0800 (CST) lv.date([2014]); // 输出:Fri Oct 31 2014 00:00:00 GMT+0800 (CST) lv.date([2014, 11]); // Thu Nov 13 2014 00:00:00 GMT+0800 (CST) lv.date([2014, 11, 13]);
注意哦,请不要将时间、日期单独作为参数请求,如:
// 输出:Thu Jan 01 1970 08:00:02 GMT+0800 (CST) lv.date(2014); // 实际相当于 new Date(2014);
Date 对象(2014.11.7 新增)
0.1.3之前并不支持Date对象,这点也是后来才发现很奇怪的地方。0.1.3后新增,如下:
lv.date(new Date()); // 设置当前时间 lv.date(new Date('2014/11/16')); // 设置指定时间
Object/JSON对象
lv.date({FullYear: 1986, Month: 10});
对象属性名请参照Date对象的set方法,例如:
所有的属性名均和方法名一致,不包含方法名字前三个字符“set”,属性名必须按照大小写来
注意哦,通过这样的方式设置月份需要-1;例如11月,实际上设置的值为10
DateQuery对象
lv.date(lv.date('2012-11-2')); // 这种方法经常用于设置间隔时间 var date = lv.date('2017-11-6'); lv.date().set(date, true);
lv.date().set('2014-11-12 11:12:30.001');
返回值:lv.date对象
参数:参考初始化时的参数设置
若需要更新为当前时间,可以使用下面的方法
lv.date('1986-11-05').set();
lv.date().set('2017-11-12 11:12:30.001', true);
可以通过给set方法的第二个参数传入true,来设置两个时间点,这样可以比较获取两个时间点的差值等其他用途
获取时间也是这个对象的特点之一,参考了PHP的Date函数,支持的参数也和Date函数一样,略有差异;相信情况见篇尾附录表格,这里我只列举几个简单的列子:
lv.date().get(); // 输出格式:Wed Nov 01 2000 00:00:00 GMT+0800 lv.date().get('Y-m-d H:i:s'); // 输出格式:2000-11-01 17:23:03 lv.date().get('Y年m月j日 星期w'); // 输出格式:2000年11月1日 星期5 lv.date().get('U'); // 输出格式:当前UNIX时间戳 - 973008000000
获取时间接受注释符号“/”,例如:
// 输出格式:2014-10-31,在Y镇有一个叫j的姑娘... lv.date().get('Y-m-d,在/Y镇有一个叫/j的姑娘...');
注意哦,是“/”,不是“”,因为在字符中要获取“”,需要设置为“”;避免麻烦,我用了“/”
lv.date().set('2015-11-2', true).get('', true);
通过在get方法和set方法中设置第二个参数为true,可以设置时间间隔,获取差额时间;注意哦,设置间隔时间,可以指定一个具体时间,而获取时间差额,只能获取间隔时间和指定时间的“差额”,而不是获取间隔的时间,举例:
获取差额的方法:通过第一个参数,可以获取差额指定单位的时间,默认是毫秒
lv.date().set('2015-11-2', true).get('', true); // 以毫秒为单位获取差额时间 lv.date().set('2015-11-2', true).get('h', true); // 以天为单位获取差额时间
所有的单位参数:ms – 毫秒、s – 秒、i – 分、h – 小时、d – 天、w – 周、m – 月、y – 年
时间单位不区分大小写
注意哦:获取年和月是按照自然日算,并非实际差额,例如:2014-11-27,和2014-12-4,获取的月份差额将为1个月;如果你需要按照自然日算,请自行获取时间单位计算,例如:
var date = lv.date('2014-11-27').set('2014-12-4', true).get('d', true); Math.floor(date/30);
在对象中还有个方法:getBetween,其方法和get(”, true)一样,区别在于,不用写第二个参数
lv.date().set('2015-11-12 11:00:20', true).get('g', true);
在get方法中使用参数’g’,来获取一组倒计时的参数,返回一个数组,格式如下:
[1, 736, 23, 11, 22, 16, 12, 1]
当然,你已可以自定义获取一组数据;例如我有这么一个需求:不需要获取毫秒、最大获取单位为周,代码如下
lv.date().set('2015-11-12 11:00:20', true).get(['s', 'i', 'h', 'd', 'w'], true);
实际效果,请见篇头在线演示。
关于倒计时的进阶研究,这里我就不再深入了,这里有篇帖子,应要求写的,感兴趣的可以查看这篇文章
http://levi.yii.so/archives/3728
2014.11.03.感谢ng群(240328422) @潮阳-饿货空 帮忙查找问题
之前写的倒计时中,月份取余值为30不正确,导致倒计时中月份不正确,git已修正为12对“时间差额”的问题,有的朋友不理解,为什么倒计时设定过去的时间,返回的是正数。这是因为DateQuery只帮你算“差额”,“差额”并没有正负。举例:
- 我有5块钱,你有8块钱,那么我们的差额是“3块钱”
- 反过来,我有8块钱,你有5块钱,那么我们的差额还是“3块钱”
- 而绝对不可能出现差额为“-3元”
- 所以我在返回的数组值,第一个值中就提供了1、0,告诉使用者,到底谁的钱比较多点
2014.11.5增加,之前的方法中只提供了时间差额获取方法:getBetween;上面有提到,这个方法返回的永远是时间差额,且是正数;那么就无法满足下面两个需求:
对于第一个需求只要设置第一个参数(当然也可以默认不传任何参数,默认);第一个参数为获取日期的单位,参数的形式请参照方法:get中的第一个参数:
// 获取两天的间隔时间,单位:毫秒,输出:86400000 lv.date('2012-11-12').set(2012-11-13).diff(); // 获取两天的间隔时间,单位:毫秒,输出:-86400000 lv.date('2012-11-14').set(2012-11-13).diff();
对于第二个需求,可以给第二个参数传入一个时间作为临时比较的时间:
var date = lv.date('2012-11-2').set('2012-11-3'); // 查看时间间隔,输出:86400000 data.get('', true); // 两个时间相比较,输出:86400000 data.diff(); // 给起始时间增加2天再比较,输出:-86400000 data.add(2, 'd').diff(); // 比较一个临时的时间,它不会被记录,输出:86400000 data.add(2, 'd').diff('', '2015-11-5'); // 再回头看看起止两个时间相比较(别忘了,之前咱给起始时间加过两天咯),输出:-86400000 data.diff();
注意哦:
- lv.date所有时间设置的格式,均参照方法:set,无论是:初始时间、更新时间、截止时间、临时比较时间
- diff方法中没有传入第二个参数,均以“截止时间”为“临时比较时间”
lv.date().add(1000000); // 增加1000000毫秒 lv.date().add(-1000000); // 减少1000000毫秒 lv.date().add(1, 'h'); // 增加1小时 lv.date().add(1, 'd'); // 增加1天 lv.date().add(1, 'y'); // 增加1年
参数:
时间单位不区分大小写
2014.11.5新增,之前和朋友沟通的时候有提到希望用这个时间类做一个日历插件。我大致思考了下,如果在不更新时间遍历的方法来看,也能实现,无非自己写个循环,但是我觉得我可以帮你做的更简单点,就像这样:
lv.date().walk('m', 'd', function() { console.log(this.get('Y-m-d 星期:') + ['日', '一', '二', '三', '四', '五', '六'][this.get('w')]); });
通过上面的方法,会将当前月份,以天为间隔单位,通过闭包的方式循环输出lv.date对象(剩下的,只需在闭包中通过get方法,输出指定时间格式)。这篇文章通过walk方法,制作了一个简单的日历演示,你可以点击连接查看:
http://levi.yii.so/archives/3728
返回值:lv.date对象,不受walk传参影响,记录的时间为最近set的时间
参数:
他可以是以下几种形式:
时间格式:
参照lv.date对象中的set方法接受的时间参数,设置的时间将作为walk截止时间,点击查看set方法 >
// 从2012-11-2到2012-11-30,按照天为单位,循环输出DateQuery对象 lv.date('2012-11-2').walk('2012-11-30', 'd', function() {});
如果没有指定初始时间,仅设置一个截止时间,如果当天时间已过了一大半,可能会出现少一天的情况哦:
lv.date().walk('2012-11-30', 'd', function() {});原因:当今天时间过了一大半(例如23点),自然增加到最后一天大于walk截止时间
解决方法:
- 设置开始时间,及截止时间
- 尽量通过“指定时间单位”来设置walk时间,见下方
指定时间单位:
参考lv.date对象中的getPot的name参数,设置的时间单位将分别作为walk开始时间、walk截止时间,点击查看getPot方法 >
// 以2012年11月为例,将从自然月1号到30号,按照天为单位,循环输出DateQuery对象 lv.date().walk('m', 'd', function() {});
自定义时间
通过一段obj对象设置walk的起止,设置的时间规范请参考set方法,点击查看set方法 >
// 从2012-11-1到2012-12-31,按照天为单位,循环输出DateQuery对象 lv.date().walk({ stat: '2012-11-1', end: '2012-12-31' }, 'd', function() {});
obj接受两个属性,stat:开始时间,end:结束时间
为空或者null
若为空或者null的话,将当前设置的初始时间,和间隔结束时间为walk时间
// 从2012-11-1到2012-12-31,按照天为单位,循环输出DateQuery对象 lv.date('2012-11-1').set('2012-12-31').walk('', 'd', function() {});
注意哦,除了通过初始、截止时间设置walk时间之外,以上任何方式传入的参数都不能修改当前DateQuery对象的时间值,仅作为当前walk方法使用
时间单位不区分大小写,包含有:y – 年、m-月、w-周、d-天、h-小时、i-分、s-秒;示范代码,如下:
// 一天中以小时为单位,循环输出DateQuery对象 lv.date().walk('d', 'h', function() {}); // 指定时间,以小时为单位,循环输出DateQuery对象 lv.date('2012-11-1 22:00:00').walk('2012-11-1 23:59:00', 'h', function() {}); // 按照年为单位,下面结果只能返回一次回调 lv.date('2012-11-1 22:00:00').walk('2012-11-1 23:59:00', 'y', function() {});
也可以自定一个数值,作为walk间隔时间。
// 每10分钟响应一次回调 lv.date('2012-11-1 22:00:00').walk('2012-11-1 23:59:00', 60000, function() {});
回调函数中的this为lv.date对象,方便输出指定格式日期(点击查看get方法 >),还是以上面“日历”来举例
// 将12月的日期按照日历的方式全部输出 lv.date('2012-12-1').walk('m', 'd', function() { console.log(this.get('Y-m-d 星期:') + ['日', '一', '二', '三', '四', '五', '六'][this.get('w')]); });
如果要输出11月,你可以这样设置
// 指定日期 var date = lv.date('2012-11-1').walk(); // 也可以计算设置日期 date.add(1, 'm').walk()
若为空值,将以每秒响应一次回调
lv.date('2012-11-1 22:00:00').walk('2012-11-1 23:59:00', null, function() {});
2014.11.8新增,walk回调函数新增num,返回当前回调的顺序。
lv.date().walk('m', 'd', function(num, limit) { console.log(num); // 打印当前回调的顺序 console.log(limit); // 打印间隔时间 });
注意哦:
- 执行顺序从1开始,根据回调递增;最后一个返回0
- limit参数为间隔时间,位置调整为第二个参数
还是会到最开始“日历”这个需求,现在要获取当前月份、上个月、下个月的日期相当容易,还可以指定输出2个月或3个月,也可以输出1周的日期;你也可以将输出的日期按照自己要求获取展示格式,至于如何更新时间:点击、悬停、滑动,这个就看你个人意愿了,lv.date都挺方便哒~
2014.11.5新增,考虑这么一个过程,如果我需要暂时对时间进行不同的处理,并在处理完成后再设置回来,需要几个步骤?具体步骤我就不再说明了,不过通过temp这个方法可以大大简化这个过程,代码如下:
// 即便在闭包中给this增加了时间,但是最终记录的时间依然不变 lv.date().temp(function() { // 临时增加1天作为比较 this.add(1, 'd').diff(); }).get();
返回值:当前lv.date对象
这个方法挺实际的,有兴趣可以好好研究研究,这里就列这么多,在类中用了不少temp方法,可以看看
lv.date().toData(); lv.date().toData(null, true);
返回值如下:
["2014", "10", "31", "12", "58", "50"] {y: "2014", m: "10", d: "31", h: "12", i: "58", s: "50"}
参数:
若没有提供参数,默认为:[‘Y’, ‘m’, ‘d’, ‘H’, ‘i’, ‘s’]
在传统的new Date对象中可以获取当前对象为第几天、星期几,也可以通过lv.date包装获取当月最大天数,但是还是少了点什么,比如说:以当前设置时间为基准,获取当月第一天、最后一天;当年第一天、最后一天、当月第一天最后一天;等等,诸如此类。
2014.11.5新增方法:getPot,根据设定时间得到指定起止点:
lv.date().getPot('m'); // 获取本月开始时间 lv.date().getPot('m', true); // 获取本月结束时间 lv.date().getPot('q'); // 获取本季度开始时间 lv.date().getPot('q', true); // 获取本季度结束时间 lv.date().getPot('d'); // 获取本天开始时间 lv.date().getPot('d', true); // 获取本天结束时间
返回值:new Date对象,注意不是lv.date对象哦;同样,getPot获取的值也不会作为时间记录在lv.date对象中。如果你需要将返回的对象变为时间戳、或是再利用,可以这样:
// 将返回的对象转化为时间戳 +lv.date().getPot('m'); // 将返回的对象再次利用 lv.date(+lv.date().getPot('m'));
参数:
注意哦:没有毫秒,因为使用过程中基本用不上
字符串转换为时间对象
lv.date.strTotime('2012-11-12');
参数见DateQuery对象中的set方法
判断是否为正确的时间格式
lv.date.isDate('2012-11-12');
获取当前类库版本号
lv.date.version
为了方便查看,以后DateQuery的更新日志,只在这篇文档中更新。如果你你需要获取更新提醒,可以关注我的git:https://coding.net/u/levi/p/levi-js/git
版本更新至0.1.1,增加了新的方法;这次版本修改后,压缩文件大小相对版本0.0.1要稍微小一点
版本更新至0.1.2,增加调用方法:
增加DateQuery.develope.js,develope为内部开发版,未经过测试,不建议线上环境使用。开发版优化如下:
正式版本更新至0.1.4版
注意哦:以上的错误修复,均是修改内部测试版本的bug,正式发布的版本中并不包含这些bug,若需要用在实际开发中,请使用DateQuery.min.js这个文件
在获取特定时间时,传入特定格式作为get参数使用;DateQuery的时间格式是以PHP的Date函数为原型作为参考,有细微差别,大致情况如下:
字符 | 说明 | 返回值例子 |
---|---|---|
日 | ||
d | 月份中的第几天,有前导零的 2 位数字 | 01 到 31 |
D | 星期中的第几天,文本表示,3 个字母 | Mon 到 Sun |
j | 月份中的第几天,没有前导零 | 1 到 31 |
l(“L”的小写字母) | 星期中的第几天,文本表示,3 个字母 | Mon 到 Sun注1 |
N | ISO-8601 格式注2数字表示的星期中的第几天(PHP 5.1.0 新加) | 1(表示星期一)到 7(表示星期天)注3 |
S | 每月天数后面的英文后缀,2 个字符 | st,nd,rd 或者 th。可以和 j 一起用 |
w | 星期中的第几天,数字表示 | 0(表示星期天)到 6(表示星期六) |
z | 年份中的第几天 | 0 到 365 |
星期 | ||
W | 年份中的第几周注4,每周从星期一开始(PHP 4.1.0 新加的) | 例如:42(当年的第 42 周) |
月 | ||
F | 三个字母缩写表示的月份 | Jan 到 Dec注1 |
m | 数字表示的月份,有前导零 | 01 到 12 |
M | 三个字母缩写表示的月份 | Jan 到 Dec |
n | 数字表示的月份,没有前导零 | 1 到 12 |
t | 给定月份所应有的天数 | 28 到 31 |
年 | ||
L | 是否为闰年 | 如果是闰年为 1,否则为 0 |
o | ISO-8601 格式年份数字,这和 Y 的值相同。注5 | Examples: 1999 or 2003 |
Y | 4 位数字完整表示的年份 | 例如:1999 或 2003 |
y | 2 位数字表示的年份 | 例如:99 或 03 |
时间 | ||
a | 小写的上午和下午值 | am 或 pm |
A | 大写的上午和下午值 | AM 或 PM |
g | 小时,12 小时格式,没有前导零 | 1 到 12 |
G | 小时,24 小时格式,没有前导零 | 0 到 23 |
h | 小时,12 小时格式,有前导零 | 01 到 12 |
H | 小时,24 小时格式,有前导零 | 00 到 23 |
i | 有前导零的分钟数 | 00 到 59> |
s | 秒数,有前导零 | 00 到 59> |
u | 毫秒注6 | 示例: 654 |
时区 | ||
e | 时区标识 | 例如:CST注7 |
I | 是否为夏令时 | 如果是夏令时为 1,否则为 0 |
O | 与格林威治时间相差的小时数 | 例如:+0800 |
P | 与格林威治时间(GMT)的差别,小时和分钟之间有冒号分隔(PHP 5.1.3 新加) | 例如:+08:00 |
T | 本机所在的时区 | 例如:CST注7 |
Z | 时差偏移量的秒数。UTC 西边的时区偏移量总是负的,UTC 东边的时区偏移量总是正的 | -43200 到 43200 |
完整的日期/时间 | ||
c | ISO 8601 格式的日期 | 2004-02-12T15:19:21+00:00 |
r | RFC 822 格式的日期 | 2012-12-30T00:00:00.000Z |
r | RFC 822 格式的日期 | Sun, 30 Dec 2012 00:00:00 GMT |
U | 从 Unix 纪元(January 1 1970 00:00:00 GMT)开始至今的秒数 | 时间戳注8 |
之前有朋友建议我使用“L”代替“lv”来命名,我放弃了;理由很简单,“L”要敲3下键盘,“lv”两下。后来有考虑过“l”(小写的“L”),不过还是放弃了,因为很多人用l、len、length表示长度,避免污染。
既然谈道污染,那如果说lv被占用了怎么办?这种情况下还可以使用lvDate来代替lv.date。
在版本0.1.3之后,支持的日期格式更广泛,但同时可能因为你输入的日期特殊造成浏览器不一致;例如:
lv.date('2014/0/0');
原因是因为:
目前暂时不会对这种特殊情况做处理,解决办法:
这个类库设计初衷就是为了前端进行操作的,有下面几个原因:
var date = lv.date(); date.get('Y年-n月-j日 星期:') + [日、一、二、三、四、五、六][date.get('w')];
设计这个类之前就考虑到了,希望尽量以“数字”的形式返回值,这样无论如何操作都能得心应手,如果我还需要配备本地化语言,比如中文的:星期一,那么就相对不灵活了。
您可能也喜欢: | ||||
Mac下配置Redis服务器(自启动、后台运行) |
通过 Google Docs 加密你的 Gmail 邮件 |
linux使用crontab实现PHP执行定时任务 |
初识 jQuery Deferred |
一句话删除目录下所有文件 |
无觅 |