指南区域旨在帮助开发人员学习更好地与日期和时间问题域以及Moment.js库进行交互。
我们在这里解决了我们最常见的支持请求,因此这里是检查您可能遇到的任何问题的解决方案的好地方。
指南部分是新的,仍在建设中。如果您希望在此处看到指南的要求,或者想添加指南,
请在momentjs.com存储库中创建问题或提出拉取请求。
如果您刚刚开始,请查看此scrimba时刻指南。
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库提供。
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最常被滥用的工具之一。
本节列出了有关如何在您的情况下正确使用解析器的一些准则。
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
推荐使用严格模式解析日期。如果您的代码库允许,则应始终使用严格模式。
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都会显示有关功能的弃用警告,这些警告将来会被删除。此处概述了解决方法。
Moment construction falls back to js Date.
This is discouraged and will be removed in an upcoming major release.
如果找不到传递给字符串构造函数的日期的已知格式,则会引发此弃用警告。
要变通解决此问题,请为传递给的字符串指定格式moment()
。
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"
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)
这些资源由日期/时间/时区社区的成员提供。