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】:
Date
和moment
默认都会在浏览器的本地时区解析输入字符串。然而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()
= 12
和 d.getDate()
= 11
是的,有一些例外。 ES5(大多数当前浏览器)会将带有连字符的日期解释为 UTC,但几乎所有其他内容都被解释为本地时间。 ES6 正在改变这种行为以解释与本地时间相同的字符串。我更新了答案。
问题是,ISO8601 明确指出,除非提供偏移量(或 Z
),否则该区域被假定为 local。 EcmaScript 在原始规范中忽略了这一点,只是假设所有 ISO 格式默认都应该是 UTC。他们正在为 ES6 “修复它”,因此它符合实际的 ISO 规范。看看“修复”创建了多少新错误应该很有趣。 :)以上是关于moment.js - UTC 给出错误的日期的主要内容,如果未能解决你的问题,请参考以下文章