How to convert time correctly across timezones?

59,767

Solution 1

Is there a way, in javascript, without external web services, to do a correct conversion? That is, to detect that 10am UTC-08:00 should actually be 10am UTC-07:00, since it is Daylight Saving.

10:00-8 and 10:00-7 are two different moments in time. They are equal to 18:00Z and 17:00Z respectively (Z = UTC). When you are measuring in terms of an offset, daylight saving time does not enter the picture. Ever.

I assume that since the standard timezone in CA is PST, people don't switch to thinking in PDT in summer time. Or do they?!

In general, people just think in "Pacific Time", and that means both PST in the winter, and PDT in the summer. But computers are more precise. When you see PST, it means UTC-8. When you see PDT, it means UTC-7. It would be invalid to label using one form while simultaneously referring to the offset of the other.

Time zone abbreviations can be ambiguous. Ideally, when referencing the zone programmatically, you should use the IANA zone name, such as America/Los_Angeles. However, this is not currently possible in all JavaScript runtimes without a library. (They are working on this though.)

In central Europe, standard date is UTC+01:00, Daylight Saving date is UTC+02:00. So that difference between CA and Europe should be 9 hours, except for two periods in a year, when one or the other area switches between Standard and Daylight Saving modes.

Correct. They could be either 8, 9, or 10 hours apart. They switch at completely different times though, so don't try to manage this yourself.

So far, it looks like the moment.js/timezone plugin, suggested by Guido Preite is capable of doing this (more or less).

Moment-timezone is a great library. However, from the scenario you described, I don't think you need to worry about time zone conversion as much as you are thinking. See if you can follow this logic:

  1. The user in California enters a date and time into a textbox.
  2. You read that textbox value into a string, and parse it into a date:

    var dt = new Date("8/15/2013 10:00");
    

    or using moment.js:

    var m = moment("8/15/2013 10:00", "M/D/YYYY HH:mm");
    
  3. Because this is being done on the user's computer, JavaScript will automatically assume that this is a local date and time. You do not need to provide any offset or time zone information.

  4. This does mean that because of the DST transitions that the time entered might be invalid or ambiguous. JavaScript doesn't do such a great job at handling that, in fact - you will get different results on different browsers. If you want to be unambiguous, then you would provide an offset.

    // PST
    var dt = new Date("3/11/2013 1:00 UTC-08:00");
    
    // PDT
    var dt = new Date("3/11/2013 1:00 UTC-07:00");
    
  5. Once you have a Date (or a moment), then you can evaluate its UTC equivalent:

    var s = dt.toISOString();  //  2013-08-15T17:00:00Z
    

    it's the same with moment.js, but you will have better browser support:

    var s = m.toISOString();  //  2013-08-15T17:00:00Z
    
  6. You store that UTC value in your database.

  7. The other user in Central Europe comes along and loads the data.

  8. You feed it in to a Date or moment in JavaScript:

    var dt = new Date("2013-08-15T17:00:00Z");
    

    or with moment.js (again, better browser support)

    var m = moment("2013-08-15T17:00:00Z")
    
  9. Because JavaScript knows the time zone rules of the local computer, you can now display this date and it will be presented with the Central Europe time zone:

    var s = dt.ToString();  //  browser specific output
    // ex: "Thu Aug 15 2013 19:00:00 GMT+0200 (Central Europe Daylight Time)"
    

    or with moment.js, you can control the output format better

    var s = m.format("DD/MM/YYYY HH:mm"); // "15/08/2013 19:00"
    

    you could also let moment.js decide what localized format should be output:

    var s = m.format("llll"); // "Thu, 15 Aug 2013 19:00"
    

To summarize - if you are only interested in converting to and from the local time zone (whatever zone that may be), then you can do it all with just Date. Moment.js will make things easier for parsing and formatting, but it isn't absolutely required.

There are only a few scenarios that require a time zone library (such as moment-timezone or others).

  • You want to convert to or from a zone that is not the local time zone or UTC.

  • You are working with dates that are in the past, and there has been a change to the time zone rules or daylight saving time rules since then, and you have dates that would be interpreted differently under the new rules than with the old ones. This is a bit technical, but it does happen. Read more here and here.

Solution 2

Default constructor creates instance of local time

var localDate = new Date(); 

I can't test it right now, but you should be able to provide your datetime (as a parameter to the constructor)..

var eventDate = [SOMEDATE];
var localDate = new Date(eventDate);

..and then you should be able to call Date object functions like getMonth, which returns data in local timezone. As written at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

Note1: Without server = there is no server|db at all? If there is, the date should be saved as UTC in db and load it as local time for every user.. that way you don't have to worry conversions.

Note2: This question has some code showing how to get timezone difference: How to get the exact local time of client?

Solution 3

I developed this solution based on other examples...hope this works for you! Available on jsfiddle.

/* 
* Author: Mohammad M. AlBanna
* Website: MBanna.me
* Description: Get the current time in different time zone 
*/

//Check daylight saving time prototype
Date.prototype.stdTimezoneOffset = function() {
    var jan = new Date(this.getFullYear(), 0, 1);
    var jul = new Date(this.getFullYear(), 6, 1);
    return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
}

Date.prototype.dst = function() {
    return this.getTimezoneOffset() < this.stdTimezoneOffset();
}

var today = new Date();
var isDST = today.dst() ? true : false;
var pstOffset = isDST ? 7 : 8;
var cstOffset = isDST ? 5 : 6;
var estOffset = isDST ? 4 : 5;
var gmtOffset = 1;

pstOffset = pstOffset * 60 * 60 * 1000;
cstOffset = cstOffset * 60 * 60 * 1000;
estOffset = estOffset * 60 * 60 * 1000;
gmtOffset = gmtOffset * 60 * 60 * 1000;

var todayMillis = today.getTime();
var timeZoneOffset = (today.getTimezoneOffset() * 60 * 1000);

var curretPST = todayMillis - pstOffset; 
var curretCST = todayMillis - cstOffset; 
var curretEST = todayMillis - estOffset;
var curretGMT = todayMillis - gmtOffset;

addP("PST Time : " + new Date(curretPST).toUTCString());
addP("CST Time : " + new Date(curretCST).toUTCString());
addP("EST Time : " + new Date(curretEST).toUTCString());
addP("GMT Time : " + new Date(curretGMT).toUTCString());
addP("Local Time : " + new Date(today.getTime() - timeZoneOffset ).toUTCString());

function addP(value){
    var p = document.createElement("p");
    p.innerHTML = value;
    document.body.appendChild(p);
}
Share:
59,767

Related videos on Youtube

rdamborsky
Author by

rdamborsky

Updated on September 22, 2020

Comments

  • rdamborsky
    rdamborsky over 3 years

    Let's say user in CA, US picks up a date, time and timezone:

    Worldwide beer marathon starts on 8/15/2013 10:00 am, UTC-08:00

    Another user, in Central Europe opens the page where this date and time is displayed. He doesn't want to do time calculations (had few beers already). He just wants to see this date and time:

    8/15/2013 19:00

    Given the browser receives the date and time information, as entered by user in California:

    Is there a way, in javascript, without external web services, to do a correct conversion? That is, to detect that 10am UTC-08:00 should actually be 10am UTC-07:00, since it is Daylight Saving.

    Maybe I got wrong understanding of this from the beginning, but I don't want to let the entering user to think whether he should choose UTC-08:00 (PST) or UTC-07:00 (PDT). I assume that since the standard timezone in CA is PST, people don't switch to thinking in PDT in summer time. Or do they?!

    In central Europe, standard date is UTC+01:00, Daylight Saving date is UTC+02:00. So that difference between CA and Europe should be 9 hours, except for two periods in a year, when one or the other area switches between Standard and Daylight Saving modes.

    Update:

    After some more thinking and reading the comments, what I would ideally need is this:

    var utcOffset = f('2013-08-15T10:00', 'America/Los_Angeles');
    // utcOffset == "-07:00"
    var utcOffset = f('2013-11-15T10:00', 'America/Los_Angeles');
    // utcOffset == "-08:00"
    

    So far, it looks like the moment.js/timezone plugin, suggested by Guido Preite is capable of doing this (more or less).

    Any other way, using browser APIs?

    • Guido Preite
      Guido Preite almost 11 years
      check Moment.js and Moment Timezone momentjs.com/timezone
    • rdamborsky
      rdamborsky almost 11 years
      I use moment.js already. The Timezone extension looks promising. The generated timezones file contains the Daylight Savings conversion data. After a quick testing, it was able to correctly adjust the time entered. So this looks like browsers are not able to tell "hey, for this date you have to use this UTC offset since at that date, there is Summer time"?
  • rdamborsky
    rdamborsky almost 11 years
    Yes, this generally works ok. The problem is when user enters explicit timezone to be used for the date being saved. Imagine you submit 07/20/2013 10:00 UTC-08:00 while thinking about this as time in CA. But this information is incorrect, since at that given date -07:00 should be used for utc offset. And this is what I need to detect and solve. The storage/retrieval part is easy once the date is saved correctly. I want to avoid decision between standard/summer time during the entering phase.
  • rdamborsky
    rdamborsky almost 11 years
    Thanks Matt, for an exhaustive information, links and guide. My scenario is exactly the first one you pointed out: the conversion is not from local time zone. That is, user who enters the date and time also enters timezone that is relevant to that time. This doesn't necessarily have to be the timezone user is located in. I see I should state this more clearly in the question.
  • Brad Kent
    Brad Kent about 7 years
    I will say that it's ridiculous that javascript, the programing of language of the "world wide web" doesn't have built in time conversion / timezone tools