如何忽略用户的时区和强制日期()使用特定的时区

在一个 JS 应用程序中,我从服务器(Ajax)接收时间戳(例如 1270544790922)。

基于这个时间戳,我使用以下方法创建 Date对象:

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

现在,_date在当前用户区域时区中解码了时间戳。

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

我该怎么做?

206826 次浏览

Date 对象的基础值实际上是 UTC。要证明这一点,请注意,如果键入 new Date(0),您将看到类似于: Wed Dec 31 1969 16:00:00 GMT-0800 (PST)的内容。在 GMT 中,0被视为0,而 .toString()方法显示的是局部时间。

注意,UTC 代表 通用的时间码。现在在两个不同的地方的当前时间是相同的 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"

This works but.... you can't really use any of the other date methods for your purposes since they describe the user's timezone. What you want is a date object that's related to the Helsinki timezone. Your options at this point are to use some 3rd party library (I recommend this), or hack-up the date object so you can use most of it's methods.

选择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-修改 date 对象

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 语句来描述时区何时发生更改,那么应该可以解决您的问题。

结论 -我认为特别是为了这个目的,你应该使用像 瞬间-时区这样的数据库。

若要计算毫秒和用户的时区,请使用以下内容:

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

我怀疑 回答我没有给出正确的结果。在问题中,提问者希望将时间戳从服务器转换为 Hellsinki 的当前时间,而不考虑用户的当前时区。

事实上,用户的时区可以是任何东西,所以我们不能信任它。

如果时间戳是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);

当一个纽约人访问这个页面时,警告(_ helsenkiTime)打印:

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

And when a Finlander visits the page, alert(_helsenkiTime) prints:

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

因此,只有当页面访问者的计算机中有目标时区(欧洲/赫尔辛基) ,但在世界其他地区几乎都失败时,该函数才是正确的。而且由于服务器时间戳通常是 UNIX 时间戳,根据定义,UNIX 时间戳以 UTC 表示,即自 UNIX 时代(1970年1月1日00:00:00 GMT)以来的秒数,因此我们无法通过时间戳确定 DST 或非 DST。

So the solution is to DISREGARD the current time zone of the user and implement some way to calculate UTC offset whether the date is in DST or not. Javascript has not native method to determine DST transition history of other timezone than the current timezone of user. We can achieve this most simply using server side script, because we have easy access to server's timezone database with the whole transition history of all timezones.

但是如果您不能访问服务器的(或任何其他服务器的)时区数据库,并且时间戳是 UTC 的,那么您可以通过用 Javascript 硬编码 DST 规则来获得类似的功能。

在欧洲/赫尔辛基,你可以使用以下函数(jsfiddled)覆盖1998-2099年的日期:

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

Of course if you can return timestamp in a form that the offset (DST or non-DST one) is already added to timestamp on server, you don't have to calculate it clientside and you can simplify the function a lot. BUT remember to NOT use timezoneOffset(), because then you have to deal with user timezone and this is not the wanted behaviour.

你可以用 setUTCMilliseconds()

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

只是另一种方法

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


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

干杯!

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

var _date	= 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

稍后注意,始终从 date 对象询问 UTC 值。这样,不管本地设置如何,用户都将看到相同的日期值。 否则,日期值将根据本地时间设置移位。

我的解决方案是确定浏览器应用的时区调整,然后反转它:

var timestamp = 1600913205;  //retrieved from unix, that is why it is in seconds


//uncomment below line if you want to apply Pacific timezone
//timestamp += -25200;


//determine the timezone offset the browser applies to Date()
var offset = (new Date()).getTimezoneOffset() * 60;


//re-initialize the Date function to reverse the timezone adjustment
var date = new Date((timestamp + offset) * 1000);


//here continue using date functions.

这一点的日期将是时区自由,始终 UTC,您可以应用您自己的偏移量的时间戳,以产生任何时区。

使用这个函数,然后 一直都是使用 UTC 函数,例如 mydate.getUTCHours();

   function getDateUTC(str) {
function getUTCDate(myDateStr){
if(myDateStr.length <= 10){
//const date = new Date(myDateStr); //is already assuming UTC, smart - but for browser compatibility we will add time string none the less
const date = new Date(myDateStr.trim() + 'T00:00:00Z');
return date;
}else{
throw "only date strings, not date time";
}
}


function getUTCDatetime(myDateStr){
if(myDateStr.length <= 10){
throw "only date TIME strings, not date only";
}else{
return new Date(myDateStr.trim() +'Z'); //this assumes no time zone is part of the date string. Z indicates UTC time zone
}
}
        

let rv = '';
        

if(str && str.length){
if(str.length <= 10){
rv = getUTCDate(str);
}else if(str.length > 10){
rv = getUTCDatetime(str);
}
}else{
rv = '';
}
return rv;
}


console.info(getDateUTC('2020-02-02').toUTCString());


var mydateee2 = getDateUTC('2020-02-02 02:02:02');
console.info(mydateee2.toUTCString());


// you are free to use all UTC functions on date e.g.
console.info(mydateee2.getUTCHours())
console.info('all is good now if you use UTC functions')