代码之家  ›  专栏  ›  技术社区  ›  warpech

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

  •  89
  • warpech  · 技术社区  · 16 年前

    在js应用程序中,我接收时间戳(eq. 1270544790922 )从服务器(ajax)。

    基于我创建的时间戳 Date 对象使用:

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

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

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

    我该怎么做?

    6 回复  |  直到 8 年前
        1
  •  59
  •   Parris    8 年前

    日期对象的基础值实际上是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"
    

    这很有效,但是……因为其他日期方法描述了用户的时区,所以不能真正使用它们。你想要的是一个与赫尔辛基时区相关的日期对象。此时,您可以选择使用一些第三方库(我建议您这样做),或者修改date对象,以便您可以使用它的大多数方法。

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

    结论 -我认为特别是为了这个目的,你应该使用 moment-timezone .

        2
  •  17
  •   Ehren    14 年前

    要计算毫秒和用户的时区,请使用以下命令:

    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
    
        3
  •  14
  •   Mohan    9 年前

    只是另一种方法

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

    干杯!

        4
  •  13
  •   Community Mohan Dere    9 年前

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

    当Finlander访问页面时,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或non-dst one)已经添加到服务器上的timestamp的形式返回timestamp,那么您不必在客户端计算它,并且可以大大简化函数。但请记住不要使用timezoneoffset(),因为这样就必须处理用户时区,而这不是所需的行为。

        5
  •  2
  •   Tibor    9 年前

    假设您得到赫尔辛基时间的时间戳,我将创建一个日期对象,设置为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

    请稍后注意,始终从date对象询问utc值。这样,无论本地设置如何,用户都将看到相同的日期值。 否则,日期值将根据本地时间设置进行移动。

        6
  •  0
  •   jimasun    11 年前

    你可以用 setUTCMilliseconds()

    var _date = new Date();
    _date.setUTCMilliseconds(1270544790922);
    
    推荐文章