Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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?

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);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top