替代在Javascript中投射UTC日期?

问题描述 投票:2回答:3

我希望在JS中创建一个新的Date,但是它可以作为UTC时间进行转换。例如,假设castAsUTC()产生以下预期效果:

var x = new Date('2019-01-01T00:00:00') // In local time (PST)
castAsUTC(x).toISOString(); // => '2019-01-01T00:00:00Z'
// x.toISOString() gives us '2019-01-01T08:00:00Z', which is undesired

目前,我的功能如下:

function castAsUTC(date) {
  return new Date(x.toLocaleString() + '+00:00');
}

是否有更清洁/更好的方式产生相同的效果?提前致谢!

编辑:更具体地说,我有兴趣转换日期的时区,而不是用尽可能少的算术改变它的实际值。因此,调用.toISOString()将产生与当地时间相同的日期。

我目前正在使用moment-timezone库,但我似乎无法使用它获得所需的效果。我绝对会接受使用Moment.js的答案

javascript date
3个回答
2
投票

您可以使用utc function将Moment实例切换为UTC。然后只需使用format即可获得您想要的任何特定输出。


1
投票

tl;dr;

您将日期格式化为错误。将字母“Z”添加到日期字符串的末尾,它将被视为UTC。

var x = new Date('2019-01-01T00:00:00Z')    // Jan 1, 2019 12 AM UTC

使用诸如momentjs(utcformat函数)之类的库来管理这些格式化问题,如其他答案中所述。如果你想使用vanilla javascript,你需要在调用toISOString之前减去时区偏移(请参阅下面较长的答案中的警告)。

Details

javascript中的Date以一种有点反直觉的方式处理时区。在内部,日期存储为自Unix纪元(1970年1月1日)以来的毫秒数。这是你拨打getTime()时得到的数字,它是用于数学和比较的数字。

但是 - 当您使用标准字符串格式化函数(toStringtoTimeStringtoDateString等)时,javascript会在格式化之前自动应用本地计算机时区的时区偏移量。在浏览器中,这意味着它将为最终用户计算机而不是服务器应用偏移量。 toISOStringtoUTCString函数将不应用偏移量 - 它们打印存储在Date中的实际UTC值。这可能看起来仍然“错误”,因为它与您在控制台中看到的值或调用toString时不匹配。

事情真正变得有趣。您可以在javascript中创建Date,方法是使用new Date(milliseconds)或使用new Date(dateString)解析器指定自Unix纪元以来的毫秒数。使用毫秒方法,没有时区可以担心 - 它被定义为UTC。问题是,使用解析方法,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 Workaround

如上所述,这里真正的问题是知道日期是被视为本地还是UTC。你不能从本地“施放”到UTC,因为所有的Date都已经是UTC了 - 它只是格式化。但是,如果您确定将日期解析为本地且它应该是UTC,则可以通过手动调整时区偏移来解决它。这被称为“epoch转换”(感谢@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();

0
投票

如果确实你拥有的字符串与显示的字符串相同,那么最简单的方法是附加一个Z来表示UTC。

var input = '2019-01-01T00:00:00';
var date = new Date(input + 'Z');
var output = date.toISOString();

或者,如果您想使用Moment.js,请执行以下操作:

var input = '2019-01-01T00:00:00';
var m = moment.utc(input);
var output = m.format();

你不需要时间 - 时区。

© www.soinside.com 2019 - 2024. All rights reserved.