2

I am going absolutely insane trying to work out how to get two dates, from two different time zones to show the same times regardless of where you are.

ie: If I have a time in Melbourne (GMT +1000) at 7am, and I have another in Perth (GMT +0800) at 7am I would like them both to show in a bootstrap timepicker as 07:00 on the same page.

If I am in Melbourne the actual time in Perth is 2 hours behind. There are many different time zones in Australia with daylight savings thrown into the mix.

I understand that JS dates are localised to the region of where the computer is set, so I am assuming that the computer in question is correct.

I have created a filter using momentjs and moment-timezones but I just cannot get it to show the correct results.

An example input is: "2017-07-28T23:00:00.000Z" - or Sat Jul 29 2017 07:00:00 GMT+0800 (AWST).

I have found that momentjs does a great job of converting times into strings, but how do I successfully convert that into a date object?

Here is my code so far:

  (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);
    };
  }
}());
4
  • convert 2017-07-28T23:00:00.000Z to a date? What about moment("2017-07-28T23:00:00.000Z") ? Commented May 28, 2017 at 10:00
  • Input is "2017-07-28T23:00:00.000Z", what are the expected outputs for Melbourne and Perth? Your requirement is not clear to me. Commented May 28, 2017 at 10:00
  • String manipulation on Date.toString() is not good. It spits out different results in different browsers. Use moment to get timezone as well. Commented May 28, 2017 at 10:02
  • @sabithpocker What I would like to have is Sat Jul 29 2017 07:00:00 as a date object regardless of where the user is based. As you can see I was trying to alter time offsets but I was not able to get anywhere with that... Commented May 28, 2017 at 10:18

2 Answers 2

1

Date objects are UTC internally. The host timezone is used for calculations involving "local" values and for generating the UTC value when parsing a "local" string.

The most robust way of creating a "local" date object for 28 July, 2017 at 07:00 is to pass appropriate values directly to the Date constructor. This will generate a UTC value for the equivalent UTC date and time, but will appear to be the same date and time regardless of the host timezone (but of course will actually represent a different moment in time for each host with a different timezone offset).

You can use an ISO 8601 format date and time string without a timezone, which should be treated as local. However, parsing of strings is somewhat unreliable so not the preferred solution (e.g. Safari parses ISO 8601 format date and time strings without a timezone as UTC, not local).

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

Sign up to request clarification or add additional context in comments.

Comments

0

You cannot have a Date object with just "Sat Jul 29 2017 07:00:00". It will any way have an associated timezone. You can anyway create say an IST date with 29 May 9 am and just assume that it is Australia/Melbourne. See the following example, in that you can use objForDatePicker to be used with datepicker. Then the returned Date from DatePicker will need to be corrected again as shown.

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>

Check if your time picker implementation accepts a moment object, if yes it will be easier, use date directly. Also add a link to the time picker that you are using, there are a lot of time picker implementations for Bootstrap.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.