Detect the ID of the current user timezone using m

2019-01-14 11:50发布

问题:

What I'm looking for is a way to detect the browser's timezone ID (as defined in the Olson tables) but I don't care for the exact ID, I just need the ID of a timezone that works the same as the user's one (for example "Europe/Rome" is fine if the user is in Paris).

I'm not interested in the current offset, I really need the timezone so that I can send it to the server to do computations for other dates (the server has the Olson tables too).

Theoretically, as I already use Moment.js timezone library and have included the Olson tables, I don't need anything else, but I don't find any API to do the detection. I don't know if it's hidden somewhere or if somebody has it already written. One of the problems is that the current timezone plugin seems to keep its data private.

I dont' want a solution based on the integration of yet another copy or extract of the Olson tables (which I would have to maintain), I know there are a few libraries duplicating them, I want to use the ones I already have in Moment.js.

回答1:

moment now has the guess() API as described here



回答2:

I made a small script to do that detection. It starts by registering the ids of the available timezones, then, on a call to the matches function tests all timezone ids for the current time and the times 4 and 8 months later (to filter out the timezones with different daylight rules) and five years before.

Here it is :

<script src="moment-with-langs.min.js"></script>
<script src="moment-timezone.min.js"></script>
<script src="moment-timezone-data.js"></script>
<script>
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;
    }
};
</script>

If you just want one timezone id, simply use

var tzid = tzdetect.matches()[0];

Demonstration

GitHub Repository : https://github.com/Canop/tzdetect.js

Update : The code here shown isn't compatible with the most recent versions of moment.js. Please refer to the GitHub repository for a maintained (free to use) code.

2017 Update: There's now an API in moment.js to guess the timezone. That's probably the best solution right now.



回答3:

If you want to use the standard JavaScript API, you can use Intl.DateTimeFormat.resolvedOptions where there is browser support:

Intl.DateTimeFormat().resolvedOptions().timeZone; // "America/Los_Angeles"

resolvedOptions is currently (Jan 2016) available in all browsers except Safari on iOS and desktop: http://caniuse.com/#feat=internationalization

However, the timeZone property is currently only available on Chrome.



回答4:

There's a javascript tool that does just that :

https://github.com/entraigas/jstz

It seems to deal with timezones ambiguity also.

Combined with momentJS timezone, you can get the timezone and show formatted date :

var tzObj = jstz.determine();
var timezoneCode = tzObj.name();
console.log(moment.tz(timeZoneCode).format());