tl;博士;
您的日期格式错误。将字母“Z”添加到日期字符串的末尾,它将被视为 UTC。
var x = new Date('2019-01-01T00:00:00Z') // Jan 1, 2019 12 AM UTC
如其他答案中所述,使用诸如 momentjs(utc 和 format 函数)之类的库更容易管理这些格式问题。如果您想使用原版 javascript,则需要在调用 toISOString 之前减去时区偏移量(请参阅下面较长答案中的警告)。
详情
Date 在 javascript 中处理时区的方式有点反直觉。在内部,日期存储为自 Unix 纪元(1970 年 1 月 1 日)以来的毫秒数。这是您拨打getTime() 时得到的号码,它是用于数学和比较的号码。
但是 - 当您使用标准字符串格式化函数(toString、toTimeString、toDateString 等)时,javascript 会在格式化之前自动应用本地计算机时区的时区偏移量。在浏览器中,这意味着它将为最终用户计算机应用偏移量,而不是服务器。 toISOString 和 toUTCString 函数不会应用偏移量 - 它们打印存储在 Date 中的实际 UTC 值。这对您来说可能仍然看起来“错误”,因为它与您在控制台或调用 toString 时看到的值不匹配。
这才是真正有趣的地方。您可以通过使用new Date(milliseconds) 或使用带有new Date(dateString) 的解析器指定自Unix 纪元以来的毫秒数,在javascript 中创建Date。使用毫秒方法,无需担心时区 - 它被定义为 UTC。问题是,使用 parse 方法,javascript 如何确定您想要的时区?在 ES5(2009 年发布)之前,答案是不同的取决于浏览器!发布 ES5,答案取决于你如何格式化字符串!如果您使用 ISO 8601 的简化版本(只有日期,没有时间),javascript 会将日期视为 UTC。否则,如果您以 ISO 8601 格式指定时间,或者使用“人类可读”格式,它会将日期视为本地时区。 Check out MDN 了解更多。
一些例子。如果 javascript 将其视为 UTC 或本地日期,我已经指出了每个。在 UTC 中,该值将是 1970 年 1 月 1 日午夜。在本地,它取决于时区。对于太平洋时间 (UTC-8) 中的 OP,UTC 值为 1970 年 1 月 1 日上午 8 点。
new Date(0) // UTC (milliseconds is always UTC)
new Date("1/1/1970"); // Local - (human readable string)
new Date("1970-1-1"); // Local (invalid ISO 8601 - missing leading zeros on the month and day)
new Date("1970-01-01"); // UTC (valid simplified ISO 8601)
new Date("1970-01-01T00:00"); // Local (valid ISO 8601 with time and no timezone)
new Date("1970-01-01T00:00Z"); // UTC (valid ISO 8601 with UTC specified)
您不能更改此行为 - 但您可能对用于解析日期的格式持迂腐态度。在您的情况下,问题是您提供了一个带有时间组件但没有时区的 ISO-8601 字符串。将字母“Z”添加到字符串的末尾,或者删除时间都对你有用。
或者,总是使用像 momentjs 这样的库来避免这些复杂性。
Vanilla JS 解决方法
如前所述,这里的真正问题是知道日期是被视为本地日期还是 UTC。您不能从本地“转换”为 UTC,因为所有 Date 已经是 UTC - 它只是格式化。但是,如果您确定日期被解析为本地日期并且它确实应该是 UTC,您可以通过手动调整时区偏移量来解决它。这被称为“时代转移”(感谢@MattJohnson 的这个词!)而且很危险。您实际上创建了一个指向不同时间点的全新日期!如果你在代码的其他部分使用它,你可能会得到不正确的值!
这是一个时代偏移方法示例(为清楚起见,从castAsUtc 重命名)。首先从对象获取时区偏移量,然后减去它并使用新值创建一个新日期。如果您将其与toISOString 结合使用,您将获得所需格式的日期。
function epochShiftToUtc(date) {
var timezoneOffsetMinutes = date.getTimezoneOffset();
var timezoneOffsetMill = timezoneOffsetMinutes * 1000 * 60;
var buffer = new Date(date.getTime() - timezoneOffsetMill);
return buffer;
}
epochShiftToUtc(date).toUTCString();