2010-05-05 113 views
80

在JS应用程序中,我从服务器(Ajax)接收时间戳(eq。1270544790922)。如何忽略用户的时区并强制Date()使用特定时区

此基础上戳我创建使用Date对象:

var _date = new Date(); 
_date.setTime(1270544790922); 

现在,在当前用户区域设置时区_date解码时间戳。我不想那样。

我希望_ date将此时间戳转换为欧洲赫尔辛基市的当前时间(不考虑当前用户的时区)。

我该怎么做?

+0

我知道赫尔辛基的时区偏移量在冬季为+2,在夏令时为+3。但谁知道什么时候是DST?只有一些在JS – warpech 2010-05-05 09:09:15

+0

中不可用的语言环境机制有可能,但不使用Javascript的本地方法,因为JavaScript没有方法来确定其他时区的时区转换历史记录,而不是用户系统的当前时区(并且它是通过浏览器至少当我们进入80年代日期时)。但这种方式是可能的:http://stackoverflow.com/a/12814213/1691517我认为我的答案给你正确的结果。 – 2012-10-10 08:06:33

+0

http://www.w3schools.com/jsref/jsref_setutcmilliseconds.asp – radpin 2015-09-14 17:30:31

回答

56

Date对象的基础值实际上是UTC。为了证明这一点,请注意,如果您输入new Date(0),您会看到类似于:Wed Dec 31 1969 16:00:00 GMT-0800 (PST)。格林尼治标准时将0视为0,但.toString()方法显示当地时间。

大注意,UTC代表通用时间码。目前在2个不同地方的当前时间与UTC相同,但输出格式可能不同。

我们所需要的就是一些格式

var _date = new Date(1270544790922); 
// outputs > "Tue Apr 06 2010 02:06:30 GMT-0700 (PDT)", for me 
_date.toLocaleString('fi-FI', { timeZone: 'Europe/Helsinki' }); 
// outputs > "6.4.2010 klo 12.06.30" 
_date.toLocaleString('en-US', { timeZone: 'Europe/Helsinki' }); 
// outputs > "4/6/2010, 12:06:30 PM" 

这工作,但....你真的不能使用任何其他日期的方法达到你的目的,因为它们所描述的用户的时区。你想要的是一个与赫尔辛基时区有关的日期对象。此时你的选择是使用一些第三方库(我推荐这个),或者修改日期对象,以便使用它的大部分方法。

选项1 - 第三方像时刻,时区

moment(1270544790922).tz('Europe/Helsinki').format('YYYY-MM-DD HH:mm:ss') 
// outputs > 2010-04-06 12:06:30 
moment(1270544790922).tz('Europe/Helsinki').hour() 
// outputs > 12 

这看起来很多比我们即将下一步要做更优雅。

选项2 - 砍了日期对象

var currentHelsinkiHoursOffset = 2; // sometimes it is 3 
var date = new Date(1270544790922); 
var helsenkiOffset = currentHelsinkiHoursOffset*60*60000; 
var userOffset = _date.getTimezoneOffset()*60000; // [min*60000 = ms] 
var helsenkiTime = new Date(date.getTime()+ helsenkiOffset + userOffset); 
// Outputs > Tue Apr 06 2010 12:06:30 GMT-0700 (PDT) 

它仍然认为它是GMT-0700(PDT),但是如果你不盯着太辛苦你可以误以为,对于一个日期对象,这对你的目的很有用。

我很方便地跳过了一部分。您需要能够定义currentHelsinkiOffset。如果您可以在服务器端使用date.getTimezoneOffset(),或者只是使用一些if语句来描述何时会发生时区更改,那么应该可以解决您的问题。

结论 - 我认为特别为此目的,你应该使用日期库,如moment-timezone

+0

...也可以通过简单地使用来自一个位置的gmt偏移量来完成类似的任务。在这种情况下,你根本不需要JavaScript。 – Parris 2010-05-05 08:50:24

+0

对不起,我的意思是完全相反:)我编辑的问题,也许它现在更清楚 – warpech 2010-05-05 09:01:37

+0

好吧,我改变了我的解决方案。我认为这是你正在寻找的。 – Parris 2010-05-05 16:47:53

15

为了说明毫秒,用户的时区,使用以下命令:

var _userOffset = _date.getTimezoneOffset()*60*1000; // user's offset time 
var _centralOffset = 6*60*60*1000; // 6 for central time - use whatever you need 
_date = new Date(_date.getTime() - _userOffset + _centralOffset); // redefine variable 
+0

要使用中心的固定偏移来替换,我使用了使用CST创建日期为00:00的固定时间的概念,然后使用该日期的getUTCHHours。 – grantwparks 2012-07-14 03:36:16

+0

+1这对我有用。不知道“答案”如何在没有毫秒处理的情况下工作。 – 2013-01-25 11:57:41

+2

@Ehren你不应该添加timezoneOffset去gmt,然后减去中央偏移? – coder 2013-04-11 21:24:07

13

我怀疑,该Answer没有给予正确的结果。在提问者希望将时间戳从服务器转换为当前时间的情况下,不管用户当前的时区在赫尔辛基。

事实上,用户的时区可能是我们无法相信的东西。

如果例如。时间戳是1270544790922,我们有一个功能:

var _date = new Date(); 
_date.setTime(1270544790922); 
var _helsenkiOffset = 2*60*60;//maybe 3 
var _userOffset = _date.getTimezoneOffset()*60*60; 
var _helsenkiTime = new Date(_date.getTime()+_helsenkiOffset+_userOffset); 

当纽约人访问页面,警报(_helsenkiTi​​me)打印:

Tue Apr 06 2010 05:21:02 GMT-0400 (EDT) 

而当Finlander访问页面,警报(_helsenkiTi​​me)打印:

Tue Apr 06 2010 11:55:50 GMT+0300 (EEST) 

因此函数是正确的只有当页面访客在他的电脑上的目标时区(欧洲/赫尔辛基),但却未能在世界的几乎所有其他部分。而且由于服务器时间戳通常是UNIX时间戳,根据定义UTC(自从Unix Epoch(1970年1月1日00:00:00 GMT)以来的秒数),我们无法从时间戳确定DST或非DST。

因此,解决方案是DISREGARD用户的当前时区,并实现某种方式来计算UTC偏移量,无论日期是否在DST中。 Javascript没有本地方法来确定其他时区的DST转换历史记录,而不是当前用户的时区。我们可以最简单地使用服务器端脚本来实现这一点,因为我们可以轻松访问服务器的时区数据库以及所有时区的整个转换历史记录。

但是,如果您无法访问服务器(或任何其他服务器)的时区数据库,并且时间戳采用UTC,则可以通过在JavaScript中对DST规则进行硬编码来获得类似的功能。

为了掩盖日期在1998年岁月 - 2099欧洲/赫尔辛基您可以使用下面的函数(jsfiddled):

function timestampToHellsinki(server_timestamp) { 
    function pad(num) { 
     num = num.toString(); 
     if (num.length == 1) return "0" + num; 
     return num; 
    } 

    var _date = new Date(); 
    _date.setTime(server_timestamp); 

    var _year = _date.getUTCFullYear(); 

    // Return false, if DST rules have been different than nowadays: 
    if (_year<=1998 && _year>2099) return false; 

    // Calculate DST start day, it is the last sunday of March 
    var start_day = (31 - ((((5 * _year)/4) + 4) % 7)); 
    var SUMMER_start = new Date(Date.UTC(_year, 2, start_day, 1, 0, 0)); 

    // Calculate DST end day, it is the last sunday of October 
    var end_day = (31 - ((((5 * _year)/4) + 1) % 7)) 
    var SUMMER_end = new Date(Date.UTC(_year, 9, end_day, 1, 0, 0)); 

    // Check if the time is between SUMMER_start and SUMMER_end 
    // If the time is in summer, the offset is 2 hours 
    // else offset is 3 hours 
    var hellsinkiOffset = 2 * 60 * 60 * 1000; 
    if (_date > SUMMER_start && _date < SUMMER_end) hellsinkiOffset = 
    3 * 60 * 60 * 1000; 

    // Add server timestamp to midnight January 1, 1970 
    // Add Hellsinki offset to that 
    _date.setTime(server_timestamp + hellsinkiOffset); 
    var hellsinkiTime = pad(_date.getUTCDate()) + "." + 
    pad(_date.getUTCMonth()) + "." + _date.getUTCFullYear() + 
    " " + pad(_date.getUTCHours()) + ":" + 
    pad(_date.getUTCMinutes()) + ":" + pad(_date.getUTCSeconds()); 

    return hellsinkiTime; 
} 

用法示例:

var server_timestamp = 1270544790922; 
document.getElementById("time").innerHTML = "The timestamp " + 
server_timestamp + " is in Hellsinki " + 
timestampToHellsinki(server_timestamp); 

server_timestamp = 1349841923 * 1000; 
document.getElementById("time").innerHTML += "<br><br>The timestamp " + 
server_timestamp + " is in Hellsinki " + timestampToHellsinki(server_timestamp); 

var now = new Date(); 
server_timestamp = now.getTime(); 
document.getElementById("time").innerHTML += "<br><br>The timestamp is now " + 
server_timestamp + " and the current local time in Hellsinki is " + 
timestampToHellsinki(server_timestamp);​ 

且不论这种打印以下用户时区:

The timestamp 1270544790922 is in Hellsinki 06.03.2010 12:06:30 

The timestamp 1349841923000 is in Hellsinki 10.09.2012 07:05:23 

The timestamp is now 1349853751034 and the current local time in Hellsinki is 10.09.2012 10:22:31 

当然,如果你可以返回ti mestamp以偏移量(DST或非DST之一)已经添加到服务器上的时间戳的形式,您不必在客户端计算它,并且可以简化该功能。但记得不要使用timezoneOffset(),因为那么你必须处理用户时区,这不是想要的行为。

+2

nb。赫尔辛基只有一个'l'。这个错误实际上减损了这个答案。 – 2017-03-20 14:31:01

+0

@BenMcIntyre这是一个小笑话。或者应该是这样的。 :) – 2017-03-21 23:30:12

0

你可以使用setUTCMilliseconds()

var _date = new Date(); 
_date.setUTCMilliseconds(1270544790922); 
+0

这个答案是错的。 setUTCMilliseconds将指定的毫秒数添加到日期。 – Tibor 2017-03-29 16:11:55

+0

@Tibor:从MozDev:'setUTCMilliseconds()'方法根据通用时间设置指定日期的毫秒数。 [...]如果您指定的参数超出预期范围,则'setUTCMilliseconds()'会相应地尝试更新Date对象中的日期信息。换句话说,在UTC创建一个具有给定的Unix时间戳的Date对象。 – jimasun 2017-03-30 08:57:13

+0

从w3schools:setUTCMilliseconds()方法根据通用时间设置毫秒(从0到999)。请尝试上面的答案并亲自查看。 – Tibor 2017-05-04 20:31:42

10

只是另一种方法

function parseTimestamp(timestampStr) { 
 
    return new Date(new Date(timestampStr).getTime() + (new Date().getTimezoneOffset() * 60 * 1000)); 
 
}; 
 

 
//Sun Jan 01 2017 12:00:00 
 
var timestamp = 1483272000000; 
 
date = parseTimestamp(timestamp); 
 
document.write(date);

干杯!

1

假设你在赫尔辛基时间获得时间戳,我会创建一个日期对象设置为1970年1月1日午夜UTC(忽略浏览器的本地时区设置)。 然后只需添加所需的毫秒数。

var _date \t = new Date(Date.UTC(1970, 0, 1, 0, 0, 0, 0)); 
 
_date.setUTCMilliseconds(1270544790922); 
 

 
alert(_date); //date shown shifted corresponding to local time settings 
 
alert(_date.getUTCFullYear()); //the UTC year value 
 
alert(_date.getUTCMonth());  //the UTC month value 
 
alert(_date.getUTCDate());  //the UTC day of month value 
 
alert(_date.getUTCHours());  //the UTC hour value 
 
alert(_date.getUTCMinutes());  //the UTC minutes value

当心以后,总是从日期对象问UTC值。这样,无论本地设置如何,用户都将看到相同的日期值。 否则日期值将根据本地时间设置进行移位。