指南区域旨在帮助开发人员学习更好地与日期和时间问题域以及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)
这些资源由日期/时间/时区社区的成员提供。