无法使用 moment.js 返回 UTC 日期时间

Posted

技术标签:

【中文标题】无法使用 moment.js 返回 UTC 日期时间【英文标题】:cannot return a utc datetime with moment.js 【发布时间】:2015-12-14 15:45:47 【问题描述】:

试图将已经被 momentjs 转换为 UTC 的 datetime 对象传递给我的 MVC 控制器。我正在使用剑道 datetimepicker,出于某种原因,moment.utc 不会向控制器发送我想要的值。例如,我在我的剑道 datetimepicker 中输入“9/17/2015 12:00 AM”。我得到这个值:

var start = $("#startTime").val();

这给了我 "9/17/2015 12:00 AM" 。伟大的。然后我将其转换为日期对象:

var t1 = new Date(start);

读取为 Thu Sep 17 2015 00:00:00 GMT-0700 (Pacific Daylight Time) 。看起来还是不错的。接下来我尝试使用时刻转换为 UTC:

var t2 = moment.utc(t1);

这给了我

dt _isAMomentObject: true, _i: Thu Sep 17 2015 00:00:00 GMT-0700 (Pacific Daylight Time), _isUTC: true, _locale: fu, _d: Thu Sep 17 2015 00:00:0...

未转换为 UTC。而不是转换它似乎所做的一切是获取一个日期对象,让我告诉它“嘿,这是 UTC”,它说“好的”(通过标记 _isUTC:true),即使它仍然在那里保存 GMT 值

即使我决定先制作一个时刻对象,然后在其上运行 UTC?结果还是一样:

var t2 = moment(t1);
var t3 = moment.utc(t2);

因此,如果我在其中任何一个值上运行 .format()(这是我需要传递给我的控制器的内容),我总是会得到“2015-09-17T07:00:00+00:00”,这不是 UTC 时间。这是我输入的确切时间。我在这里做错了什么?

【问题讨论】:

【参考方案1】:

一些事情:

甚至不要查看带有下划线前缀的字段。它们是 moment.js 内部设计的一部分,并不意味着直接使用。在许多情况下,必须组合几个字段才能获得正确的结果。这在公共 API 的函数中进行了说明,例如 format

不要依赖Date 对象来进行解析。跨浏览器的结果可能不一致。 Moment 有自己的解析器,您可以像这样使用它:

moment("9/17/2015 12:00 AM","M/D/YYYY h:mm A")

但是,在您的特定情况下,您实际上根本不需要解析任何字符串。你说你使用的是 Kendo 的 DateTimePicker 控件,所以你应该使用 value 函数,它已经返回了一个 Date 对象。

Moment 有两种不同的函数用于处理 UTC。

moment.utc(value) - 根据 UTC 解释值 m.utc() - 其中m 是任意时刻实例,值转换为 UTC

请注意,第二个它通过将现有实例从“本地模式”切换到“UTC 模式”来改变现有实例。如果你想链接函数,它也会返回实例,但它也会修改原始实例。

如果您希望输出显示+00:00 偏移量,可以在转换为UTC 后使用format。但是,如果您想显示 Z(通常是首选),您可以直接调用 .toISOString() 而无需先明确转到 UTC - 因为该函数总是输出 UTC。

此外,大多数现代浏览器已经直接在Date 对象上支持.toISOString(),因此除非您针对的是旧版浏览器,否则您可能根本不需要时间。

您说"2015-09-17T07:00:00+00:00" 不是UTC 时间,但实际上它是。您从 UTC-7 的 00:00 开始,相当于 UTC+0 的 7:00。因此,尽管跳过了几个不必要的步骤,但最终时刻仍然正确 - 至少在 t3 中是这样。

您可以使用以下任何一种来简化您的代码:

var picker = $("#startTime").data().kendoDateTimePicker;
var dt = picker.value();  // dt is a Date object
var m = moment(dt);       // m is a moment object
m.utc();                  // m has been converted to UTC
var s = m.format();       // ex: "2015-09-17T07:00:00+00:00"

或者……

var picker = $("#startTime").data().kendoDateTimePicker;
var dt = picker.value();  // dt is a Date object
var m = moment(dt);       // m is a moment object
var s = m.toISOString();  // ex: "2015-09-17T07:00:00Z"

或者……

var picker = $("#startTime").data().kendoDateTimePicker;
var dt = picker.value();  // dt is a Date object
var s = dt.toISOString(); // ex: "2015-09-17T07:00:00Z"  (requires browser support)

【讨论】:

谢谢,这很有帮助。奇怪的是它仍然不适合我,我确保 javascript 工作正常(plnkr.co/edit/JchbfJqAwJwIr8zm803K?p=preview),但显然我遇到的其他问题之一是我的 MVC 控制器将 datetime 参数作为输入。由于某种原因,这将对象 BACK 转换为本地时间。一旦我将该参数更改为字符串,它就可以正常工作。诡异的。谢谢! 是的,这可能是 ASP.NET MVC 的问题。尽管如果您改用 WebAPI,则不会有这个问题,因为反序列化是由 JSON.net 处理的。你也可以试试DateTimeOffset

以上是关于无法使用 moment.js 返回 UTC 日期时间的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

JS 将UTC时间转为本地时间

针对当前时区调整的不同夏令时的UTC日期[重复]

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