从 UTC 创建日期
默认情况下,Date
对象创建为本地时间。这并不总是令人满意的,例如在服务器和客户端之间传送不在同一时区的日期时。在这种情况下,根本不需要担心时区,直到日期需要在当地时间显示,如果甚至根本不需要的话。
问题
在这个问题中,我们希望与不同时区的某个人通知特定日期(日,月,年)。第一个实现天真地使用本地时间,这导致错误的结果。第二种实现使用 UTC 日期来避免不需要它们的时区。
使用错误结果的朴素方法
function formatDate(dayOfWeek, day, month, year) {
var daysOfWeek = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
return daysOfWeek[dayOfWeek] + " " + months[month] + " " + day + " " + year;
}
//Foo lives in a country with timezone GMT + 1
var birthday = new Date(2000,0,1);
console.log("Foo was born on: " + formatDate(`birthday.getDay()`, `birthday.getDate()`,
`birthday.getMonth()`, `birthday.getFullYear()`));
sendToBar(`birthday.getTime()`);
样本输出:
Foo was born on: Sat Jan 1 2000
//Meanwhile somewhere else...
//Bar lives in a country with timezone GMT - 1
var birthday = new Date(`receiveFromFoo()`);
console.log("Foo was born on: " + formatDate(`birthday.getDay()`, `birthday.getDate()`,
`birthday.getMonth()`, `birthday.getFullYear()`));
样品输出:
Foo was born on: Fri Dec 31 1999
因此,Bar 总是相信 Foo 出生于 1999 年的最后一天。
正确的做法
function formatDate(dayOfWeek, day, month, year) {
var daysOfWeek = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
return daysOfWeek[dayOfWeek] + " " + months[month] + " " + day + " " + year;
}
//Foo lives in a country with timezone GMT + 1
var birthday = new Date(Date.UTC(2000,0,1));
console.log("Foo was born on: " + formatDate(`birthday.getUTCDay()`, `birthday.getUTCDate()`,
`birthday.getUTCMonth()`, `birthday.getUTCFullYear()`));
sendToBar(`birthday.getTime()`);
样品输出:
Foo was born on: Sat Jan 1 2000
//Meanwhile somewhere else...
//Bar lives in a country with timezone GMT - 1
var birthday = new Date(`receiveFromFoo()`);
console.log("Foo was born on: " + formatDate(`birthday.getUTCDay()`, `birthday.getUTCDate()`,
`birthday.getUTCMonth()`, `birthday.getUTCFullYear()`));
样品输出:
Foo was born on: Sat Jan 1 2000
从 UTC 创建日期
如果想要基于 UTC 或 GMT 创建 Date
对象,可以使用 Date.UTC(...)
方法。它使用与最长的 Date
构造函数相同的参数。此方法将返回一个数字,表示自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的时间。
console.log(Date.UTC(2000,0,31,12));
样本输出:
949320000000
var utcDate = new Date(Date.UTC(2000,0,31,12));
console.log(utcDate);
样品输出:
Mon Jan 31 2000 13:00:00 GMT+0100 (West-Europa (standaardtijd))
不出所料,UTC 时间和本地时间之间的差异实际上是时区偏移转换为毫秒。
var utcDate = new Date(Date.UTC(2000,0,31,12));
var localDate = new Date(2000,0,31,12);
console.log(localDate - utcDate === `utcDate.getTimezoneOffset()` * 60 * 1000);
样品输出:
true
更改 Date 对象
所有 Date
对象修饰符,例如 setDate(...)
和 setFullYear(...)
都具有等效的 UTC 时间而不是本地时间的参数。
var date = new Date();
date.setUTCFullYear(2000,0,31);
date.setUTCHours(12,0,0,0);
console.log(date);
样品输出:
Mon Jan 31 2000 13:00:00 GMT+0100 (West-Europa (standaardtijd))
其他 UTC 特定的修饰符是 .setUTCMonth()
,.setUTCDate()
(当月的某天),.setUTCMinutes()
,.setUTCSeconds()
和 .setUTCMilliseconds()
。
使用 getTime()
和 setTime()避免歧义
如果需要上述方法来区分日期中的歧义,通常更容易将日期作为自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的时间进行通信。此单个数字表示单个时间点,并且可以在必要时转换为本地时间。
var date = new Date(Date.UTC(2000,0,31,12));
var timestamp = date.getTime();
//Alternatively
var timestamp2 = Date.UTC(2000,0,31,12);
console.log(timestamp === timestamp2);
样品输出:
true
//And when constructing a date from it elsewhere...
var otherDate = new Date(timestamp);
//Represented as an universal date
console.log(`otherDate.toUTCString()`);
//Represented as a local date
console.log(otherDate);
样本输出:
Mon, 31 Jan 2000 12:00:00 GMT Mon Jan 31 2000 13:00:00 GMT+0100 (West-Europa (standaardtijd))