【问题标题】:javascript dates and timezones in angularjavascript日期和时区角度
【发布时间】:2017-05-28 09:45:58
【问题描述】:

无论你身在何处,我都想弄清楚如何从两个不同的时区获取两个日期以显示相同的时间,这绝对是疯了。

ie:如果我早上 7 点在墨尔本 (GMT +1000) 有一个时间,而我在早上 7 点在珀斯 (GMT +0800) 有另一个时间,我希望它们都在引导时间选择器中显示为 07:00同一页。

如果我在墨尔本,珀斯的实际时间会晚 2 小时。澳大利亚有许多不同的时区,夏令时混合在一起。

我了解 JS 日期已本地化到设置计算机的区域,所以我假设有问题的计算机是正确的。

我使用 momentjs 和 moment-timezones 创建了一个过滤器,但我无法让它显示正确的结果。

示例输入是:“2017-07-28T23:00:00.000Z” - 或 2017 年 7 月 29 日星期六 07:00:00 GMT+0800 (AWST)。

我发现 momentjs 在将时间转换为字符串方面做得很好,但是如何成功地将其转换为日期对象呢?

到目前为止,这是我的代码:

  (function () {
  'use strict';

  angular
    .module('bookings')
    .filter('timezone', timezone);

  timezone.$inject = [];

  function timezone() {

    function isCurrentTimeZone(code){
      var currentTimeCode = new Date().toString().split('(')[1].replace(')','');

      if (code.indexOf(currentTimeCode) >= 0) {
        return true;
      }

      return false;
    }

    function getLocalAustralianTimeZone() {

      var currentTimeCode = new Date().toString().split('(')[1].replace(')','');

      let timezones = [
        { state: 'NSW', tz: 'Australia/Sydney', code: 'AEST AEDT' },
        { state: 'QLD', tz: 'Australia/Brisbane', code: 'AEST AEDT' },
        { state: 'SA', tz: 'Australia/Adelaide', code: 'ACST ACDT' },
        { state: 'TAS', tz: 'Australia/Hobart', code: 'AEST AEDT' },
        { state: 'NT', tz: 'Australia/Darwin', code: 'ACST ACDT' },
        { state: 'VIC', tz: 'Australia/Melbourne', code: 'AEST AEDT' },
        { state: 'WA', tz: 'Australia/Perth', code: 'AWST AWDT' },
        { state: 'ACT', tz: 'Australia/Sydney', code: 'AEST AEDT' }
      ];

      let selectedTz = _.find(timezones, function (o) {
        return o.code.indexOf(currentTimeCode) >= 0;
      });
      return selectedTz;
    }

    function getAustralianTimeZone(state) {
      let timezones = [
        { state: 'NSW', tz: 'Australia/Sydney', code: 'AEST AEDT' },
        { state: 'QLD', tz: 'Australia/Brisbane', code: 'AEST AEDT' },
        { state: 'SA', tz: 'Australia/Adelaide', code: 'ACST ACDT' },
        { state: 'TAS', tz: 'Australia/Hobart', code: 'AEST AEDT' },
        { state: 'NT', tz: 'Australia/Darwin', code: 'ACST ACDT' },
        { state: 'VIC', tz: 'Australia/Melbourne', code: 'AEST AEDT' },
        { state: 'WA', tz: 'Australia/Perth', code: 'AWST AWDT' },
        { state: 'ACT', tz: 'Australia/Sydney', code: 'AEST AEDT' }
      ];

      let selectedTz = _.find(timezones, function (o) {
        return o.state === state;
      });
      return selectedTz;
    }

    function createDateAsUTC(date) {
      return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
    }

    function convertDateToUTC(date) {
      return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
    }

    return function (val, state) {
      moment.tz.add('Australia/Sydney|AEST AEDT|-a0 -b0|0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101|-293lX xcX 10jd0 yL0 1cN0 1cL0 1fB0 19X0 17c10 LA0 1C00 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 14o0 1o00 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 U00 1qM0 WM0 1tA0 WM0 1tA0 U00 1tA0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 11A0 1o00 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 11A0 1o00 WM0 1qM0 14o0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0|40e5');
      moment.tz.add('Australia/Adelaide|ACST ACDT|-9u -au|0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101|-293lt xcX 10jd0 yL0 1cN0 1cL0 1fB0 19X0 17c10 LA0 1C00 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 U00 1qM0 WM0 1tA0 WM0 1tA0 U00 1tA0 U00 1tA0 Oo0 1zc0 WM0 1qM0 Rc0 1zc0 U00 1tA0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 11A0 1o00 WM0 1qM0 14o0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0|11e5');
      moment.tz.add('Australia/Brisbane|AEST AEDT|-a0 -b0|01010101010101010|-293lX xcX 10jd0 yL0 1cN0 1cL0 1fB0 19X0 17c10 LA0 H1A0 Oo0 1zc0 Oo0 1zc0 Oo0|20e5');
      moment.tz.add('Australia/Broken_Hill|ACST ACDT|-9u -au|0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101|-293lt xcX 10jd0 yL0 1cN0 1cL0 1fB0 19X0 17c10 LA0 1C00 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 14o0 1o00 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 U00 1qM0 WM0 1tA0 WM0 1tA0 U00 1tA0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 11A0 1o00 WM0 1qM0 14o0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0|18e3');
      moment.tz.add('Australia/Currie|AEST AEDT|-a0 -b0|0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101|-29E80 19X0 10jd0 yL0 1cN0 1cL0 1fB0 19X0 17c10 LA0 1C00 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 11A0 1qM0 WM0 1qM0 Oo0 1zc0 Oo0 1zc0 Oo0 1wo0 WM0 1tA0 WM0 1tA0 U00 1tA0 U00 1tA0 11A0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 11A0 1o00 1io0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1cM0 1a00 1io0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0|746');
      moment.tz.add('Australia/Darwin|ACST ACDT|-9u -au|010101010|-293lt xcX 10jd0 yL0 1cN0 1cL0 1fB0 19X0|12e4');
      moment.tz.add('Australia/Eucla|+0845 +0945|-8J -9J|0101010101010101010|-293kI xcX 10jd0 yL0 1cN0 1cL0 1gSp0 Oo0 l5A0 Oo0 iJA0 G00 zU00 IM0 1qM0 11A0 1o00 11A0|368');
      moment.tz.add('Australia/Hobart|AEST AEDT|-a0 -b0|010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101|-29E80 19X0 10jd0 yL0 1cN0 1cL0 1fB0 19X0 VfB0 1cM0 1o00 Rc0 1wo0 Rc0 1wo0 U00 1wo0 LA0 1C00 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 11A0 1qM0 WM0 1qM0 Oo0 1zc0 Oo0 1zc0 Oo0 1wo0 WM0 1tA0 WM0 1tA0 U00 1tA0 U00 1tA0 11A0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 11A0 1o00 1io0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1cM0 1a00 1io0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0|21e4');
      moment.tz.add('Australia/Lord_Howe|AEST +1030 +1130 +11|-a0 -au -bu -b0|0121212121313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313|raC0 1zdu Rb0 1zd0 On0 1zd0 On0 1zd0 On0 1zd0 TXu 1qMu WLu 1tAu WLu 1tAu TXu 1tAu Onu 1zcu Onu 1zcu Onu 1zcu Rbu 1zcu Onu 1zcu Onu 1zcu 11zu 1o0u 11zu 1o0u 11zu 1o0u 11zu 1qMu WLu 11Au 1nXu 1qMu 11zu 1o0u 11zu 1o0u 11zu 1qMu WLu 1qMu 11zu 1o0u WLu 1qMu 14nu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1fAu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1fAu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1fzu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1fAu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1fAu 1cLu 1cMu 1cLu 1cMu|347');
      moment.tz.add('Australia/Lindeman|AEST AEDT|-a0 -b0|010101010101010101010|-293lX xcX 10jd0 yL0 1cN0 1cL0 1fB0 19X0 17c10 LA0 H1A0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0|10');
      moment.tz.add('Australia/Melbourne|AEST AEDT|-a0 -b0|0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101|-293lX xcX 10jd0 yL0 1cN0 1cL0 1fB0 19X0 17c10 LA0 1C00 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 U00 1qM0 WM0 1qM0 11A0 1tA0 U00 1tA0 U00 1tA0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 11A0 1o00 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 11A0 1o00 WM0 1qM0 14o0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0|39e5');
      moment.tz.add('Australia/Perth|AWST AWDT|-80 -90|0101010101010101010|-293jX xcX 10jd0 yL0 1cN0 1cL0 1gSp0 Oo0 l5A0 Oo0 iJA0 G00 zU00 IM0 1qM0 11A0 1o00 11A0|18e5');

      if (state !== "") {
        var timezone = getAustralianTimeZone(state);
        var currentZone = getLocalAustralianTimeZone();
        var isCurrent = isCurrentTimeZone(timezone.code);


        if (!isCurrent) {

          var date = new Date(Date.parse(val));
          date = new Date(date.getTime() - (60000 * moment(val).tz(timezone.tz)._offset));
          return date;
        }

        return new Date(Date.parse(val));

      }

      return new Date(val);
    };
  }
}());

【问题讨论】:

  • 2017-07-28T23:00:00.000Z 转换为日期? moment("2017-07-28T23:00:00.000Z") 呢?
  • 输入是“2017-07-28T23:00:00.000Z”,墨尔本和珀斯的预期输出是多少?你的要求我不清楚。
  • Date.toString() 上的字符串操作不好。它在不同的浏览器中输出不同的结果。也可以使用时刻来获取时区。
  • @sabithpocker 我想要的是 Sat Jul 29 2017 07:00:00 作为日期对象,无论用户位于何处。如您所见,我试图更改时间偏移量,但我无法获得任何结果......

标签: javascript date datetime


【解决方案1】:

日期对象在内部是 UTC。主机时区用于涉及“本地”值的计算以及在解析“本地”字符串时生成 UTC 值。

为 2017 年 7 月 28 日 07:00 创建“本地”日期对象的最可靠方法是将适当的值直接传递给 Date 构造函数。这将为等效的 UTC 日期和时间生成一个 UTC 值,但无论主机时区如何,它似乎都是相同的日期和时间(当然,对于每个具有不同时区偏移量的主机,它实际上代表不同的时间点) .

您可以使用不带时区的 ISO 8601 格式日期和时间字符串,应该将其视为本地。但是,字符串的解析有些不可靠,因此不是首选解决方案(例如,Safari 将没有时区的 ISO 8601 格式日期和时间字符串解析为 UTC,而不是本地)。

console.log(new Date(2017,6,28,7).toString());
console.log(new Date('2017-07-28T07:00').toString()); // Safari treats this as UTC

【讨论】:

    【解决方案2】:

    Date 对象不能只包含“Sat Jul 29 2017 07:00:00”。它无论如何都会有一个关联的时区。无论如何,您都可以使用29 May 9 am 创建一个IST 日期,并假设它是Australia/Melbourne。请参阅以下示例,因为您可以使用 objForDatePicker 与 datepicker 一起使用。然后需要再次更正从 DatePicker 返回的日期,如图所示。

    var input = "2017-07-28T23:00:00.000Z";
    console.log('input :', input);
    var date = moment.tz(input, 'Australia/Melbourne');
    //now you can use it like a  Date object
    
    console.log("moment date :",date.format('MMMM Do YYYY, h:mm:ss a'), date.format('z'));
    
    // create a local date with that time but false timezone
    
    var objForDatePicker = moment(date.format('MMMM Do YYYY, h:mm:ss a'),'MMMM Do YYYY, h:mm:ss a').toDate();
    
    console.log("js date :", objForDatePicker.toString(),' :Jul 29 9AM IST this is wrong timezone-date duo')
    
    // to convert back to  UTC or a correct timezone-date duo
    dateStringWithoutTZ = moment(objForDatePicker).format('MMMM Do YYYY, h:mm:ss a');
    var date2 = moment.tz(dateStringWithoutTZ, 'MMMM Do YYYY, h:mm:ss a', 'Australia/Melbourne');
    
    console.log("moment date: ",date2.format('MMMM Do YYYY, h:mm:ss a'), date2.format('z'));
    
    console.log("output :", date2.toISOString());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.13/moment-timezone-with-data-2012-2022.js"></script>

    检查您的时间选择器实现是否接受moment 对象,如果是会更容易,直接使用date。还要添加一个指向您正在使用的时间选择器的链接,Bootstrap 有很多时间选择器实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多