如何将日期转换为UTC?

842
假设您的网站用户输入了一个日期范围。
2009-1-1 to 2009-1-3

你需要将这个日期发送到服务器进行处理,但是服务器希望所有的日期和时间都是以协调世界时(UTC)为准。

现在假设用户在阿拉斯加。由于他们所处的时区与UTC相差很大,因此日期范围需要转换为如下形式:

2009-1-1T8:00:00 to 2009-1-4T7:59:59

如何使用 JavaScript Date 对象将第一个“localized”日期范围转换为服务器可以理解的内容?


14
我重新翻译了这句话并且使其更加通俗易懂,但是没有改变原意:“我将此提出来是因为它是我在谷歌中搜索到的排名最高的结果,并且较新版本的浏览器已经内置了对UTC日期字符串的支持。” - jcomeau_ictx
6
我更新了被接受的答案,以突出新的ECMAScript 5 toISOString()方法。请参见https://dev59.com/inNA5IYBdhLWcg3wdtv5#11957822。 - dthrasher
9
所以在2015年我必须折腾字符串化和解析日期?荒谬! - Toolkit
2
当然了。你永远不能依赖别人为你做工作 :-P 至少在世界停止使用时区并开始统一日期和时间之前是这样的。 - Erenor Paz
7
"Stardates",如果可能的话。 - Michael Daw
显示剩余2条评论
35个回答

728

简单而愚蠢

var date = new Date();
var now_utc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(),
                date.getUTCDate(), date.getUTCHours(),
                date.getUTCMinutes(), date.getUTCSeconds());

console.log(new Date(now_utc));
console.log(date.toISOString());


107
我喜欢你的想法并使用了我已经用了很多次的方法。function convertDateToUTC(date) { return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()); }这段代码的作用是将输入的日期转换成UTC时间。 - Tim
33
我想到的获取UTC日期和时间的最短代码是通过去掉时区:new Date(new Date().toUTCString().substr(0, 25)) - joelvh
18
请注意,getUTCMonth() 返回值为 0 到 11。因此,如果您需要以数字而不是字符串形式获得月份,需要将该值加1。 - Talvi Watia
38
这是无意义的。新的日期将具有不同于实际想要的值。只需使用 now.toUTCString() 而不是(错误的)now_utc.toString() 即可。 - Bergi
39
我不会使用这个方法 - 使用 new Date() 会获取浏览器的时区。在 Chrome 29 和 IE10 中,日期和时间看起来是正确的,但时区设置为浏览器的时区,这可能会引起问题... - Sean
显示剩余15条评论

582

toISOString()方法返回一个字符串,格式为简化扩展的ISO格式(ISO 8601),其长度始终为24或27个字符(YYYY-MM-DDTHH:mm:ss.sssZ±YYYYYY-MM-DDTHH:mm:ss.sssZ),后者表示日期前有符号。时区始终是零UTC偏移,由后缀"Z"表示。

来源: MDN web docs

您需要使用.toISOString()方法创建所需的格式。对于不支持此方法的旧版浏览器(ie8及以下版本),可以在此处找到补丁程序:

这将使您能够完成所需操作:

var isoDateString = new Date().toISOString();
console.log(isoDateString);

对于时区处理,moment.js和moment.js timezone是非常宝贵的工具......特别是在客户端和服务器端javascript之间导航时区方面。


176
实际上,这将把日期对象转换为字符串,之后将无法对其执行其他日期操作。 - orszaczky
6
@TheRebel,所给的用例是他需要向服务器发送一个格式化字符串。 - Will Stern
52
@Will,你说得完全正确,但是-就像我想象的大多数观众一样-我基于标题来到这里,搜索普通JS日期到UTC的转换,所以我认为在这里提到它很有用 :) - orszaczky
12
使用此方法时要谨慎!它不会创建一个UTC日期,而是将现有的日期数据原封不动地格式化为UTC格式,并赋予其“Z”时区。这通常是错误的99%!在使用此方法之前,必须将日期转换为GMT时区! - user1944491
14
根据 MDN 文档,我认为这不正确。toISOString 正确地转换为 UTC。 [toISOString] 以简化的扩展 ISO 格式返回一个字符串... 时区始终是零 UTC 偏移量。此外,在示例中,调用 toISOString 时已经考虑了偏移量。 - FFF
显示剩余8条评论

260

这是我的方法:

var now = new Date();
var utc = new Date(now.getTime() + now.getTimezoneOffset() * 60000);

得到的utc对象实际上不是一个UTC日期,而是本地日期调整后与UTC时间匹配(请参见评论)。 但是,在实践中它能够胜任工作。


更新:此答案是在调用utc.toString()utc.toLocaleString()等时快速获取UTC日期的一种简单方法。 不过,现代浏览器有更好的解决方案,因此我应该努力改进答案。 基本上,now.toISOString()(IE 9+)是您要使用的内容。


24
添加 60000 * Date.getTimezoneOffset() 是不正确的!首先,您必须将所有日期/时间视为已经具有针对显示目的的时区修饰符的 UTC。浏览器可能会有所不同,但是 Date.getTime() 返回自 1970-01-01 以来的毫秒数。如果您使用此数字创建一个新的日期,例如 new Date(Date.getTime()); 它将是 UTC,但是当您显示它(例如通过 Chrome 开发工具控制台)时,它将出现为您的本地时区。 - Aaron Hoffman
19
在我的浏览器中,这将创建一个不是UTC的DateTime。然而,在我的浏览器中显示时,它会显示为本地时区的DateTime,如果忽略时区信息,则显示正确的UTC时间。 - Aaron Hoffman
getTime() 返回毫秒级 Unix 时间戳。它是与 GMT 时间相关的时钟。您不需要使用当前时区来校正时间。时间戳在地球时间方面具有普遍意义。由于服务器将使用 UTC 时间,因此最好让 Javascript Data 对象自己执行时区转换。例如:var usertime = new Date(serverUnixEpochTime*1000) -> 进入 JavaScript 代码。serverUnixEpochTime = usertime->getTime()/1000 -> 进入服务器。 - 0xC0DEGURU
5
这个答案展示了另一种常见的“时代转换”实现方式,但在孤立状态下是危险的,因为它可能在类似夏令时(DST)转换这样的边缘情况下失效。不建议使用。 - Matt Johnson-Pint
1
Matt Johnson是正确的。这里有一个具体的例子,它由于夏令时而失败。在澳大利亚新南威尔士州,夏令时开始于2016年10月2日02:00:00(以下内容只有当您的语言环境为新南威尔士州时才会显示问题)console.log( new Date(date.getTime() + date.getTimezoneOffset() * 60000) ); => Sat Oct 01 2016 15:00:00 GMT+1000 (AEST)``` 这是不正确的。它应该显示时间为16:00:00(即凌晨3点-11小时)。 我的答案或DrunkCoder的答案给出了正确的结果。 - CMcClymont
显示剩余4条评论

39

不改变日期/时间的情况下转换为ISO格式

var now = new Date(); // Fri Feb 20 2015 19:29:31 GMT+0530 (India Standard Time) 
var isoDate = new Date(now.getTime() - now.getTimezoneOffset() * 60000).toISOString();
//OUTPUT : 2015-02-20T19:29:31.238Z

将日期/时间更改后转换为ISO格式(日期/时间将被更改)

isoDate = new Date(now).toISOString();
//OUTPUT : 2015-02-20T13:59:31.238Z 

Fiddle链接


这有点像伪造UTC?我改变了本地日期,成功向服务器提交了我在PC时钟上实际看到的日期和时间。哇。无论如何,这比字符串化和解析要好。 - Toolkit
".toISOString() 很简单明了,从中获取日期需要额外的步骤(isoDate 不是一个函数)。" - RollerCosta
你不需要减去偏移量,而是需要加上它吗?请参考https://dev59.com/inNA5IYBdhLWcg3wdtv5#11964609。 - Asclepius
如果当前时区偏移量是正的,则应该减去它(在我们的情况下,IST为+5:30),否则添加。 - RollerCosta
2
@RollerCosta,请在您的回答中提到减去/加上 now.getTimezoneOffset() 取决于用户(浏览器)的时区是在 UTC 之前还是之后。 - Iman Mahmoudinasab
显示剩余6条评论

31
另一种将时间转换为UTC并保持其为日期对象的方法: (通过从格式化字符串末尾删除“ GMT”部分,然后将其放回到Date构造函数中实现)

const now = new Date();
const now_utc = new Date(now.toUTCString().slice(0, -4));
console.log(now_utc.toString()); // ignore the timezone

我需要这样做来与日期时间选择库进行接口。但一般情况下,以这种方式处理日期不是好主意。

用户通常希望在本地时间中使用日期时间,因此您可以更新服务器端代码以正确解析带有偏移量的日期时间字符串,然后转换为UTC(最佳选项),或者您可以在客户端将其转换为UTC字符串后发送给服务器(如Will Stern的答案)。


27
Date.prototype.toUTCArray= function(){
    var D= this;
    return [D.getUTCFullYear(), D.getUTCMonth(), D.getUTCDate(), D.getUTCHours(),
    D.getUTCMinutes(), D.getUTCSeconds()];
}

Date.prototype.toISO= function(){
    var tem, A= this.toUTCArray(), i= 0;
    A[1]+= 1;
    while(i++<7){
        tem= A[i];
        if(tem<10) A[i]= '0'+tem;
    }
    return A.splice(0, 3).join('-')+'T'+A.join(':');    
}

这个很好用。我只需要将源日期中的“-”替换为“/”,以创建JavaScript日期,然后我就可以调用你的toISO()函数来获得正确的输出了。 - dthrasher
这个很好用。你也可以将结果输入到jQuery $.parseDate(...)中,以获取一个已转换为UTC的日期对象。 - Brian Ellis

24

我的解决方案可以让日期保持不变,无论客户端设置了哪个时区。也许有人会发现它很有用。

我的使用情况:

我正在创建一个任务应用程序,在其中设置任务的日期。无论你在哪个时区,这个日期都应该保持不变。

例如,你想在6月25日早上8点给你的朋友打电话。

你在中国的时候5天前(6月20日)创建了这个任务。

然后,在同一天,你飞到纽约待几天。

然后,在6月25日,当你仍然在纽约的时候,你早上7点半醒来(这意味着你应该在30分钟内收到任务通知,即使在你创建任务时所处的中国已经是下午1:30了)

因此,这个任务忽略了时区。这意味着“我想在任何时区都在早上8点做这件事”。

我的做法是“假设你始终在伦敦时区(UTC)”。

这意味着 - 当用户在其本地时区选择日期时,我将此日期转换为UTC中相同的日期。也就是说,你在中国选择了早上8点,但我将其转换为UTC中的早上8点。

然后 - 下次打开应用程序时 - 我读取保存在UTC中的日期并将其转换为你当前时区中相同的日期 - 例如,我将UTC中的早上8点转换为纽约时区中的早上8点。

这个解决方案意味着日期的含义可能因设置它和读取它的地方而异,但它以一种“感觉”像你始终处于同一时区的方式保持不变。

让我们写一些代码:

首先 - 我们有两个主要函数,用于忽略时区从/到UTC的转换:

export function convertLocalDateToUTCIgnoringTimezone(date: Date) {
  const timestamp = Date.UTC(
    date.getFullYear(),
    date.getMonth(),
    date.getDate(),
    date.getHours(),
    date.getMinutes(),
    date.getSeconds(),
    date.getMilliseconds(),
  );

  return new Date(timestamp);
}

export function convertUTCToLocalDateIgnoringTimezone(utcDate: Date) {
  return new Date(
    utcDate.getUTCFullYear(),
    utcDate.getUTCMonth(),
    utcDate.getUTCDate(),
    utcDate.getUTCHours(),
    utcDate.getUTCMinutes(),
    utcDate.getUTCSeconds(),
    utcDate.getUTCMilliseconds(),
  );
}

然后,我保存/读取此日期的方式如下:

function saveTaskDate(localDate: Date) {
  // I convert your local calendar date so it looks like you've picked it being in UTC somewhere around London
  const utcDate = convertLocalDateToUTCIgnoringTimezone(localDate);
  api.saveTaskDate(utcDate);
}

function readTaskDate(taskUtcDate: Date) {
  // I convert this UTC date to 'look in your local timezone' as if you were now in UTC somewhere around london
  const localDateWithSameDayAsUTC = convertUTCToLocalDateIgnoringTimezone(taskUtcDate);

  // this date will have the same calendar day as the one you've picked previously
  // no matter where you were saving it and where you are now
}

22

浏览器可能不同,您还应该记住不要相信客户端生成的任何信息。话虽如此,下面的语句对我有效(在Mac OS X 10.8.2上的Google Chrome v24)。

var utcDate = new Date(new Date().getTime());


编辑:“这与仅使用new Date()有何不同?”请参见此处:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

  • 如果未提供任何参数,则构造函数根据系统设置创建JavaScript日期对象以获取当前日期和时间。
  • 注意:当作为带有多个参数的构造函数调用Date时,指定的参数表示本地时间。如果需要UTC,请使用带有相同参数的new Date(Date.UTC(...))。(注意:Date.UTC()返回自1970-01-01 00:00:00 UTC以来的毫秒数)

像之前的答案所述,添加60000 * Date.getTimezoneOffset()是不正确的。首先,您必须将所有日期/时间视为已经具有时区修饰符的UTC,以便显示目的。

同样,浏览器可能不同,然而,Date.getTime()返回自1970-01-01 UTC/GMT以来的毫秒数。如果您像我上面那样使用这个数字创建一个新的日期,它将是UTC/GMT。但是,如果您通过调用.toString()显示它,它将似乎是在您的本地时区,因为.toString()使用您的本地时区,而不是调用它的日期对象的时区。

我还发现,如果您在日期上调用.getTimezoneOffset(),它将返回您的本地时区,而不是调用它的日期对象的时区(我无法验证这是否标准)。

在我的浏览器中,添加 60000 * Date.getTimezoneOffset() 会创建一个不是UTC的DateTime。但是,当在浏览器中显示时(例如:.toString()),它会显示一个在我的本地时区中正确的UTC时间,如果忽略时区信息。


14
我刚刚在 Firefox 和 Chrome 上运行了这段代码,但它似乎不起作用:结果与 new Date() 的输出完全相同,无论是时间戳还是时区都没有改变。请问您需要的是什么样的翻译? - Gras Double
4
这是因为时间戳与时区无关。new Date().getTime() 始终返回一个与时区无关的时间戳。在你尝试将其格式化为除自 Unix 纪元以来毫秒数之外的其他格式之前,它没有相关联的时间戳。 - frontendbeauty
10
据我所知,new Date(new Date().getTime()) 返回的值与 new Date() 返回的值完全相同。您能解释一下您的答案在哪些方面提供了与 new Date() 不同的值吗? - Kirk Woll
我正在将这个值发布到我的服务器 new Date("5/19/2014").getTime()。Date构造函数创建了一个带有+7偏移量的日期。在服务器上(C#),我将发布的值作为毫秒数添加到Unix纪元new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(1401087600000)。结果是5/19/2014 7:00:00 AM。因此,似乎getTime()给出了包括我的UTC偏移量在内的毫秒数。 - xr280xr
1
有很多评论抱怨new Date(new Date().getTime())无法正常工作。我可以确认new Date(Date.UTC(2019, 8, 27, 0, 0, 0))确实会产生UTC时间。如果你没有使用Date.UTC(...),你将得到在你所在时区的UTC偏移日期。 - Alex Barker
感谢@AlexBarker,这个答案�时会被踩但没有任何评论。我一直无法确定�因。🤷 - Aaron Hoffman

18
var myDate = new Date(); // Set this to your date in whichever timezone.
var utcDate = myDate.toUTCString();

1
日期对象需要真正设置为一个日期。上面只是一个示例。 - James Skidmore
9
现在它返回的是"Thu, 04 Jun 2009 04:10:56 GMT",这不是OP要求的ISO格式。 - nickf
8
这将把它转换为一个字符串,而不是日期。 - Anthony
2
不,实际上它应该是一个字符串表示的日期,根据原帖。 - jcomeau_ictx
4
转换为UTC后,它以字符串格式返回,那么如何访问getMonth()、getDate()等方法? - Sandeep sandy
有关如何解决这个问题的任何更新吗? - undefined

10
date = '2012-07-28'; stringdate = new Date(date).toISOString();

应该能在大多数更新的浏览器中运行。在 Firefox 6.0 上返回 2012-07-28T00:00:00.000Z


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接