前言

在很多时候,我们需要对时间进行处理,比如时间间隔计算,时间转换,时间格式化等操作,如果用原生的JS进行操作的话,会是一件很繁琐的事情,幸好我们有了Moment.js使得时间的处理变得更加简单高效。

Moment.js简介

Moment.js 是一个 JavaScript 日期处理类库,用于解析、检验、操作、以及显示日期,Github地址为https://github.com/moment/moment/
官方文档地址为:http://momentjs.com/

安装

Nodejs中安装:

npm install moment
var moment = require('moment');
moment().format();

浏览器中安装:

<script src="moment.js"></script>
<script>
    moment().format();
</script>

解析

1.解析当前时间:

moment(new Date())
moment();
// 2.14.0 后还支持下面的方法
moment([]);
moment({});

创建后会返回这样一个对象:

Moment {_isAMomentObject: true, _isUTC: false, _pf: {…}, _locale: Locale, _d: Thu Jun 28 2018 14:36:22 GMT+0800 (中国标准时间), …}

2.传入字符串解析时间:

moment("12/25/1995", "MM-DD-YYYY");

它支持以下这些标识符:

年、月、日,标识符

输入 示例 说明
YYYY 2014 4或2位年
YY 14 2位年r
Q 1..4 季度。设置每季度的第一个月
M MM 1..12 表示月的数字
MMM MMMM Jan..December 月份名
D DD 1..31 每月的第几天
Do 1st..31st 每月的第几天的序数
DDD DDDD 1..365 每年的第几天
X 1410715640.579 Unix时间戳
x 1410715640579 Unix时间戳(毫秒级)

周年、周、周日,标识符

输入 示例 说明
gggg 2014 本地 4位周年
gg 14 本地 2位周年
w ww 1..53 本地 年中第几周
e 1..7 本地 一周中的第几天
ddd dddd Mon...Sunday 本地星期名
GGGG 2014 ISO 4位周年
GG 14 ISO 2位周年
W WW 1..53 ISO 年中第几周
E 1..7 ISO 一周中的第几天

时、分、秒、毫秒、时差,标识符

输入 示例 说明
H HH 0..23 24 小时制 时
h hh 1..12 12 小时制 时a A.
a A am pm 上午和下午
m mm 0..59
s ss 0..59
S 0..9 十分之一秒
SS 0..99 百分之一秒
SSS 0..999 千分之一秒(毫秒)
SSSS 0000..9999 微秒
Z ZZ +12:00 与UTC时间的时差,用+-HH:mm、+-HHmm或Z表示

如果不确定需要哪种格式化,可以传入一个数组:

moment("12-25-1995", ["MM-DD-YYYY", "YYYY-MM-DD"]);

Moment.js会自动选择匹配的格式化格式。

3.使用对象解析:

moment({ hour:15, minute:10 });
moment({ y    :2010, M     :3, d   :5, h    :15, m      :10, s      :3, ms          :123});
moment({ year :2010, month :3, day :5, hour :15, minute :10, second :3, millisecond :123});
moment({ years:2010, months:3, days:5, hours:15, minutes:10, seconds:3, milliseconds:123});
moment({ years:2010, months:3, date:5, hours:15, minutes:10, seconds:3, milliseconds:123});

4.使用Unix 偏移量(毫秒)或者Unix 时间戳(秒)进行初始化

moment(1318781876406);
moment.unix(1318781876);

5.使用JSDate对象进行初始化

var day = new Date(2011, 9, 16);
moment(day);

6.使用数组

[year, month, day, hour, minute, second, millisecond]
moment([2010, 1, 14, 15, 25, 50, 125]); // February 14th, 3:25:50.125 PM

7.Moment对象复制

var a = moment([2012]);
var b = moment(a);
//或者
var b = a.clone();

8.UTC

moment.utc();
moment.utc(Number);
moment.utc(Number[]);
moment.utc(String);
moment.utc(String, String);
moment.utc(String, String[]);
moment.utc(String, String, String);
moment.utc(Moment);
moment.utc(Date);

默认情况下,Moment使用本地时间进行转换和显示。如果要使用UTC标准时间进行转换和显示,需要使用moment.utc()方法代替moment()。这就是Moment.js的UTC模式。

utc()方法只会在显示上使用UTC时间,二者本质上还是相同的时间

在UTC模式下,所有显示时间的方法都会使用UTC时间代替本地时间。

var a = moment();
var b = moment.utc();
a.format();  // 2013-02-04T10:35:24-08:00
b.format();  // 2013-02-04T18:35:24+00:00
a.valueOf(); // 1360002924000
b.valueOf(); // 1360002924000

9.转换时区

moment.parseZone("2013-01-01T00:00:00-13:00").utcOffset(); // -780 ("-13:00" in total minutes)
moment.parseZone('2013 01 01 05 -13:00', 'YYYY MM DD HH ZZ').utcOffset(); // -780  ("-13:00" in total minutes)
moment.parseZone('2013-01-01-13:00', ['DD MM YYYY ZZ', 'YYYY MM DD ZZ']).utcOffset(); // -780  ("-13:00" in total minutes);

10.验证
你可以使用moment.isValid方法检测输入的初始化时间是否合法,该方法会返回一个表示是否有效的布尔值。如果想查看转换详细结果,可以使用moment.parsingFlags方法,该方法会返回一个包含以下值的对象:

  • overflow:是否有溢出,如:13th月、月中的第32天
  • invalidMonth:是否有效的月名
  • empty:转入的字符串是否不可转换,如:输入moment('this is nonsense');则为true
  • nullInput:是否输入了空值
  • invalidFormat:是否无效的输入格式
  • userInvalidated:是否创建成功,相当于moment.invalid()

当转换失败时,可以调用moment#invalidAt方法,查看失败位置:

var m = moment("2011-10-10T10:20:90");
m.isValid(); // false
m.invalidAt(); // 5 表示秒出错

返回值含义如下:

  • 0年
  • 1月
  • 2天
  • 3时
  • 4分
  • 5秒
  • 6毫秒

11.查看创建的数据
你可以使用moment().creationData();获取到创建该时间对象的输入:

moment("2013-01-02", "YYYY-MM-DD", true).creationData()
//返回下面的对象
{
    input: "2013-01-02",
    format: "YYYY-MM-DD",
    locale: Locale obj,
    isUTC: false,
    strict: true
}

12.使用默认值
创建Moment时,可以只指定一些时间单位,其它的会使用当前时间的日、时、分、秒等。

moment();  // 当前时刻
moment(5, "HH");  // 今天, 5:00:00.000
moment({hour: 5});  // 今天, 5:00:00.000
moment({hour: 5, minute: 10});  // 今天, 5:10.00.000
moment({hour: 5, minute: 10, seconds: 20});  // 今天, 5:10.20.000
moment({hour: 5, minute: 10, seconds: 20, milliseconds: 300});  // 今天, 5:10.20.300
moment(5, "DD");  // 本月的第5天
moment("4 05:06:07", "DD hh:mm:ss");  // 本月的第4天, 05:06:07.000
moment(3, "MM");  // 今年的第4个月 (April)
moment("Apr 4 05:06:07", "MMM DD hh:mm:ss");  // 今年4月的第5天, 05:06:07.000

设置与取值

Moment.js使用了重载的getter和setters,当有值的时候是一个setters,表示设置时间的对应的分,秒或日期等,当没有值传入的时候是一个getter,返回对应的时间的分或者秒等:

moment().millisecond();  //毫秒
moment().second(); //秒
moment().minute();//分
moment().hour();//小时
moment().date();//日期
moment().day(); //星期
moment().day(7); //上星期日
moment().day(-7);//下星期日
moment().weekday(); 本地化星期
//当周一为星期的第一天时
moment().weekday(-7); // 上周一
moment().weekday(7); // 下周一
//当周日为星期的第一天时
moment().weekday(-7); // 上周日
moment().weekday(7); // 下周日
moment().isoWeekday(); // ISO星期 
moment().isoWeekday(1); // 周一
moment().isoWeekday(7); // 周日
moment().dayOfYear(); //一年中的第几天
moment().weeks(); //一年中的第几周
moment().isoWeek(); //ISO周
moment().months(); //月份0-11
moment().quarter();  //季度1-4
moment().year(); //年 -270,000 〜 270,000
moment().weekYear(); //本地化的 周-年
moment().isoWeekYear();//ISO周、年
moment().weeksInYear(); //本地化时间的周数
moment().isoWeeksInYear(); //ISO 周数

或者你也可以直接使用.get(str,value)或者.set(str)加上上面提到的那些属性来设置或取值:

moment().get('year');
moment().set('year', 2013);

你还可以来取最大值或最小值:

moment.max(Moment[,Moment...]);
moment.min(Moment[,Moment...]);
var a = moment().subtract(1, 'day');
var b = moment().add(1, 'day');
moment.max(a, b);  // b
moment.min(a, b);  // a

时间操作

Moment.js的时间操作支持链式调用:

moment().add(7, 'days').subtract(1, 'months').year(2009).hours(0).minutes(0).seconds(0);

1.时间增加或减少
语法如下:

moment().add(Number, String);
moment().add(Duration);
moment().add(Object);
moment().subtract(Number, String);
moment().subtract(Duration);
moment().subtract(Object);

第二个参数为单位字符串形式,可以使用全拼或者简写形式,简写对应关系如下:

单位 简写
years y
quarters Q
months M
weeks w
days d
hours h
minutes m
seconds s
milliseconds ms

当增加月后,如果目标月的天数超过出最大值,将变为目标月的最后一天
如果传递小数的话,则会自动转换为最接近的整数

moment().add(7, 'days').add(1, 'months');
moment().subtract(7, 'days');
moment().subtract(1, 'seconds');
moment().add({days:7,months:1});
var duration = moment.duration({'days' : 1});
moment([2012, 0, 31]).add(duration); // February 1
moment().add(1.5, 'months') == moment().add(2, 'months')
moment().add(.7, 'years') == moment().add(8, 'months') //.7*12 = 8.4, rounded to 8

2.开始时间 (Start of Time)与结束时间(End of Time)

moment().startOf(String);
moment().endOf(String);
moment().startOf('year');    // 设置为今年1月第一天的 12:00 am
moment().startOf('month');   // 设置为本月第一天的 12:00 am
moment().startOf('quarter');  // 设置为本季度第一个月第一天的 12:00 am
moment().startOf('week');    // 设置为本周第一天的 12:00 am
moment().startOf('isoWeek'); // 设置为ISO本周的第一天的 12:00 am
moment().startOf('day');     // 设置为今天的 12:00
moment().startOf('hour');    // 设置为当前时间的小时,0分0秒0毫秒
moment().startOf('minute');  // 设置为当前的时间的分钟,according
moment().startOf('second');  // 类似 moment().milliseconds(0);
moment().endOf("year"); // 设置为今年的 12-31 11:59:59.999 pm

3.最大值与最小值

moment().max(Moment|String|Number|Date|Array);
moment().min(Moment|String|Number|Date|Array);

将当前moment时间设置为和另一个moment时间相比较大或较小的一个,a.max(b)a = moment.min(a, b)相同,a.min(b)a = moment.max(a, b)相同。

4.本地化与UTC

moment().local();
moment().utc();

5.UTC 偏移量(UTC Offset)

moment().utcOffset(); //获取偏移量
moment().utcOffset(Number|String); //设置偏移量

一般设置偏移量都会默认是分钟数,当输入小于16且大于-16时,moment会理解为输入的是小时:

moment().utcOffset(8);  // 设置小时偏移量
moment().utcOffset(480);  // 设置分钟偏移量 (8 * 60)

也可以通过字符串形式进行设置:

moment().utcOffset("+08:00");
moment().utcOffset(8);
moment().utcOffset(480);

当通过字符串进行设置时,moment().utcOffset会首先匹配+00:00 +0000 -00:00 -0000,即使你输入了ISO 8601格式的字符串,moment也会将成变成这个UTC 偏移量。

输入的字符串要以+和-的形式开头,如果不以这种形式开头会被解释为"+00:00"。

moment().utcOffset("2013-03-07T07:00:00+08:00");

6.时区偏移量(Timezone Offset)

moment().zone();//获取偏移量
moment().zone(Number|String);//设置偏移量

设置偏移量同UTC偏移量,可以输入数字或者是字符串,且小于16大于-16会理解为小时

格式化显示

1.格式化

moment().format();
moment().format(String);

它支持下列标识符

标识 输出
M 1 2 ... 11 12
Mo 1st 2nd ... 11th 12th
MM 01 02 ... 11 12
MMM Jan Feb ... Nov Dec
MMMM January February ... November December
Q 1 2 3 4
天数(月) D 1 2 ... 30 31
Do 1st 2nd ... 30th 31st
DD 01 02 ... 30 31
天数(年) DDD 1 2 ... 364 365
DDDo 1st 2nd ... 364th 365th
DDDD 001 002 ... 364 365
Day of Week d 0 1 ... 5 6
do 0th 1st ... 5th 6th
dd Su Mo ... Fr Sa
ddd Sun Mon ... Fri Sat
dddd Sunday Monday ... Friday Saturday
星期(本地) e 0 1 ... 5 6
星期(ISO) E 1 2 ... 6 7
周数 w 1 2 ... 52 53
wo 1st 2nd ... 52nd 53rd
ww 01 02 ... 52 53
周数(ISO) W 1 2 ... 52 53
Wo 1st 2nd ... 52nd 53rd
WW 01 02 ... 52 53
YY 70 71 ... 29 30
YYYY 1970 1971 ... 2029 2030
周、年 gg 70 71 ... 29 30
gggg 1970 1971 ... 2029 2030
周、年(ISO) GG 70 71 ... 29 30
GGGG 1970 1971 ... 2029 2030
AM/PM A AM PM
a am pm
H 0 1 ... 22 23
HH 00 01 ... 22 23
h 1 2 ... 11 12
hh 01 02 ... 11 12
m 0 1 ... 58 59
mm 00 01 ... 58 59
s 0 1 ... 58 59
ss 00 01 ... 58 59
分数秒 S 0 1 ... 8 9
SS 00 01 ... 98 99
SSS 000 001 ... 998 999
SSSS ... SSSSSSSSS 000[0..] 001[0..] ... 998[0..] 999[0..]
时区 z or zz EST CST ... MST PST
注意:1.6.0版本后,z/zz格式标识不再支持 查看详细
Z -07:00 -06:00 ... +06:00 +07:00
ZZ -0700 -0600 ... +0600 +0700
UNIX时间戳(秒级) X 1360013296
NIX时间戳(毫秒级) x 1360013296123
本地化格式

因为不同地区的首选格式不同,这里还提供了一些特殊标识时用于moment的本地格式化。在这些格式中,格式标识大小写作用相同:

时间 LT 8:30 PM
时间和秒 LTS 8:30:25 PM
数字月、日、年 L 09/04/1986
l 9/4/1986
月名、日、年 LL September 4 1986
ll Sep 4 1986
月名、日、年、时间 LLL September 4 1986 8:30 PM
lll Sep 4 1986 8:30 PM
月名、日、星期、年、时间/b> LLLL Thursday, September 4 1986 8:30 PM
llll Thu, Sep 4 1986 8:30 PM

在格式化字符串,如果包括转义字符,可以将其用方括号包起来:

moment().format('[today] dddd'); // 'today Sunday'

2.时差 (之前,相对于当前时间)

moment().fromNow();
moment().fromNow(Boolean);

如果设置为true,会得到一个不含后缀的值:

moment([2007, 0, 29]).fromNow(); // "11 years ago"
moment([2007, 0, 29]).fromNow(true); // "11 years"

下面是一些用于输出时间范围的标识字符:

范围 标识 输出
0 - 45 秒 s a few seconds ago
45 - 90 秒 m a minute ago
90 秒 - 45 分 mm 2 minutes ago ... 45 minutes ago
45 - 90 分 h an hour ago
90 分 22 小时 hh 2 hours ago ... 22 hours ago
22 - 36 小时 d a day ago
36 小时 - 25 天 dd 2 days ago ... 25 days ago
25 - 45 天 M a month ago
45- 345 天 MM 2 months ago ... 11 months ago
345 - 545 天 (1.5 年) y a year ago
546 天+ yy 2 years ago ... 20 years ago

4.时差 (之前,相对于给定的时间)

moment().from(Moment|String|Number|Date|Array);
moment().from(Moment|String|Number|Date|Array, Boolean);

5.时差 (之后,相对于现在时间)

moment().toNow();
moment().toNow(Boolean);
moment([2007, 0, 29]).toNow();     //"in 11 years"
moment([2007, 0, 29]).toNow(true); // "11 years"

下面是一些用于输出时间范围的标识字符:

范围 标识 输出
0 - 45 秒 s in seconds
45 - 90 秒 m in a minute
90 秒 分 45 秒 mm in 2 minutes ... in 45 minutes
45 - 90 分 h in an hour
90 分 - 22 小时 hh in 2 hours ... in 22 hours
22 - 36 小时 d in a day
36 小时 - 25 天 dd in 2 days ... in 25 days
25 - 45 天 M in a month
45 - 345 天 MM in 2 months ... in 11 months
345 - 547 天 (1.5 年) y in a year
548 天+ yy in 2 years ... in 20 years

6.时差 (之后,相对于给定的时间)

moment().to(Moment|String|Number|Date|Array);
moment().to(Moment|String|Number|Date|Array, Boolean);

7.日历时间

moment().calendar();
moment().calendar(referenceTime);
moment().calendar(referenceTime, formats);  // from 2.10.5

日历时间用于显示参考时间referenceTime(默认为现在时间),但不与moment().fromNow()有所有不同。

moment().calendar()会用跟据传入字符串的不同按不同的格式输出。

moment().calendar(); //"Today at 4:37 PM"

8.时差 (毫秒)

moment().diff(Moment|String|Number|Date|Array);
moment().diff(Moment|String|Number|Date|Array, String);
moment().diff(Moment|String|Number|Date|Array, String, Boolean);

获取一个毫秒级的时差,moment().diff()方法类似于moment().from()方法。

var a = moment([2007, 0, 29]);
var b = moment([2007, 0, 28]);
a.diff(b) // 86400000

如果需要获取其它单位的时间,可以在调用方法时传入第二个参数,传入第三个参数可以获得浮点数:

var a = moment([2008, 9]);
var b = moment([2007, 0]);
a.diff(b, 'years');       // 1
a.diff(b, 'years', true); // 1.75

9.Unix 偏移量 (毫秒) 和 Unix 时间戳 (秒)

moment().valueOf(); //偏移量
+moment(); //偏移量
moment().unix();//时间戳

10.获取当月天数

moment().daysInMonth();

11.获取JavaScript Date对象

moment().toDate();

通过Moment.js获取一个JavaScript Date对象,使用moment().toDate()方法。

将要返回的Date是moment正在使用的对象,所以任何对Date的修改也会导致moment改变。如果你只想获取一个Date副本,应该在调用moment().toDate()方法前使用moment().clone()方法。

12.转换为数组

moment().toArray(); //[2018, 5, 28, 16, 47, 37, 948]

13.转换为JSON

moment().toJSON(); //"2018-06-28T08:47:51.955Z"

14.转换为ISO 8601 字符串

moment().toISOString();
moment().toISOString(keepOffset); // from 2.20.0

15.转换为Object

moment().toObject();

16.转换为字符串

moment().toString();

17.检测

moment().inspect(); //"moment("2018-06-28T16:53:13.184")"

返回一个机器可读的字符串,更多用来debug使用

查询

moment().isBefore(Moment|String|Number|Date|Array);//是否之前
moment().isBefore(Moment|String|Number|Date|Array, String);
moment().isSame(Moment|String|Number|Date|Array);//是否相同
moment().isSame(Moment|String|Number|Date|Array, String);
moment().isAfter(Moment|String|Number|Date|Array);//是否之后
moment().isAfter(Moment|String|Number|Date|Array, String);
moment().isSameOrBefore(Moment|String|Number|Date|Array);
moment().isSameOrBefore(Moment|String|Number|Date|Array, String);
moment().isSameOrAfter(Moment|String|Number|Date|Array);
moment().isSameOrAfter(Moment|String|Number|Date|Array, String);
//From 2.13.0 onward
moment().isBetween(moment-like, moment-like);//是否之间
moment().isBetween(moment-like, moment-like, String);
moment().isBetween(moment-like, moment-like, String, String);
//2.9.0 to 2.12.0
moment().isBetween(moment-like, moment-like);//是否之间
moment().isBetween(moment-like, moment-like, String);
moment().isDST();//是否夏令时
moment('2013-03-10 2:30', 'YYYY-MM-DD HH:mm').isDSTShifted()//是否被转换的夏令时
moment().isLeapYear(); //是否闰年
moment.isMoment(obj);//是否Moment对象
moment.isDate(obj);//是否Date对象

isBeforeisSameisAfterisSameOrBeforeisSameOrAfter的第二个参数和isBetween的第三个参数是时间比较级别,不设置的时候默认比较级别是毫秒级别,设置后会比较当前级别和及其以上级别单位。
isBetween的第四个参数,可以设置左右包含情况,[]表示包含,()表示不包含。

moment('2016-10-30').isBetween('2016-10-30', '2016-12-30', null, '()'); //false
moment('2016-10-30').isBetween('2016-10-30', '2016-12-30', null, '[)'); //true
moment('2016-10-30').isBetween('2016-01-01', '2016-10-30', null, '()'); //false
moment('2016-10-30').isBetween('2016-01-01', '2016-10-30', null, '(]'); //true
moment('2016-10-30').isBetween('2016-10-30', '2016-10-30', null, '[]'); //true

更多精彩请看下一篇:Moment.js 详细教程2