如何在JavaScript中获取UTC时间戳?

233

在编写Web应用程序时,将(服务器端)所有日期时间作为UTC时间戳存储在数据库中是有意义的。

当我注意到JavaScript本地无法进行太多时区操作时,我感到惊讶。

我稍微扩展了Date对象。这个函数有意义吗?基本上,每次我发送任何东西到服务器时,它都会是使用这个函数格式化的时间戳...

你看到了什么主要问题吗?或者从不同的角度提供一个解决方案?

Date.prototype.getUTCTime = function(){ 
  return new Date(
    this.getUTCFullYear(),
    this.getUTCMonth(),
    this.getUTCDate(),
    this.getUTCHours(),
    this.getUTCMinutes(), 
    this.getUTCSeconds()
  ).getTime(); 
}

对我来说这似乎有些复杂。而且我也不确定性能如何。


我知道这是一个有点老的问题,但是尽量不要扩展像日期对象这样的本地对象。我点赞是因为我喜欢这个问题本身。 - trysis
Date.parse(new Date().toUTCString()) - Sagi
66
这是一个老问题,今天在我的feed中出现了,但它充满了错误信息。时间戳始终为UTC时间。new Date().toString() 将显示当前时区的时间表示形式,new Date().toUTCString() 将显示UTC时间表示形式,但 new Date().getTime() 始终是UTC时间,因为Unix时间被定义为“Unix时间(也称为POSIX时间或时代时间)是一种描述时间瞬间的系统,它被定义为自协调世界时(UTC)1970年1月1日星期四00:00:00以来经过的秒数,不包括闰秒。” - Amadan
16个回答

206
  1. 用那种方式构建的日期使用本地时区,从而使得构建的日期不正确。要设置特定日期对象的时区是从包括时区的日期字符串构造它。(我在旧版Android浏览器中无法成功实现该操作。)

  2. 注意getTime()返回毫秒,而不是秒。

对于UTC/Unix时间戳,以下代码应该足够:

Math.floor((new Date()).getTime() / 1000)

它将考虑当前时区偏移并包括在结果中。如需字符串表示,请使用David Ellis的答案。

澄清一下:

new Date(Y, M, D, h, m, s)

输入被视为本地时间。如果传入UTC时间,结果将不同。观察(我现在处于GMT +02:00,并且是07:50):

> var d1 = new Date();
> d1.toUTCString();
"Sun, 18 Mar 2012 05:50:34 GMT" // two hours less than my local time
> Math.floor(d1.getTime()/ 1000)
1332049834 

> var d2 = new Date( d1.getUTCFullYear(), d1.getUTCMonth(), d1.getUTCDate(), d1.getUTCHours(), d1.getUTCMinutes(), d1.getUTCSeconds() );
> d2.toUTCString();
"Sun, 18 Mar 2012 03:50:34 GMT" // four hours less than my local time, and two hours less than the original time - because my GMT+2 input was interpreted as GMT+0!
> Math.floor(d2.getTime()/ 1000)
1332042634

注意,getUTCDate() 不能替换 getUTCDay()。这是因为 getUTCDate() 返回 月份中的日期,而 getUTCDay() 返回 星期中的第几天


1
  1. 我没有构造一个日期...我添加了一个在this上工作的原型函数。
  2. 很好的观点,我应该做Math.floor / 1000 -- 但是我仍然需要那个函数才能获得现有日期对象的UTC时间戳...对吗?
- Merc
@Merc:1)你正在调用 new Date(),它会从你的 UTC 输入创建一个新的日期,但是将其视为本地日期/时间。2)是的,在这种情况下,你应该使用 Math.floor(this.getTime() / 1000) - DCoder
回答在这里,因为我需要更新代码...这是为了获取现有日期的UTC Unix时间戳:function (){ return Math.floor( new Date( this.getUTCFullYear(), this.getUTCMonth(), this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds() ).getTime() / 1000); }这意味着我可以这样做:var n = new Date(2008,10,10) ... ... n.getUTCTime(); (这将与n.getUTCTime()不同) - Merc
1
谢谢兄弟,它正在正常工作。 Math.floor((new Date()).getTime() / 1000) - Manoj Patel
我需要UTC小时和分钟,d1.getUTCHours(), d1.getUTCMinutes()帮助了我。 - Timo

125

以传统格式获取UTC时间的最简单方法如下:

> new Date().toISOString()
"2016-06-03T23:15:33.008Z"

如果你需要 EPOC 时间戳,请将日期传递给 Date.parse 方法

> Date.parse(new Date)
1641241000000
> Date.parse('2022-01-03T20:18:05.833Z')
1641241085833

或者你可以使用 + 将日期转换为整数。

> +new Date 
1641921156671

以秒为单位的EPOC时间戳。

> parseInt(Date.parse('2022-01-03T20:18:05.833Z') / 1000)
1641241085
> parseInt(new Date / 1000)
1643302523

19
这是正确答案。许多其他答案给出了“通用时间字符串”,但并未给出当前的“协调世界时”。我不明白为什么这里的一切都这么复杂。 - speciesUnknown
1
谢谢@gburton。感谢您看到真理的简单方式。 :) - Tahsin Turkoz
1
我使用这个代码,连同“.split('T')[0]”一起进行简单的基于YYYY-MM-DD日期的比较。 - Sean O
7
这提供了一个UTC时间字符串,但OP要求一个UTC时间戳(纪元)。 - Jordi Nebot
4
这是误导性的,它并没有提供UTC时间戳。 - GavinBelson
显示剩余3条评论

74
你还可以使用 getTimezoneOffset 和 getTime 来实现。

x = new Date()
var UTCseconds = (x.getTime() + x.getTimezoneOffset()*60*1000)/1000;

console.log("UTCseconds", UTCseconds)


7
谢谢,这在互联网上找不到! - Theofanis Pantelides
我测试了以下代码:var tt = new Date('Thu Jan 01 1970 08:00:00 GMT+0800 (China Standard Time)'); (tt.getTime() - tt.getTimezoneOffset()*60*1000)/1000。看起来 tt.getTime() - tt.getTimezoneOffset() 对于 GMT+0800 是正确的。 - zangw
2
这个更好一些:var UTCseconds = (Math.floor(x.getTime()/1000) + x.getTimezoneOffset()*60) - StefansArya
看起来这个代码写得不行。看起来你必须将带有时区的时间字符串传递到 new Date() 中,这有点违背了在 js 中尝试做的事情的初衷。 - claudekennilol
2
这是完全错误的,分配给 UTCseconds 的值不是 UTC 秒。一个日期的时间值 UTC,通过任何方法改变它意味着它代表了不同的时间点。 - RobG

17

我认为 JavaScript 中的 Date 值比 C# 中的 DateTime 对象好得多。C# 的 DateTime 对象有一个 Kind 属性,但没有严格的底层时区,如果你在两个非 UTC 和非本地时间之间进行转换,则很难跟踪时区转换。在 JavaScript 中,所有的 Date 值都有一个基础的 UTC 值,不管你进行了什么偏移或时区转换,这个值都是已知的。我对 Date 对象最大的抱怨是浏览器实现者选择包含了大量未定义的行为,这会让那些通过试错而非阅读规范来处理 JavaScript 中的日期的人感到困惑。使用像 iso8601.js 这样的工具可以通过定义 Date 对象的单一实现来解决这种不同的行为。

默认情况下,规范允许您使用扩展的 ISO 8601 日期格式创建日期,例如:

var someDate = new Date('2010-12-12T12:00Z');

你可以通过以下方式推断出精确的UTC时间。

当你想将日期值传回服务器时,应该调用:

someDate.toISOString();

或者如果您更喜欢使用毫秒级时间戳(距离1970年1月1日UTC的毫秒数)进行操作

someDate.getTime();

ISO 8601是一种标准。如果包含日期偏移量,您不可能对日期字符串的含义感到困惑。作为开发人员,这意味着您永远不必自己处理本地时间转换。 本地时间值纯粹是为用户提供方便而存在的,日期值默认以其本地时间显示。 所有本地时间操作都允许您向用户显示合理的内容,并将字符串从用户输入转换。 尽早转换为UTC是一个好习惯,而js Date对象使此过程相当简单。

不足之处在于,我没有意识到(如果有的话),没有很多范围可以强制客户机的时区或语言环境,这可能会对网站特定设置造成麻烦,但我想背后的原因是这是一个用户配置,不应该被触及。

因此,简言之,没有太多关于时区操作的本地支持的原因是您根本不想这样做。


13

如果您想要一个简短的代码,可以使用JavaScript创建UTC Unix时间戳

var currentUnixTimestap = ~~(+new Date() / 1000);

这将考虑系统的时区。它基本上是自纪元以来经过的秒数。

其工作原理:

  • 创建日期对象:new Date()
  • 通过在对象创建之前添加一元+将其转换为时间戳整数+new Date()
  • 将毫秒转换为秒:+new Date() / 1000
  • 使用双波浪线将值四舍五入为整数:~~(+new Date())

13
不要使用这个。根据当前的ecma规范,位运算(比如按位取反符号 ~)仅适用于32位有符号整数。也就是说,在2038年1月19日后,时间戳值将超过32位有符号整数的最大值,因此这个按位取反的操作将会失效。https://jsfiddle.net/phb20ymb/ - Sharky
2
@Sharky 我使用这个是因为现在还没有到2038年! - jeffbRTC
1
我承诺在2038年1月20日来给这个答案点踩。 - Mikko Ohtamaa
你好,来自2023年的问候,回声有人吗? - user15023244

13

通常情况下,客户端不需要进行太多的"时区操作"。作为一项规则,我尝试使用以 ticks 或"自1970年1月1日午夜以来的毫秒数"形式存储和处理UTC日期。这样可以简化存储、排序、计算偏移量的过程,最重要的是,让你摆脱了"夏令时"调整所带来的麻烦。以下是我使用的一小段JavaScript代码:

获取当前UTC时间:

function getCurrentTimeUTC()
{
    //RETURN:
    //      = number of milliseconds between current UTC time and midnight of January 1, 1970
    var tmLoc = new Date();
    //The offset is in minutes -- convert it to ms
    return tmLoc.getTime() + tmLoc.getTimezoneOffset() * 60000;
}

那么你通常需要的是为最终用户以他们的本地时区和格式格式化日期/时间。以下代码会处理客户端计算机上所有日期和时间格式的复杂性:

function formatDateTimeFromTicks(nTicks)
{
    //'nTicks' = number of milliseconds since midnight of January 1, 1970
    //RETURN:
    //      = Formatted date/time
    return new Date(nTicks).toLocaleString();
}

function formatDateFromTicks(nTicks)
{
    //'nTicks' = number of milliseconds since midnight of January 1, 1970
    //RETURN:
    //      = Formatted date
    return new Date(nTicks).toLocaleDateString();
}

function formatTimeFromTicks(nTicks)
{
    //'nTicks' = number of milliseconds since midnight of January 1, 1970
    //RETURN:
    //      = Formatted time
    return new Date(nTicks).toLocaleTimeString();
}

因此,以下示例:

var ticks = getCurrentTimeUTC();  //Or get it from the server

var __s = "ticks=" + ticks + 
    ", DateTime=" + formatDateTimeFromTicks(ticks) +
    ", Date=" + formatDateFromTicks(ticks) +
    ", Time=" + formatTimeFromTicks(ticks);

document.write("<span>" + __s + "</span>");
返回的结果如下(针对我的美国英语区域设置):

ticks=1409103400661,DateTime=2014年8月26日下午6:36:40,Date=2014年8月26日,Time=下午6:36:40


1
通过在您的 getCurrentTimeUTC 函数中添加 getTimezoneOffset 值,实际上返回的是不同的时间点。getTime 的结果已经是 UTC 时间。 - Matt Johnson-Pint
1
@MattJohnson:那是不正确的。 tmLoc.getTime() 的结果是相对于本地时间的偏移量。如果您可以访问任何运行JavaScript的内容,那很容易检查。 - ahmd0
2
抱歉,但那不是真的。请参阅MDN参考文档。您还可以在ECMAScript规范中查看此内容。§15.9.3.3描述了getTime,指向§15.9.5中定义的“时间值”,这是一个原始值(PrimitiveValue),并在§15.9.3.3中明确设定为UTC。 - Matt Johnson-Pint
2
既然您是通过 new Date() 获取 tmLoc,那么它们是一样的。时区将影响 tmLoc.toString() 和类似项的字符串输出,但不会影响 tmLoc.getTime()。这总是自1970年1月1日午夜以来UTC的毫秒数。 - Matt Johnson-Pint
1
@StefansArya://偏移量以分钟为单位--将其转换为毫秒 - ahmd0
显示剩余4条评论

7

由于new Date().toUTCString()返回的字符串类似于"Wed, 11 Oct 2017 09:24:41 GMT",因此您可以切割最后3个字符并将切割后的字符串传递给new Date()

new Date()
// Wed Oct 11 2017 11:34:33 GMT+0200 (CEST)

new Date(new Date().toUTCString().slice(0, -3))
// Wed Oct 11 2017 09:34:33 GMT+0200 (CEST)

7

我认为这是一个更好的解决方案

// UTC milliseconds
new Date(Date.now()+(new Date().getTimezoneOffset()*60000)).getTime()

// UTC seconds
new Date(Date.now()+(new Date().getTimezoneOffset()*60000)).getTime()/1000|0

2
另一个错误的答案,getTime返回一个UTC偏移量,添加本地时区偏移量会完全搞砸它。ECMAScript偏移量对于西部是+ve,对于东部是-ve,因此应从UTC中减去它们以获取本地时间。但由于时间值最初是UTC,因此添加它实际上将其从UTC向相反方向移动到本地偏移量。 - RobG

6

我使用以下内容:

Date.prototype.getUTCTime = function(){ 
  return this.getTime()-(this.getTimezoneOffset()*60000); 
};

一旦定义了这个方法,你可以执行以下操作:

var utcTime = new Date().getUTCTime();

最干净的解决方案。谢谢! - avalanche1
但是这并不是一个干净的解决方案来发送日期,因为时间戳始终是UTC。对我而言,发送日期的最佳解决方案是使用字符串表示形式,例如“dd/MM/yyyy HH:mm:ss”,然后在服务器端使用服务器的默认时区解析它以获取UTC时间戳或其他内容。请参见此答案 - jlbofh
2
解析字符串 - 你把那叫做干净?呃 - avalanche1
请注意,有方法可以按照ISO规范生成日期字符串格式。该方法是toISOString()。您可以使用类似以下代码在Java中干净地解析它:DateTime dt = new DateTime ("2018-07-15T02:36:00+02:00"); - jlbofh
1
另一个错误的答案,this.getTime() 返回一个UTC偏移量,减去本地时区偏移量会使其变成本地时间,而不是UTC,因此 getUTCTime 返回的是本地偏移量,而不是UTC。 - RobG
我同意... 4年前 ;)... 正确的方法名应该是'getLocalTimestamp'... 这个方法没用。 - jlbofh

4
我需要澄清的是,new Date().getTime() 确实返回一个UTC值,因此这是一种非常有用的方式来存储和管理日期,同时不用考虑本地化时间问题。
换句话说,不要费心使用所有UTC的JavaScript函数。只需使用Date.getTime()。
更多解释信息在这里: 如果从两个不同的时区运行JavaScript "(new Date()).getTime()"。

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