我希望在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的答案
您可以使用utc
function将Moment实例切换为UTC。然后只需使用format
即可获得您想要的任何特定输出。
您将日期格式化为错误。将字母“Z”添加到日期字符串的末尾,它将被视为UTC。
var x = new Date('2019-01-01T00:00:00Z') // Jan 1, 2019 12 AM UTC
使用诸如momentjs(utc
和format
函数)之类的库来管理这些格式化问题,如其他答案中所述。如果你想使用vanilla javascript,你需要在调用toISOString
之前减去时区偏移(请参阅下面较长的答案中的警告)。
javascript中的Date
以一种有点反直觉的方式处理时区。在内部,日期存储为自Unix纪元(1970年1月1日)以来的毫秒数。这是你拨打getTime()
时得到的数字,它是用于数学和比较的数字。
但是 - 当您使用标准字符串格式化函数(toString
,toTimeString
,toDateString
等)时,javascript会在格式化之前自动应用本地计算机时区的时区偏移量。在浏览器中,这意味着它将为最终用户计算机而不是服务器应用偏移量。 toISOString
和toUTCString
函数将不应用偏移量 - 它们打印存储在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这样的库来避免这些复杂性。
如上所述,这里真正的问题是知道日期是被视为本地还是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();
如果确实你拥有的字符串与显示的字符串相同,那么最简单的方法是附加一个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();
你不需要时间 - 时区。