javascript 如何忽略用户的时区并强制Date()使用特定时区

643ylb08  于 2023-01-24  发布在  Java
关注(0)|答案(8)|浏览(98)

在JS应用程序中,我从服务器(Ajax)接收时间戳(eq.1270544790922)。
基于该时间戳,我使用以下命令创建Date对象:

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

现在,_date解码了当前用户区域设置时区的时间戳。我不希望这样。
我想使用_date将此时间戳转换为欧洲赫尔辛基市的当前时间(不考虑用户的当前时区)。
我该怎么做呢?

yeotifhr

yeotifhr1#

Date对象的底层值实际上是UTC。为了证明这一点,请注意,如果您键入new Date(0),您将看到如下内容:Wed Dec 31 1969 16:00:00 GMT-0800 (PST).0在GMT中被视为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-timezone

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这样的日期库。

xt0899hw

xt0899hw2#

要考虑毫秒数和用户的时区,请使用以下命令:

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
3phpmpom

3phpmpom3#

只是另一种方法

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);

干杯!

qzlgjiam

qzlgjiam4#

我怀疑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);

当纽约人访问该页面时,alert(_helsenkiTime)将打印:

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

当芬兰人访问该页面时,alert(_helsenkiTime)会打印:

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

因此,只有当页面访问者的计算机中有目标时区(欧洲/赫尔辛基)时,该函数才是正确的,但在世界上几乎所有其他地方都是错误的。而且,由于服务器时间戳通常是UNIX时间戳,根据UTC的定义,它是从Unix纪元(1970年1月1日00:00:00 GMT)以来的秒数,我们无法根据时间戳确定DST或非DST。
因此解决方案是不考虑用户的当前时区,并实现某种方法来计算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

当然,如果你可以返回一个格式的时间戳,偏移量(DST或非DST)已经添加到服务器上的时间戳,你不必计算它的客户端,你可以简化函数很多.但记住不要使用timezoneOffset(),因为这样你就必须处理用户时区,这不是想要的行为.

hfyxw5xn

hfyxw5xn5#

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

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

以后要注意,总是从日期对象中询问UTC值。这样,无论本地设置如何,用户都将看到相同的日期值。否则,日期值将根据本地时间设置而移动。

zvokhttg

zvokhttg6#

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

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,您可以应用自己的偏移时间戳产生任何时区。

j8ag8udp

j8ag8udp7#

使用此函数并在以后 * 始终 * 使用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')
ou6hu8tu

ou6hu8tu8#

解决这个问题的唯一方法是从字符串中删除时区和毫秒信息。

import { format } from 'date-fns'

  const myDateTimeString = '2022-02-22T19:55:00.000+01:00'
  const dateTimeWithoutTimezone = myDateTimeString.slice(0, 16) // <- 2022-02-22T19:55
  format(new Date(dateTimeWithoutTimezone), 'HH:mm')

相关问题