Moment.js 手册

指南区域旨在帮助开发人员学习如何更好地与日期和时间问题域以及Moment.js库进行交互。
我们在这里解决了我们最常见的支持请求,因此它是检查您可能遇到的任何问题的解决方案的好地方。

指南部分是新的,仍在建设中。如果您有想要在此处查看的指南的请求,或者想要添加指南,
请在momentjs.com 存储库中创建问题或提出拉取请求。

如果你刚刚开始,请查看这个scrimba时刻指南。

可变性 1.0.0+

Moment.js中的时刻对象是可变的。这意味着add,subtract或set等操作会更改原始时刻对象。
当第一次使用Moment.js时,许多开发人员对这样的场景感到困惑:

var a = moment('2016-01-01'); 
var b = a.add(1, 'week'); 
a.format();
"2016-01-08T00:00:00-06:00"

如您所见,添加一个变量a。为了避免这种情况,请在执行日期数学之前克隆一下:

var a = moment('2016-01-01'); 
var b = a.clone().add(1, 'week'); 
a.format();
"2016-01-01T00:00:00-06:00"

日期数学与时间数学

时间数学和日期数学之间存在逻辑差异。

在Moment.js中,时间数学采用线性时间标度,只是将基于UTC的时间戳递增或递减所提供的时间单位数量。

日期数学不使用线性时间刻度,而是递增或递减日历上的日期。这是因为一天,一个月或一年中的时间量是可变的。
例如,由于夏令时转换,一天可能在23到25小时之间。
当然月份的天数也不同,由于闰年,年份的长度也各不相同。日期数学可能会导致一些有趣的场景

由于夏令时,一天可能不等于24小时:

//date math
moment('2016-03-12 13:00:00').add(1, 'day').format('LLL')
"March 13, 2016 1:00 PM"
//time math
moment('2016-03-12 13:00:00').add(24, 'hours').format('LLL')
"March 13, 2016 2:00 PM"

由于闰年,一年可能不等于365天:

moment('2016-01-01').add(1, 'year').format('LL')
"January 1, 2017"
moment('2016-01-01').add(365, 'day').format('LL')
"December 31, 2016"

由于日数学中持续时间的变化,Moment的API不正式支持添加或减去几天和更大的十进制值。
Moment.js将接受十进制值,并尽力通过舍入到最接近的整数来处理它们。

截至2.12.0十进制日和月值使用绝对值/ round转换为整数。这意味着1.5轮到2轮,-1.5轮到-2轮。

moment().add(1.5, 'days') == moment().add(2, 'days')
moment().add(-1.5, 'days') == moment().add(-2, 'days') == moment().subtract(1.5, 'days') == moment().subtract(2, 'days')
moment().add(2.3, 'months') == moment().add(2, 'months')
moment().add(-2.3, 'months') == moment().add(-2, 'months') == moment().subtract(2.3, 'months') == moment().subtract(2, 'months')

将季度和年份转换为月份,然后是绝对值/舍入。

moment().add(1.5, 'years') == moment().add(18, 'months')
moment().add(.8, 'years') == moment().add(9.6, 'months') == moment().add(10, 'months')
moment().add(1.5, 'quarters') == moment().add(4.5, 'months') == moment().add(5, 'months')

时区与偏移

人们常常对时区和UTC偏移之间的差异感到困惑。

UTC偏移量是表示特定日期和时间距离UTC的距离的值。它在大多数情况下以HH:mm的格式表示。

时区是一个地理区域,所有人都遵守法定的标准时间。

由于夏令时,时区通常与UTC有一个以上的偏移。在一年中的某些时间点,几个时区可能具有相同的偏移量。
例如,美国/芝加哥,美国/丹佛和美国/伯利兹的时区在不同时间都有-06:00的偏移。因此,不可能仅从偏移值推断出时区。

Moment.js核心库提供与基于偏移值调整时间相关的功能。
它不支持根据时区数据调整日期 - 这是由Moment TimeZone库提供的。

有关此问题的深入描述,请参阅Stack Overflow标记。

JavaScript日期

Moment.js为本机JavaScript日期对象提供了一个包装器。
在这样做时,Moment.js扩展了功能,并且还解决了对象中的一些缺陷。

使用原生日期解析显然是不可预测的。例如,假设我在美国使用计算机,但我有DD / MM / YYYY格式的日期。

var a = new Date('01/12/2016'); //December 1 2016 in DD/MM/YYYY format
//"Tue Jan 12 2016 00:00:00 GMT-0600 (Central Standard Time)"

对于使用本机Date对象的此行为,没有好的解决方法。
Moment的解析器处理得很好但是:

moment('01/12/2016', 'DD/MM/YYYY', true).format()
"2016-12-01T00:00:00-06:00"

此外,ECMA Script 5规范对ISO 8601日期的偏移做出了不同寻常的断言:

缺席时区偏移的值是"Z"

实际上,这意味着ISO 8601没有偏移的日期将被视为UTC值,从而产生以下奇怪之处:

//US local format
var a = new Date('1/1/2016'); 
//"Fri Jan 01 2016 00:00:00 GMT-0600 (Central Standard Time)"

//ISO 8601
var a = new Date('2016-01-01');
//"Thu Dec 31 2015 18:00:00 GMT-0600 (Central Standard Time)"

ES2015规范修复了这个错误,使其符合ISO8601规范,该规范指定了没有偏移的本地时间。
这本身就很糟糕,因为它有很多负面的后兼容性含义。

使用Moment时,除非另行指定,否则日期始终被解释为本地时间。随着ES2015的采用,这不会改变。

moment('2016-01-01')
//"2016-01-01T00:00:00-06:00"

算术是缺少本机Date对象的另一个区域。Date对象实际上没有为此提供API。相反,它依赖于溢出的日期值。
假设您想在2016年4月30日之前添加1天。使用日期对象,您将执行以下操作:

var a = new Date('4/30/2016'); 
a.setDate(a.getDate() + 1);

这样做的伎俩,但有点不直观。
Moment提供了一个加/减的API:

moment('4/30/2016', 'MM/DD/YYYY').add(1, 'day')
//"2016-05-01T00:00:00-05:00"

内部属性

Moment对象具有几个以前缀为前缀的内部属性_.

最常见的内部属性是_d保存Moment包装器的JavaScript日期的属性。
通常,开发人员对控制台输出的价值感到困惑_d.
Moment使用一种称为epoch移位的技术,该技术有时会使该属性与Moment反映的实际日期值不同。
特别是如果正在使用Moment TimeZone,则此属性几乎不会与Moment从其公共.format() 函数输出的实际值相同。
因此,_d前缀的值和任何其他属性_不应用于任何目的。

要打印出的时刻,利用价值.format(), .toString().toISOString().

要从Moment检索本机Date对象,请使用.toDate()。此函数返回正确移位的日期,以便与第三方API进行交互。

Moment.js有一个非常灵活和高级的解析器,允许广泛的功能。
解析器的灵活性也使其成为Moment.js中最常被滥用的工具之一。

本节列出了有关如何在您的情况下正确使用解析器的一些指导原则。

本地vs UTC与偏移

Moment提供了三个解析日期的函数moment,moment.utc和moment.parseZone。

如果您希望在用户当地时间的上下文中与日期进行交互,请使用时刻功能。

moment('2016-01-01T23:35:01');

这会导致UTC偏移量与本地计算机相同的日期:

"2016-01-01T23:35:01-06:00"

如果您希望以UTC日期与日期进行互动,请使用moment.utc:

moment.utc('2016-01-01T23:35:01');

这会导致utc偏移量为+0:00的日期:

"2016-01-01T23:35:01+00:00"

如果您的日期格式具有固定的时区偏移量,请使用moment.parseZone:

moment.parseZone("2013-01-01T00:00:00-13:00");

这导致具有固定偏移的日期:

"2013-01-01T00:00:00-13:00"

请注意,如果使用moment()或moment.utc()来解析具有指定偏移量的日期,则日期将从该偏移量转换为本地或UTC:

此日期移动了8小时,从+2移动到-6(本地机器的偏移量)

moment('2016-01-01T00:00:00+02:00').format()
"2015-12-31T16:00:00-06:00"

这个日期移动了2个小时,从+2移动到UTC

moment.utc('2016-01-01T00:00:00+02:00').format()
"2015-12-31T22:00:00+00:00"

已知日期格式

如果您知道要解析的日期字符串的格式,则始终是明确指定该格式的最佳选择。

例子:

moment('01/01/2016', 'MM/DD/YYYY')
moment('2016-01-01 11:31:23 PM', 'YYYY-MM-DD hh:mm:ss a')

如果您的日期采用ISO 8601格式,则可以使用常量内置时刻来指示:

moment('2016-01-01 12:25:32', moment.ISO_8601)

ISO 8601格式包括但不限于:

2013-02-08               # A calendar date part
2013-W06-5               # A week date part
2013-02-08T09            # An hour time part separated by a T
2013-02-08 09            # An hour time part separated by a space
2013-02-08 09:30:26      # An hour, minute, and second time part
2013-02-08 09+07:00      # +-HH:mm

有关完整列表的解析字符串,请参阅API文档。

严格的模式

严格模式是解析日期的推荐模式。如果您的代码库允许,您应该始终使用严格模式。
可以通过严格模式修复GitHub和Stack Overflow上看到的解析器问题的一半以上。

在以后的版本中,解析器将默认使用严格模式。

严格模式要求输入到当前时刻与指定的格式完全匹配,包括分隔符。通过将true作为第三个参数传递给moment函数来设置严格模式。

moment('01/01/2016', 'MM/DD/YYYY', true).format()
"2016-01-01T00:00:00-06:00"
moment('01/01/2016 some text', 'MM/DD/YYYY', true).format()
"Invalid date"

分隔符匹配:

//forgiving mode
moment('01-01-2016', 'MM/DD/YYYY', false).format()
"2016-01-01T00:00:00-06:00"
//strict mode
moment('01-01-2016', 'MM/DD/YYYY', true).format()
"Invalid date"

严格模式修复的场景:

//UUID matches YYYYDDD because it starts with 7 digits
moment('5917238b-33ff-f849-cd63-80f4c9b37d0c', moment.ISO_8601).format()
"5917-08-26T00:00:00-05:00"
//strict mode fails because trailing data exists
moment('5917238b-33ff-f849-cd63-80f4c9b37d0c', moment.ISO_8601, true).format()
"Invalid date"
//date has out of range value but is parsed anyways
moment('100110/09/2015', 'MM/DD/YYYY').format()
"2015-10-09T00:00:00-05:00"
//strict mode catches out of range issue
moment('100110/09/2015', 'MM/DD/YYYY', true).format()
"Invalid date"
//wrong date is parsed because strict mode ignores trailing data
moment('2016-12-31 11:32 PM').format('LT')
"11:32 AM"
//trailing data is noticed
moment('2016-12-31 11:32 PM', moment.ISO_8601, true).format('LT')
"Invalid date"

宽松模式

虽然严格模式在大多数情况下效果更好,但是当传递给时刻的字符串格式可能不同时,宽容模式非常有用。

宽容模式有用的常见情况是第三方API提供日期,并且该API的日期格式可能会发生变化。假设API以“YYYY-MM-DD”格式发送日期开始,然后更改为“MM / DD / YYYY”格式。

在严格模式下,以下代码会显示 'Invalid Date'

moment('01/12/2016', 'YYYY-MM-DD', true).format()
"Invalid date"

在使用格式字符串的宽容模式下,您的日期错误:

moment('01/12/2016', 'YYYY-MM-DD').format()
"2001-12-20T00:00:00-06:00"

原谅模式中的错误日期场景对于用户来说肯定不那么明显,但是这个令牌可能会被忽视很长一段时间。

在严格模式和宽容模式之间进行选择时,重要的是要考虑日期是否准确更重要,或者日期永远不会显示为"Invalid Date".

多种格式

Moment的解析器支持为日期字符串指定多种可能的格式。这对于日期可能来自多个数据源的情况非常有用。
只需将格式作为数组传递:

moment('12 March, 2016', ['DDMMMMY', 'MMMMDDY']).format()
"2016-03-12T00:00:00-06:00"
moment('March 12, 2016', ['DDMMMMY', 'MMMMDDY']).format()
"2016-03-12T00:00:00-06:00"

为了使此功能正常工作,时刻必须解析所提供的每种格式。因此,使用的格式越多,解析所需的时间就越长。
Moment用于确定使用哪种格式的启发式方法如下:

  • 首选格式会导致有效日期超过无效日期。
  • 更喜欢解析更多字符串而不是更少字符串的格式,并使用更多格式而不是更少,即更喜欢更严格的解析。
  • 首选阵列中较早的格式。

有几个地方Moment.js显示有关将来要删除的功能的弃用警告。这里概述了解决方法。

定义区域设置覆盖

Use moment.updateLocale(localeName, config) to change an existing locale. 
moment.defineLocale(localeName, config) should only be used for creating a new locale

当您尝试使用defineLocale函数更改现有语言环境时,将引发此弃用警告。
执行此操作将导致与属性继承相关的意外行为。moment.updateLocale将正确替换现有语言环境中的属性。

查看原始拉取请求

父区域设置未定义

自2.16.0以来已删除警告。

在定义或加载父本身之前,可以使用父级定义语言环境。如果父节点不存在或者在创建时刻时无法延迟加载,则父节点将默认为全局区域设置。

找不到区域设置

Locale <key> not found. Did you forget to load it?

设置全局区域设置但Moment无法找到时,将显示此警告。也许这个区域设置没有捆绑在您的副本中。

加/减

moment().add(period, number) is deprecated. Please use moment().add(number, period)
moment().subtract(period, number) is deprecated. Please use moment().subtract(number, period)

不推荐使用时刻将加减参数排序为(period, number)。反转您的参数。(

坏:

moment().add('hours', 3);

好:

moment().add(3, 'hours');

最小/最大

moment().min is deprecated, use moment.max
moment().max is deprecated, use moment.min

这个警告不是拼写错误,但令人困惑。

在版本2.7.0之前,支持moment().min和moment().max函数。这些功能不直观。

Min将返回有问题的两个时刻中的较大者,而max将返回较小的时刻。

由于这种反转行为,弃用警告中提供的建议是正确的。

moment('2016-01-01').min('2016-02-01').format()
"2016-02-01T00:00:00-06:00"
//is equivalent to
moment.max(moment('2016-01-01'), moment('2016-02-01')).format()
"2016-02-01T00:00:00-06:00"
moment('2016-01-01').max('2016-02-01').format()
"2016-01-01T00:00:00-06:00"
//is equivalent to
moment.min(moment('2016-01-01'), moment('2016-02-01')).format()
"2016-01-01T00:00:00-06:00"

请参阅原始GitHub问题。

moment().zone is deprecated, 
use moment().utcOffset instead.

这种弃用是为了清楚起见。

结果moment().zone()是一个整数,表示给定时刻偏离UTC的分钟数,符号反转(US时刻产生正值)。

使用 moment().zone(number)设置偏移量将设置日期的偏移量,也使用反转符号。

由于时区与偏移量不同,因此名称已更改为utcOffset。那时,符号被更正以反映UTC偏移的实际方向。

moment().zone()
360
//is replaced by
moment().utcOffset()
-360

moment().zone(420)
//is replaced by 
moment().utcOffset(-420)

有关时区与偏移的更多信息,请参阅时区与偏移指南。

查看原始GitHub问题。