/** * This script gives you the zone info key representing your device's time zone setting. * * @name jsTimezoneDetect * @version 1.0.5 * @author Jon Nylander * @license MIT License - http://www.opensource.org/licenses/mit-license.php * * For usage and examples, visit: * http://pellepim.bitbucket.org/jstz/ * * Copyright (c) Jon Nylander */ /*jslint undef: true */ /*global console, exports*/ (function(root) { /** * Namespace to hold all the code for timezone detection. */ var jstz = (function () { 'use strict'; var HEMISPHERE_SOUTH = 's', /** * Gets the offset in minutes from UTC for a certain date. * @param {Date} date * @returns {Number} */ get_date_offset = function (date) { var offset = -date.getTimezoneOffset(); return (offset !== null ? offset : 0); }, get_date = function (year, month, date) { var d = new Date(); if (year !== undefined) { d.setFullYear(year); } d.setMonth(month); d.setDate(date); return d; }, get_january_offset = function (year) { return get_date_offset(get_date(year, 0 ,2)); }, get_june_offset = function (year) { return get_date_offset(get_date(year, 5, 2)); }, /** * Private method. * Checks whether a given date is in daylight saving time. * If the date supplied is after august, we assume that we're checking * for southern hemisphere DST. * @param {Date} date * @returns {Boolean} */ date_is_dst = function (date) { var is_southern = date.getMonth() > 7, base_offset = is_southern ? get_june_offset(date.getFullYear()) : get_january_offset(date.getFullYear()), date_offset = get_date_offset(date), is_west = base_offset < 0, dst_offset = base_offset - date_offset; if (!is_west && !is_southern) { return dst_offset < 0; } return dst_offset !== 0; }, /** * This function does some basic calculations to create information about * the user's timezone. It uses REFERENCE_YEAR as a solid year for which * the script has been tested rather than depend on the year set by the * client device. * * Returns a key that can be used to do lookups in jstz.olson.timezones. * eg: "720,1,2". * * @returns {String} */ lookup_key = function () { var january_offset = get_january_offset(), june_offset = get_june_offset(), diff = january_offset - june_offset; if (diff < 0) { return january_offset + ",1"; } else if (diff > 0) { return june_offset + ",1," + HEMISPHERE_SOUTH; } return january_offset + ",0"; }, /** * Uses get_timezone_info() to formulate a key to use in the olson.timezones dictionary. * * Returns a primitive object on the format: * {'timezone': TimeZone, 'key' : 'the key used to find the TimeZone object'} * * @returns Object */ determine = function () { var key = lookup_key(); return new jstz.TimeZone(jstz.olson.timezones[key]); }, /** * This object contains information on when daylight savings starts for * different timezones. * * The list is short for a reason. Often we do not have to be very specific * to single out the correct timezone. But when we do, this list comes in * handy. * * Each value is a date denoting when daylight savings starts for that timezone. */ dst_start_for = function (tz_name) { var ru_pre_dst_change = new Date(2010, 6, 15, 1, 0, 0, 0), // In 2010 Russia had DST, this allows us to detect Russia :) dst_starts = { 'America/Denver': new Date(2011, 2, 13, 3, 0, 0, 0), 'America/Mazatlan': new Date(2011, 3, 3, 3, 0, 0, 0), 'America/Chicago': new Date(2011, 2, 13, 3, 0, 0, 0), 'America/Mexico_City': new Date(2011, 3, 3, 3, 0, 0, 0), 'America/Asuncion': new Date(2012, 9, 7, 3, 0, 0, 0), 'America/Santiago': new Date(2012, 9, 3, 3, 0, 0, 0), 'America/Campo_Grande': new Date(2012, 9, 21, 5, 0, 0, 0), 'America/Montevideo': new Date(2011, 9, 2, 3, 0, 0, 0), 'America/Sao_Paulo': new Date(2011, 9, 16, 5, 0, 0, 0), 'America/Los_Angeles': new Date(2011, 2, 13, 8, 0, 0, 0), 'America/Santa_Isabel': new Date(2011, 3, 5, 8, 0, 0, 0), 'America/Havana': new Date(2012, 2, 10, 2, 0, 0, 0), 'America/New_York': new Date(2012, 2, 10, 7, 0, 0, 0), 'Europe/Helsinki': new Date(2013, 2, 31, 5, 0, 0, 0), 'Pacific/Auckland': new Date(2011, 8, 26, 7, 0, 0, 0), 'America/Halifax': new Date(2011, 2, 13, 6, 0, 0, 0), 'America/Goose_Bay': new Date(2011, 2, 13, 2, 1, 0, 0), 'America/Miquelon': new Date(2011, 2, 13, 5, 0, 0, 0), 'America/Godthab': new Date(2011, 2, 27, 1, 0, 0, 0), 'Europe/Moscow': ru_pre_dst_change, 'Asia/Amman': new Date(2013, 2, 29, 1, 0, 0, 0), 'Asia/Beirut': new Date(2013, 2, 31, 2, 0, 0, 0), 'Asia/Damascus': new Date(2013, 3, 6, 2, 0, 0, 0), 'Asia/Jerusalem': new Date(2013, 2, 29, 5, 0, 0, 0), 'Asia/Yekaterinburg': ru_pre_dst_change, 'Asia/Omsk': ru_pre_dst_change, 'Asia/Krasnoyarsk': ru_pre_dst_change, 'Asia/Irkutsk': ru_pre_dst_change, 'Asia/Yakutsk': ru_pre_dst_change, 'Asia/Vladivostok': ru_pre_dst_change, 'Asia/Baku': new Date(2013, 2, 31, 4, 0, 0), 'Asia/Yerevan': new Date(2013, 2, 31, 3, 0, 0), 'Asia/Kamchatka': ru_pre_dst_change, 'Asia/Gaza': new Date(2010, 2, 27, 4, 0, 0), 'Africa/Cairo': new Date(2010, 4, 1, 3, 0, 0), 'Europe/Minsk': ru_pre_dst_change, 'Pacific/Apia': new Date(2010, 10, 1, 1, 0, 0, 0), 'Pacific/Fiji': new Date(2010, 11, 1, 0, 0, 0), 'Australia/Perth': new Date(2008, 10, 1, 1, 0, 0, 0) }; return dst_starts[tz_name]; }; return { determine: determine, date_is_dst: date_is_dst, dst_start_for: dst_start_for }; }()); /** * Simple object to perform ambiguity check and to return name of time zone. */ jstz.TimeZone = function (tz_name) { 'use strict'; /** * The keys in this object are timezones that we know may be ambiguous after * a preliminary scan through the olson_tz object. * * The array of timezones to compare must be in the order that daylight savings * starts for the regions. */ var AMBIGUITIES = { 'America/Denver': ['America/Denver', 'America/Mazatlan'], 'America/Chicago': ['America/Chicago', 'America/Mexico_City'], 'America/Santiago': ['America/Santiago', 'America/Asuncion', 'America/Campo_Grande'], 'America/Montevideo': ['America/Montevideo', 'America/Sao_Paulo'], 'Asia/Beirut': ['Asia/Amman', 'Asia/Jerusalem', 'Asia/Beirut', 'Europe/Helsinki','Asia/Damascus'], 'Pacific/Auckland': ['Pacific/Auckland', 'Pacific/Fiji'], 'America/Los_Angeles': ['America/Los_Angeles', 'America/Santa_Isabel'], 'America/New_York': ['America/Havana', 'America/New_York'], 'America/Halifax': ['America/Goose_Bay', 'America/Halifax'], 'America/Godthab': ['America/Miquelon', 'America/Godthab'], 'Asia/Dubai': ['Europe/Moscow'], 'Asia/Dhaka': ['Asia/Yekaterinburg'], 'Asia/Jakarta': ['Asia/Omsk'], 'Asia/Shanghai': ['Asia/Krasnoyarsk', 'Australia/Perth'], 'Asia/Tokyo': ['Asia/Irkutsk'], 'Australia/Brisbane': ['Asia/Yakutsk'], 'Pacific/Noumea': ['Asia/Vladivostok'], 'Pacific/Tarawa': ['Asia/Kamchatka', 'Pacific/Fiji'], 'Pacific/Tongatapu': ['Pacific/Apia'], 'Asia/Baghdad': ['Europe/Minsk'], 'Asia/Baku': ['Asia/Yerevan','Asia/Baku'], 'Africa/Johannesburg': ['Asia/Gaza', 'Africa/Cairo'] }, timezone_name = tz_name, /** * Checks if a timezone has possible ambiguities. I.e timezones that are similar. * * For example, if the preliminary scan determines that we're in America/Denver. * We double check here that we're really there and not in America/Mazatlan. * * This is done by checking known dates for when daylight savings start for different * timezones during 2010 and 2011. */ ambiguity_check = function () { var ambiguity_list = AMBIGUITIES[timezone_name], length = ambiguity_list.length, i = 0, tz = ambiguity_list[0]; for (; i < length; i += 1) { tz = ambiguity_list[i]; if (jstz.date_is_dst(jstz.dst_start_for(tz))) { timezone_name = tz; return; } } }, /** * Checks if it is possible that the timezone is ambiguous. */ is_ambiguous = function () { return typeof (AMBIGUITIES[timezone_name]) !== 'undefined'; }; if (is_ambiguous()) { ambiguity_check(); } return { name: function () { return timezone_name; } }; }; jstz.olson = {}; /* * The keys in this dictionary are comma separated as such: * * First the offset compared to UTC time in minutes. * * Then a flag which is 0 if the timezone does not take daylight savings into account and 1 if it * does. * * Thirdly an optional 's' signifies that the timezone is in the southern hemisphere, * only interesting for timezones with DST. * * The mapped arrays is used for constructing the jstz.TimeZone object from within * jstz.determine_timezone(); */ jstz.olson.timezones = { '-720,0' : 'Pacific/Majuro', '-660,0' : 'Pacific/Pago_Pago', '-600,1' : 'America/Adak', '-600,0' : 'Pacific/Honolulu', '-570,0' : 'Pacific/Marquesas', '-540,0' : 'Pacific/Gambier', '-540,1' : 'America/Anchorage', '-480,1' : 'America/Los_Angeles', '-480,0' : 'Pacific/Pitcairn', '-420,0' : 'America/Phoenix', '-420,1' : 'America/Denver', '-360,0' : 'America/Guatemala', '-360,1' : 'America/Chicago', '-360,1,s' : 'Pacific/Easter', '-300,0' : 'America/Bogota', '-300,1' : 'America/New_York', '-270,0' : 'America/Caracas', '-240,1' : 'America/Halifax', '-240,0' : 'America/Santo_Domingo', '-240,1,s' : 'America/Santiago', '-210,1' : 'America/St_Johns', '-180,1' : 'America/Godthab', '-180,0' : 'America/Argentina/Buenos_Aires', '-180,1,s' : 'America/Montevideo', '-120,0' : 'America/Noronha', '-120,1' : 'America/Noronha', '-60,1' : 'Atlantic/Azores', '-60,0' : 'Atlantic/Cape_Verde', '0,0' : 'Etc/UTC', '0,1' : 'Europe/London', '60,1' : 'Europe/Berlin', '60,0' : 'Africa/Lagos', '60,1,s' : 'Africa/Windhoek', '120,1' : 'Asia/Beirut', '120,0' : 'Africa/Johannesburg', '180,0' : 'Asia/Baghdad', '180,1' : 'Europe/Moscow', '210,1' : 'Asia/Tehran', '240,0' : 'Asia/Dubai', '240,1' : 'Asia/Baku', '270,0' : 'Asia/Kabul', '300,1' : 'Asia/Yekaterinburg', '300,0' : 'Asia/Karachi', '330,0' : 'Asia/Kolkata', '345,0' : 'Asia/Kathmandu', '360,0' : 'Asia/Dhaka', '360,1' : 'Asia/Omsk', '390,0' : 'Asia/Rangoon', '420,1' : 'Asia/Krasnoyarsk', '420,0' : 'Asia/Jakarta', '480,0' : 'Asia/Shanghai', '480,1' : 'Asia/Irkutsk', '525,0' : 'Australia/Eucla', '525,1,s' : 'Australia/Eucla', '540,1' : 'Asia/Yakutsk', '540,0' : 'Asia/Tokyo', '570,0' : 'Australia/Darwin', '570,1,s' : 'Australia/Adelaide', '600,0' : 'Australia/Brisbane', '600,1' : 'Asia/Vladivostok', '600,1,s' : 'Australia/Sydney', '630,1,s' : 'Australia/Lord_Howe', '660,1' : 'Asia/Kamchatka', '660,0' : 'Pacific/Noumea', '690,0' : 'Pacific/Norfolk', '720,1,s' : 'Pacific/Auckland', '720,0' : 'Pacific/Tarawa', '765,1,s' : 'Pacific/Chatham', '780,0' : 'Pacific/Tongatapu', '780,1,s' : 'Pacific/Apia', '840,0' : 'Pacific/Kiritimati' }; if (typeof exports !== 'undefined') { exports.jstz = jstz; } else { root.jstz = jstz; } })(this);