Moment-timezone: Get the browsers current time zone.

Created on 16 Oct 2014  路  40Comments  路  Source: moment/moment-timezone

Unless I'm missing something it seems that there is no way to get the current time zone?? I know there are third party libs to get the olson name.. I just thought this would be included.

moment.tz().zoneName()
moment.tz(new Date()).zoneName()
moment.tz(new Date()).zone()

enhancement

Most helpful comment

This has been released in [email protected] as moment.tz.guess().

All 40 comments

See #55 as well.

This is planned, but I haven't had time to implement it yet.

Hi, I'd like this feature as well. A couple of questions:

  • Should the API return a single guessed timezone or all suitable timezones? Maybe have both zoneName() and zoneNames()?
  • Any thoughts on how to implement it? I thought about getting the offset, adjusting it if DST is in effect, and then using the result to find suitable timezones. Or is that too naive? ;)

Yeah, I think the api would be something like moment.tz.localZones() to return a list of possible matches and moment.tz.localZone() to return the first item from that list.

Fortunately, this can be a one-time calculation, as the user's timezone won't change without a refresh.

var cachedLocalZones;

function localZones () {
  if (!cachedLocalZones) {
    cachedLocalZones = calculateLocalZones()
  }
  return cachedLocalZones.slice(); // always return a copy
}

function localZone () {
  return localZones().pop();
}

As far as the actual logic for calculating the local timezone, I was thinking something along these lines.

First Pass

Create Date objects for Jan 1 and Jul 1 of the current year.

var currYear = new Date().getFullYear();
var jan = new Date(currYear, 0, 1);
var jul = new Date(currYear, 6, 1);

Get the offsets for those dates using getTimezoneOffset.

var janOffset = jan.getTimezoneOffset();
var julOffset = jul.getTimezoneOffset();

Filter out zones which do not match the Jan and Jul offsets. See http://momentjs.com/timezone/docs/#/zone-object/offset/

zone.offset(jan) === janOffset && zone.offset(jul) === julOffset

That should filter down the list pretty significantly.

Second Pass

This pass is where things can get a bit more hairy, @mj1856, you should weigh in on this as I think you have more knowledge here. I don't know if we can check any more than just the current year in this step as browser timezone rules are unreliable for previous years.

For each zone that made it through the first pass, check the offset right before and after the untils for that year.

for (var i = 0; i < zone._untils.length; i++) {
  if (
    isCurrentYear(zone._untils[i])) {
    (new Date(zone._untils[i] - 1000).getTimezoneOffset() === zone._offsets[i]) &&
    (new Date(zone._untils[i] + 1000).getTimezoneOffset() === zone._offsets[i + 1])
  ) {
    // zone makes it through pass
  }
}

I think that should get most of the way there. This doesn't provide a way to prefer one zone alias over another, so we may have to add support for adding a list of preferred names to get America/Los_Angeles instead of US/Pacific for example.

As far as testing this functionality, I think we should mock Date.prototype.getTimezoneOffset to output the offsets that we want.

var getTimezoneOffset = Date.prototype.getTimezoneOffset;
exports.localZones = {
  tearDown : function () {
    Date.prototype.getTimezoneOffset = getTimezoneOffset;
  },
  someTest : function () {
    Date.prototype.getTimezoneOffset = function () {
      return this > someTimestamp ? 420 : 480;
    };
  }
};

I found this, also see the first comment to that answer...

I wonder, wouldn't it work if we just retrieved the standard timezone offset (without DST if it's in effect) and returned all zones with the same timezone offset? To borrow from the example in the link above:

  • Assume: Browser is in New York and DST is in effect, so its offset is -04:00
  • Get the standard timezone offset (-05:00 in this case)
  • Look for zones with that timezone offset (get an array that includes America/New_York)

We are trying to get the smallest array possible with localZones, so we should try to eliminate as many zones as we can. The southern hemisphere has DST during the northern hemisphere's winter, so checking both Jan and Jul will help eliminate those.

moment.tz([2014, 0, 1], 'Africa/Windhoek').format('MMM Z'); // Jan +02:00
moment.tz([2014, 6, 1], 'Africa/Windhoek').format('MMM Z'); // Jul +01:00
moment.tz([2014, 0, 1], 'Europe/Berlin').format('MMM Z');   // Jan +01:00
moment.tz([2014, 6, 1], 'Europe/Berlin').format('MMM Z');   // Jul +02:00

Alright. I'll go ahead an proceed with an initial implementation in a couple of days unless @mj1856 (or someone else) gets there first. :)

Another pass we could add is to check if the Jan and Jul Date objects contain the timezone abbreviation in their toString value.

new Date().toString(); //Wed Nov 05 2014 09:25:33 GMT-0800 (PST)

Date.prototype.toString does not always contain a timezone abbreviation, so we'll have to ignore this pass if it doesn't yield any results.

@elad - Go for it. I'm swamped at the moment. :)

Hi Guys! You can check how jstimezonedetect doest it!

@franleplant - Yes, we're well aware of jstimezonedetect. There's also an effort at https://github.com/Canop/tzdetect.js to take the same approach within the moment-timezone data.

The bigger problem is that as time goes on, the detection tests have to be updated. Due to the ECMAScript issue, tests around historical dates don't always work. So jstz, and anything else, has to rely on _current_ tz rules. (see https://github.com/moment/moment/issues/831 and http://codeofmatt.com/2013/06/07/javascript-date-type-is-horribly-broken/).

Some browsers that support the ECMAScript Internationalization API (ECMA-402) can easily get the time zone from the host directly. (I say _some_ because Internet Explorer supports that API, but doesn't support the provision for reporting IANA time zones.)

Intl.DateTimeFormat().resolvedOptions().timeZone

Thanks for all the information @mj1856
Im currently working on a private app that needs to support Different timezones, and timezone selection, and let me tell you that it is no trivial task.
Thanks to moment.js and moment-timezone its easier though!

Fran

Would love to see this get put in place! I just went through some troubles trying to figure this out today. I ended up using jstz with moment-timezone as follows

var someTimeFromUTC = moment('2014-11-19T08:00:00Z');
var tzName = jstz.determine().name(); // America/Los_Angeles
var localTime = moment(someTimeFromUTC).tz(tzName)
var formatedTime = localTime.format('llll z'); // Tue, Nov 19, 2014 8:00AM PST

All I really wanted to do was to be able to format my time with the abbreviated time zone. I saw that was depreciated in moment.js in lieu of creating moment-timezone however the functionality doesn't seem to exist anymore.

@elad Did you get a chance to wire up a working protoype for this feature.. I can give it a shot, if you haven't done a lot of progress on it already. Thanks!

@kashifshamaz21 please do! Unfortunately I haven't had a chance to get to it yet. :(

Hello,
This feature would be awsome!
+1000

Check this code
http://stackoverflow.com/questions/19420582/detect-the-id-of-the-current-user-timezone-using-moment-js
https://github.com/Canop/tzdetect.js

var tzdetect = {
    names: moment.tz.names(),
    matches: function(base){
        var results = [], now = Date.now(), makekey = function(id){
            return [0, 4, 8, -5*12, 4-5*12, 8-5*12, 4-2*12, 8-2*12].map(function(months){
                var m = moment(now + months*30*24*60*60*1000);
                if (id) m.tz(id);
                return m.format("DDHHmm");
            }).join(' ');
        }, lockey = makekey(base);
        tzdetect.names.forEach(function(id){
            if (makekey(id)===lockey) results.push(id);
        });
        return results;
    }
};

If you just want one timezone id, simply use
var tzid = tzdetect.matches()[0];

I love the idea of having a function that can be used directly against the moment-timezone data, rather than jsTimeZoneDetect, which has it's own data. However, I'm not convinced that the Canop/tzdetect solution is complete enough to be useful.

Running it on my computer, which is Windows 8.1, Chrome latest, in US Pacific time, I get:

["America/Dawson", "America/Ensenada", "America/Los_Angeles", "America/Tijuana",
 "America/Vancouver", "America/Whitehorse", "Canada/Pacific", "Canada/Yukon",
 "Mexico/BajaNorte", "PST8PDT", "US/Pacific", "US/Pacific-New"]

jsTimeZoneDetect gives the correct result of America/Los_Angeles.

I'd love to be proven wrong, but I'm fairly certain that any solution other than the Ecma Intl API (in supported browsers) will have problems. The mere fact that ECMAScript 5.1 hides all non-current DST transitions makes it near impossible to properly interrogate the Date object for time zone information.

Until this gets fixed you can use Intl.DateTimeFormat().resolvedOptions().timeZone on latest Chrome & FF

@emorikawa - Chrome, yes. FF - no. I also believe it works in Opera, but not IE. Not sure about Safari.

+1 ! with todays SaaS apps displaying analytics everywhere it's a must-have feature. Thank you if you cant make it !

Gonna try and jump in and implement this. I have a lot of docs to read to orient myself though. @elad @timrwood if you have any updates other than what you have specified above let me know!

I opened a PR for this at #220.

@mj1856 good call on Intl.DateTimeFormat().resolvedOptions().timeZone!

@timrwood I'm using moment-timezone 0.3.0. Is the capability of getting client/browser timezone implemented? I'm currently using jstz-detect to detect the timezone (Country/City) and using that with moment.tz.* functions.

@gnansu - no, it is not yet implemented in the release. You can try the code in PR #220, but we've still got some things to work out before we are ready to merge and release it.

@mj1856 Thanks Matt for the information. Looking forward to the new additions.

Fortunately, this can be a one-time calculation, as the user's timezone won't change without a refresh.

@timrwood that's not true all the time: try on Chrome (OSX), it will update the timezone dynamically without refresh.

@avetisk, that's a bummer, we'll have to add some cache checks to make sure we aren't getting stale data.

the great white hope:
Intl.DateTimeFormat().resolvedOptions().timeZone

Unfortunately I tried it with my 4 browsers. Safari (today's) has no Intl, FF41 and IE11 have it but returns undefined (which is documented as 'the current timezone' thanx a lot). Chrome has it but use 'resolved' in place of 'resolvedOptions()'. So the only one that works, is the improperly implemented one. :-(

Why is this so hard? It would be easy to implement once you've done the rest of Intl. EZ.

Have implemented this feature,i noted that is issue have been posted more than one year,but i can find any info about this in moment-timezone's documents.

@argb is right, it looks like it's done.
@timrwood @mj1856 this was closed in favor of #220. #220 is now closed because it was moved to #256 which is merged, but only to guess-timezone. I just saw there's progress (#274), but there's no open tracking issue for this as a feature, or is there?

This has been released in [email protected] as moment.tz.guess().

@timrwood I tried using moment.tz.guess() it works however it doesn't detect it automatically the page has to reload first. is there a way to get the timezone immediately without having to reload the page?

@Ihs88999 - There's nothing special about that function in terms of loading. Perhaps you just aren't loading moment and moment-timezone correctly? We don't know anything about your code or environment, so it's hard to say.

@timrwood Suggestions for how to use this outside the browser?

@kevinSuttle process.env.TZ

@bcherny is there a trick to get TZ on OSX?

$ node
> process.env.TZ
undefined

I'm using OS X 10.11.6

$ node --version
v5.4.1

Looks like OSX doesn't define it. I just published node-timezone, which I tested on OSX and Ubuntu.

This works for me inside of Webpack: https://github.com/moment/moment-timezone/issues/138#issuecomment-77792958

Was this page helpful?
0 / 5 - 0 ratings

Related issues

LunarSweeper picture LunarSweeper  路  4Comments

GMeulendyks picture GMeulendyks  路  5Comments

palindrom615 picture palindrom615  路  4Comments

SathyaChenniappan picture SathyaChenniappan  路  4Comments

jishaal picture jishaal  路  6Comments