Moment.js 指南

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

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

如果您刚刚开始,请查看此scrimba时刻指南

可变性 1.0.0+

编辑

Moment.js中的一下对象是可变的。这意味着加,减或设置之类的操作会更改原始矩对象。
初次使用Moment.js时,许多开发人员对这样的场景感到困惑:

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

如您所见,加上mutated一个星期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小时之间。
当然,月份的天数会有所不同,并且由于leap年,年份的长度也会有所不同。日期数学可能会导致一些有趣的情况。

由于夏令时,一天可能不等于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"

由于leap年,一年可能不等于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开始,十进制的日和月值使用绝对值/舍入值转换为整数。这意味着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的偏移量不止一个。在一年中的某些时候,几个时区可能具有相同的偏移量。
例如,时区America / Chicago,America / Denver和America / Belize在不同时间的偏移均为-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天。使用date对象,您可以执行以下操作:

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 Date 属性。
通常,控制台的输出会混淆开发人员的价值_d
Moment使用了一种称为时代转移的技术,该技术有时会导致此属性与Moment反映的实际日期值不同。
特别是如果使用Moment TimeZone,则此属性几乎永远不会与Moment从其公共.format()功能输出的实际值相同
因此,不得将的值_d和任何其他属性作为前缀_使用。

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

要从Moment中检索本地Date对象,请使用.toDate()此函数返回一个适当偏移的日期,以便与第三方API进行交互。

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

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

本地vs UTC vs偏移

编辑

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('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”格式。

在严格模式下,以下代码导致显示“无效日期”:

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"

对于宽恕模式而言,错误的日期方案对用户而言显然不那么明显,但由于这种原因,很长一段时间都不会引起注意。

在严格和宽恕模式之间进行选择时,重要的是要考虑是否更重要的一点是日期要准确,或者日期永远不要显示为“无效日期”。

多种格式

编辑

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)

不建议使用矩,即对加减法参数(时间,数字)进行排序。反转参数。

坏:

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支持moment()。min和moment()。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偏移的分钟数(带反转符号)(美国时刻表示正值)。

使用moment().zone(number)设置偏移量将在日期上设置偏移量,同时也使用反斜杠。

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

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

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

有关时区与偏移量的更多信息,请参见《时区与偏移量》指南。

查看原始GitHub问题。

这些资源由日期/时间/时区社区的成员提供。