moment.js - UTC 给出错误的日期

Posted

技术标签:

【中文标题】moment.js - UTC 给出错误的日期【英文标题】:moment.js - UTC gives wrong date 【发布时间】:2013-07-25 05:13:22 【问题描述】:

为什么 moment.js UTC 总是显示错误的日期。例如来自 chrome 的开发者控制台:

moment(('07-18-2013')).utc().format("YYYY-MM-DD").toString()
// or
moment.utc(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

他们都将返回 "2013-07-17" 为什么返回 17th 而不是传入的 18th

但是如果我使用没有 utc 的 momentjs:

moment(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

我返回 “2013-07-18”,这也是我在使用 moment.js UTC 时所期望的。

这是否意味着我们在使用 moment.js UTC 时无法获得正确的日期?

【问题讨论】:

我认为在format() 之后不需要toString()(它已经返回一个字符串)。 【参考方案1】:

使用这个:

return moment.utc(new Date(oData.CreatedAtUtc), 'MM/DD/YYYY h:mm A').local().format("YYYY-MM-DD HH:mm") + ' (' + timezoneAbbr + ')';

【讨论】:

【参考方案2】:

默认情况下,MomentJS 以本地时间解析。如果只提供日期字符串(没有时间),则时间默认为午夜。

在您的代码中,您创建了一个本地日期,然后将其转换为 UTC 时区(实际上,它使时刻实例切换到 UTC mode),因此当它被格式化时,它会被转移(取决于您的本地时间)向前或向后。

如果本地时区为 UTC+N(N 为正数),并且您解析一个仅限日期的字符串,您将获得上一个日期。

这里有一些例子来说明它(我的本地时间偏移是 DST 期间的 UTC+3):

>>> moment('07-18-2013', 'MM-DD-YYYY').utc().format("YYYY-MM-DD HH:mm")
"2013-07-17 21:00"
>>> moment('07-18-2013 12:00', 'MM-DD-YYYY HH:mm').utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 09:00"
>>> Date()
"Thu Jul 25 2013 14:28:45 GMT+0300 (Jerusalem Daylight Time)"

如果您希望将日期时间字符串解释为 UTC,则应明确说明:

>>> moment(new Date('07-18-2013 UTC')).utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

或者,正如马特约翰逊在他的回答中提到的那样,您可以(并且可能应该)首先使用 moment.utc() 将其解析为 UTC 日期,并将格式字符串作为第二个参数包含在内避免歧义。

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

反之,将 UTC 日期转换为本地日期,您可以使用local() 方法,如下所示:

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').local().format("YYYY-MM-DD HH:mm")
"2013-07-18 03:00"

【讨论】:

非常感谢。所以基本上,我应该总是在使用 UTC 时及时传递,或者像你的第二种方法一样传递 UTC。 要么坚持,要么坚持当地时区。如果您从服务器发送时间,您可以将它们表示为 Unix 时间戳 (X) 或特定时区的字符串。无论如何,为什么要使用 UTC 而不是用户的本地时区(除了向服务器发送规范化数据的目的)? 请注意,new Date('07-18-2013 UTC') 将无法在 IE8 中工作,如果您关心的话。 我已经为此苦苦挣扎了很久。他们真的应该在他们的网站上很好地解释这一点,因为我认为这是 moment.js 最常见的用例。太感谢了!你真的救了我的皮肤! 此代码适用于我:[code] moment(strDate, 'DD/MM/YYYY h:mm A').utc(strDate).format("YYYY-MM-DD HH:mm ") [/code]【参考方案3】:

Datemoment 默认都会在浏览器的本地时区解析输入字符串。然而Date 有时与这方面不一致。如果字符串具体为YYYY-MM-DD,使用连字符,或者如果它是YYYY-MM-DD HH:mm:ss,它将解释为当地时间。与Date 不同,moment 在解析方式上始终保持一致。

以您提供的格式将输入时刻解析为 UTC 的正确方法如下:

moment.utc('07-18-2013', 'MM-DD-YYYY')

请参阅this documentation。

如果你想为输出设置不同的格式,你可以这样做:

moment.utc('07-18-2013', 'MM-DD-YYYY').format('YYYY-MM-DD')

您无需显式调用toString

请注意,提供输入格式非常重要。如果没有它,像 01-04-2013 这样的日期可能会被处理为 1 月 4 日或 4 月 1 日,具体取决于浏览器的文化设置。

【讨论】:

仅供学习,在控制台中:moment.utc('2013-07-18 0:00 +0100', 'YYYY-MM-DD HH:mm') 给了我 "2013-07-18 0:00 +0100" 但是运行时在 jsfiddle 上显示的不同是:2013 年 7 月 25 日星期四 01:00:00 GMT+0100 请注意 01:00:00。谢谢。 在控制台上输出一个原始的moment 不是很有用。您可能正在查看其内部属性之一。您应该在检查结果之前对其进行格式化。例如moment.utc().format()moment().format() 默认情况下,日期和时刻都会在浏览器的本地时区解析输入字符串。我现在在 EDT。 new Date('2010-12-12') 在 FF 38.0.5 中给了我 Date Sat Dec 11 2010 19:00:00 GMT-0500 (Eastern Daylight Time)。只是为了具体说明“在当地时间”的含义,确切地说——在这种情况下,它似乎意味着,Date 将假定无时区字符串采用 UTC 并解析为本地时间。” i> d.getUTCDate() = 12d.getDate() = 11 是的,有一些例外。 ES5(大多数当前浏览器)会将带有连字符的日期解释为 UTC,但几乎所有其他内容都被解释为本地时间。 ES6 正在改变这种行为以解释与本地时间相同的字符串。我更新了答案。 问题是,ISO8601 明确指出,除非提供偏移量(或 Z),否则该区域被假定为 local。 EcmaScript 在原始规范中忽略了这一点,只是假设所有 ISO 格式默认都应该是 UTC。他们正在为 ES6 “修复它”,因此它符合实际的 ISO 规范。看看“修复”创建了多少新错误应该很有趣。 :)

以上是关于moment.js - UTC 给出错误的日期的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Moment.js 日期转换为用户本地时区?

使用moment.js解析时如何忽略时区

如何使用 Moment.js 从日期中删除时间?

JS 将UTC时间转为本地时间

使用 moment.js 将跨越秋季 DST 边界的一系列非 UTC 时间戳转换为 UTC 时间戳的正确方法?

将 UTC 日期和时间转换为 UNIX 时间会给出错误的(时区不同)值。为啥?