From f2ea243d31844b78a008794e92d24e66b239eb32 Mon Sep 17 00:00:00 2001 From: Timur Valeev Date: Tue, 24 May 2016 10:59:08 +0500 Subject: [PATCH 1/4] Upgrade to Rails 4.1 --- jstz-rails.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jstz-rails.gemspec b/jstz-rails.gemspec index 5477d6d..dd570bc 100644 --- a/jstz-rails.gemspec +++ b/jstz-rails.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |gem| gem.homepage = "http://rubygems.org/gems/jstz-rails" gem.files = Dir["{lib,vendor}/**/*"] + ["LICENSE", "README.md"] - gem.add_dependency "railties", ">= 3.1" + gem.add_dependency "railties", ">= 4.1" gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.name = "jstz-rails" From d50b168cf429033d47fbe66105085a9a6b5c41c2 Mon Sep 17 00:00:00 2001 From: Timur Valeev Date: Tue, 24 May 2016 11:03:03 +0500 Subject: [PATCH 2/4] Update jstz.js to 1.0.6 --- vendor/assets/javascripts/jstz.js | 1757 +++++++++++++++++++++++------ 1 file changed, 1428 insertions(+), 329 deletions(-) diff --git a/vendor/assets/javascripts/jstz.js b/vendor/assets/javascripts/jstz.js index 61881e0..44cc398 100644 --- a/vendor/assets/javascripts/jstz.js +++ b/vendor/assets/javascripts/jstz.js @@ -1,334 +1,1433 @@ -/*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.setDate(date); - d.setMonth(month); - 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 savings 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 base_offset = ((date.getMonth() > 7 ? get_june_offset(date.getFullYear()) - : get_january_offset(date.getFullYear()))), - date_offset = get_date_offset(date); - - - return (base_offset - date_offset) !== 0; - }, - - /** - * This function does some basic calculations to create information about - * the user's timezone. - * - * Returns a key that can be used to do lookups in jstz.olson.timezones. - * - * @returns {String} - */ - - lookup_key = function () { - var january_offset = get_january_offset(), - june_offset = get_june_offset(), - diff = get_january_offset() - get_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), - 'Asia/Beirut': new Date(2011, 2, 27, 1, 0, 0, 0), - 'Europe/Helsinki': new Date(2011, 2, 27, 4, 0, 0, 0), - 'Europe/Istanbul': new Date(2011, 2, 28, 5, 0, 0, 0), - 'Asia/Damascus': new Date(2011, 3, 1, 2, 0, 0, 0), - 'Asia/Jerusalem': new Date(2011, 3, 1, 6, 0, 0, 0), - 'Asia/Gaza': new Date(2009, 2, 28, 0, 30, 0, 0), - 'Africa/Cairo': new Date(2009, 3, 25, 0, 30, 0, 0), - 'Pacific/Auckland': new Date(2011, 8, 26, 7, 0, 0, 0), - 'Pacific/Fiji': new Date(2010, 11, 29, 23, 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/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/Kamchatka': ru_pre_dst_change, - 'Europe/Minsk': ru_pre_dst_change, - 'Australia/Perth': new Date(2008, 10, 1, 1, 0, 0, 0) +(function (root) {/*global exports, Intl*/ +/** + * This script gives you the zone info key representing your device's time zone setting. + * + * @name jsTimezoneDetect + * @version 1.0.6 + * @author Jon Nylander + * @license MIT License - https://bitbucket.org/pellepim/jstimezonedetect/src/default/LICENCE.txt + * + * For usage and examples, visit: + * http://pellepim.bitbucket.org/jstz/ + * + * Copyright (c) Jon Nylander + */ + + +/** + * Namespace to hold all the code for timezone detection. + */ +var jstz = (function () { + 'use strict'; + var HEMISPHERE_SOUTH = 's', + + consts = { + DAY: 86400000, + HOUR: 3600000, + MINUTE: 60000, + SECOND: 1000, + BASELINE_YEAR: 2014, + MAX_SCORE: 864000000, // 10 days + AMBIGUITIES: { + 'America/Denver': ['America/Mazatlan'], + 'Europe/London': ['Africa/Casablanca'], + 'America/Chicago': ['America/Mexico_City'], + 'America/Asuncion': ['America/Campo_Grande', 'America/Santiago'], + 'America/Montevideo': ['America/Sao_Paulo', 'America/Santiago'], + // Europe/Minsk should not be in this list... but Windows. + 'Asia/Beirut': ['Asia/Amman', 'Asia/Jerusalem', 'Europe/Helsinki', 'Asia/Damascus', 'Africa/Cairo', 'Asia/Gaza', 'Europe/Minsk'], + 'Pacific/Auckland': ['Pacific/Fiji'], + 'America/Los_Angeles': ['America/Santa_Isabel'], + 'America/New_York': ['America/Havana'], + 'America/Halifax': ['America/Goose_Bay'], + 'America/Godthab': ['America/Miquelon'], + 'Asia/Dubai': ['Asia/Yerevan'], + 'Asia/Jakarta': ['Asia/Krasnoyarsk'], + 'Asia/Shanghai': ['Asia/Irkutsk', 'Australia/Perth'], + 'Australia/Sydney': ['Australia/Lord_Howe'], + 'Asia/Tokyo': ['Asia/Yakutsk'], + 'Asia/Dhaka': ['Asia/Omsk'], + // In the real world Yerevan is not ambigous for Baku... but Windows. + 'Asia/Baku': ['Asia/Yerevan'], + 'Australia/Brisbane': ['Asia/Vladivostok'], + 'Pacific/Noumea': ['Asia/Vladivostok'], + 'Pacific/Majuro': ['Asia/Kamchatka', 'Pacific/Fiji'], + 'Pacific/Tongatapu': ['Pacific/Apia'], + 'Asia/Baghdad': ['Europe/Minsk', 'Europe/Moscow'], + 'Asia/Karachi': ['Asia/Yekaterinburg'], + 'Africa/Johannesburg': ['Asia/Gaza', 'Africa/Cairo'] + } + }, + + /** + * Gets the offset in minutes from UTC for a certain date. + * @param {Date} date + * @returns {Number} + */ + get_date_offset = function get_date_offset(date) { + var offset = -date.getTimezoneOffset(); + return (offset !== null ? 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 lookup_key() { + var january_offset = get_date_offset(new Date(consts.BASELINE_YEAR, 0, 2)), + june_offset = get_date_offset(new Date(consts.BASELINE_YEAR, 5, 2)), + 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"; + }, + + + /** + * Tries to get the time zone key directly from the operating system for those + * environments that support the ECMAScript Internationalization API. + */ + get_from_internationalization_api = function get_from_internationalization_api() { + var format, timezone; + if (typeof Intl === "undefined" || typeof Intl.DateTimeFormat === "undefined") { + return; + } + + format = Intl.DateTimeFormat(); + + if (typeof format === "undefined" || typeof format.resolvedOptions === "undefined") { + return; + } + + timezone = format.resolvedOptions().timeZone; + + if (timezone && (timezone.indexOf("/") > -1 || timezone === 'UTC')) { + return timezone; + } + + }, + + /** + * Starting point for getting all the DST rules for a specific year + * for the current timezone (as described by the client system). + * + * Returns an object with start and end attributes, or false if no + * DST rules were found for the year. + * + * @param year + * @returns {Object} || {Boolean} + */ + dst_dates = function dst_dates(year) { + var yearstart = new Date(year, 0, 1, 0, 0, 1, 0).getTime(); + var yearend = new Date(year, 12, 31, 23, 59, 59).getTime(); + var current = yearstart; + var offset = (new Date(current)).getTimezoneOffset(); + var dst_start = null; + var dst_end = null; + + while (current < yearend - 86400000) { + var dateToCheck = new Date(current); + var dateToCheckOffset = dateToCheck.getTimezoneOffset(); + + if (dateToCheckOffset !== offset) { + if (dateToCheckOffset < offset) { + dst_start = dateToCheck; + } + if (dateToCheckOffset > offset) { + dst_end = dateToCheck; + } + offset = dateToCheckOffset; + } + + current += 86400000; + } + + if (dst_start && dst_end) { + return { + s: find_dst_fold(dst_start).getTime(), + e: find_dst_fold(dst_end).getTime() }; + } + + return false; + }, + + /** + * Probably completely unnecessary function that recursively finds the + * exact (to the second) time when a DST rule was changed. + * + * @param a_date - The candidate Date. + * @param padding - integer specifying the padding to allow around the candidate + * date for finding the fold. + * @param iterator - integer specifying how many milliseconds to iterate while + * searching for the fold. + * + * @returns {Date} + */ + find_dst_fold = function find_dst_fold(a_date, padding, iterator) { + if (typeof padding === 'undefined') { + padding = consts.DAY; + iterator = consts.HOUR; + } + + var date_start = new Date(a_date.getTime() - padding).getTime(); + var date_end = a_date.getTime() + padding; + var offset = new Date(date_start).getTimezoneOffset(); + + var current = date_start; + + var dst_change = null; + while (current < date_end - iterator) { + var dateToCheck = new Date(current); + var dateToCheckOffset = dateToCheck.getTimezoneOffset(); + + if (dateToCheckOffset !== offset) { + dst_change = dateToCheck; + break; + } + current += iterator; + } + + if (padding === consts.DAY) { + return find_dst_fold(dst_change, consts.HOUR, consts.MINUTE); + } + + if (padding === consts.HOUR) { + return find_dst_fold(dst_change, consts.MINUTE, consts.SECOND); + } + + return dst_change; + }, + + windows7_adaptations = function windows7_adaptions(rule_list, preliminary_timezone, score, sample) { + if (score !== 'N/A') { + return score; + } + if (preliminary_timezone === 'Asia/Beirut') { + if (sample.name === 'Africa/Cairo') { + if (rule_list[6].s === 1398376800000 && rule_list[6].e === 1411678800000) { + return 0; + } + } + if (sample.name === 'Asia/Jerusalem') { + if (rule_list[6].s === 1395964800000 && rule_list[6].e === 1411858800000) { + return 0; + } + } + } else if (preliminary_timezone === 'America/Santiago') { + if (sample.name === 'America/Asuncion') { + if (rule_list[6].s === 1412481600000 && rule_list[6].e === 1397358000000) { + return 0; + } + } + if (sample.name === 'America/Campo_Grande') { + if (rule_list[6].s === 1413691200000 && rule_list[6].e === 1392519600000) { + return 0; + } + } + } else if (preliminary_timezone === 'America/Montevideo') { + if (sample.name === 'America/Sao_Paulo') { + if (rule_list[6].s === 1413687600000 && rule_list[6].e === 1392516000000) { + return 0; + } + } + } else if (preliminary_timezone === 'Pacific/Auckland') { + if (sample.name === 'Pacific/Fiji') { + if (rule_list[6].s === 1414245600000 && rule_list[6].e === 1396101600000) { + return 0; + } + } + } + + return score; + }, + + /** + * Takes the DST rules for the current timezone, and proceeds to find matches + * in the jstz.olson.dst_rules.zones array. + * + * Compares samples to the current timezone on a scoring basis. + * + * Candidates are ruled immediately if either the candidate or the current zone + * has a DST rule where the other does not. + * + * Candidates are ruled out immediately if the current zone has a rule that is + * outside the DST scope of the candidate. + * + * Candidates are included for scoring if the current zones rules fall within the + * span of the samples rules. + * + * Low score is best, the score is calculated by summing up the differences in DST + * rules and if the consts.MAX_SCORE is overreached the candidate is ruled out. + * + * Yah follow? :) + * + * @param rule_list + * @param preliminary_timezone + * @returns {*} + */ + best_dst_match = function best_dst_match(rule_list, preliminary_timezone) { + var score_sample = function score_sample(sample) { + var score = 0; + + for (var j = 0; j < rule_list.length; j++) { + + // Both sample and current time zone report DST during the year. + if (!!sample.rules[j] && !!rule_list[j]) { + + // The current time zone's DST rules are inside the sample's. Include. + if (rule_list[j].s >= sample.rules[j].s && rule_list[j].e <= sample.rules[j].e) { + score = 0; + score += Math.abs(rule_list[j].s - sample.rules[j].s); + score += Math.abs(sample.rules[j].e - rule_list[j].e); + + // The current time zone's DST rules are outside the sample's. Discard. + } else { + score = 'N/A'; + break; + } + + // The max score has been reached. Discard. + if (score > consts.MAX_SCORE) { + score = 'N/A'; + break; + } + } + } + + score = windows7_adaptations(rule_list, preliminary_timezone, score, sample); + + return score; + }; + var scoreboard = {}; + var dst_zones = jstz.olson.dst_rules.zones; + var dst_zones_length = dst_zones.length; + var ambiguities = consts.AMBIGUITIES[preliminary_timezone]; + + for (var i = 0; i < dst_zones_length; i++) { + var sample = dst_zones[i]; + var score = score_sample(dst_zones[i]); + + if (score !== 'N/A') { + scoreboard[sample.name] = score; + } + } + + for (var tz in scoreboard) { + if (scoreboard.hasOwnProperty(tz)) { + for (var j = 0; j < ambiguities.length; j++) { + if (ambiguities[j] === tz) { + return tz; + } + } + } + } + + return preliminary_timezone; + }, - 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. + * Takes the preliminary_timezone as detected by lookup_key(). + * + * Builds up the current timezones DST rules for the years defined + * in the jstz.olson.dst_rules.years array. + * + * If there are no DST occurences for those years, immediately returns + * the preliminary timezone. Otherwise proceeds and tries to solve + * ambiguities. * - * The array of timezones to compare must be in the order that daylight savings - * starts for the regions. - * - * @TODO: Once 2013 is upon us, remove Asia/Gaza from the Beirut ambiguity list, - * by then it should suffice that it lives in the Africa/Johannesburg check. + * @param preliminary_timezone + * @returns {String} timezone_name */ - 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/Beirut', 'Europe/Helsinki', 'Europe/Istanbul', 'Asia/Damascus', 'Asia/Jerusalem', 'Asia/Gaza'], - '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'], - 'Africa/Johannesburg': ['Asia/Gaza', 'Africa/Cairo'], - 'Asia/Baghdad': ['Europe/Minsk'] - }, - - 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' : 'Etc/GMT+12', - '-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' : 'Etc/GMT+2', - '-120,1' : 'Etc/GMT+2', - '-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); + get_by_dst = function get_by_dst(preliminary_timezone) { + var get_rules = function get_rules() { + var rule_list = []; + for (var i = 0; i < jstz.olson.dst_rules.years.length; i++) { + var year_rules = dst_dates(jstz.olson.dst_rules.years[i]); + rule_list.push(year_rules); + } + return rule_list; + }; + var check_has_dst = function check_has_dst(rules) { + for (var i = 0; i < rules.length; i++) { + if (rules[i] !== false) { + return true; + } + } + return false; + }; + var rules = get_rules(); + var has_dst = check_has_dst(rules); + + if (has_dst) { + return best_dst_match(rules, preliminary_timezone); + } + + return preliminary_timezone; + }, + + /** + * Uses get_timezone_info() to formulate a key to use in the olson.timezones dictionary. + * + * Returns an object with one function ".name()" + * + * @returns Object + */ + determine = function determine() { + var preliminary_tz = get_from_internationalization_api(); + + if (!preliminary_tz) { + preliminary_tz = jstz.olson.timezones[lookup_key()]; + + if (typeof consts.AMBIGUITIES[preliminary_tz] !== 'undefined') { + preliminary_tz = get_by_dst(preliminary_tz); + } + } + + return { + name: function () { + return preliminary_tz; + } + }; + }; + + return { + determine: determine + }; +}()); + + +jstz.olson = 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(); + */ +jstz.olson.timezones = { + '-720,0': 'Etc/GMT+12', + '-660,0': 'Pacific/Pago_Pago', + '-660,1,s': 'Pacific/Apia', // Why? Because windows... cry! + '-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/Asuncion', + '-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': '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/Majuro', + '765,1,s': 'Pacific/Chatham', + '780,0': 'Pacific/Tongatapu', + '780,1,s': 'Pacific/Apia', + '840,0': 'Pacific/Kiritimati' +}; + +/* Build time: 2015-11-02 13:01:00Z Build by invoking python utilities/dst.py generate */ +jstz.olson.dst_rules = { + "years": [ + 2008, + 2009, + 2010, + 2011, + 2012, + 2013, + 2014 + ], + "zones": [ + { + "name": "Africa/Cairo", + "rules": [ + { + "e": 1219957200000, + "s": 1209074400000 + }, + { + "e": 1250802000000, + "s": 1240524000000 + }, + { + "e": 1285880400000, + "s": 1284069600000 + }, + false, + false, + false, + { + "e": 1411678800000, + "s": 1406844000000 + } + ] + }, + { + "name": "Africa/Casablanca", + "rules": [ + { + "e": 1220223600000, + "s": 1212278400000 + }, + { + "e": 1250809200000, + "s": 1243814400000 + }, + { + "e": 1281222000000, + "s": 1272758400000 + }, + { + "e": 1312066800000, + "s": 1301788800000 + }, + { + "e": 1348970400000, + "s": 1345428000000 + }, + { + "e": 1382839200000, + "s": 1376100000000 + }, + { + "e": 1414288800000, + "s": 1406944800000 + } + ] + }, + { + "name": "America/Asuncion", + "rules": [ + { + "e": 1205031600000, + "s": 1224388800000 + }, + { + "e": 1236481200000, + "s": 1255838400000 + }, + { + "e": 1270954800000, + "s": 1286078400000 + }, + { + "e": 1302404400000, + "s": 1317528000000 + }, + { + "e": 1333854000000, + "s": 1349582400000 + }, + { + "e": 1364094000000, + "s": 1381032000000 + }, + { + "e": 1395543600000, + "s": 1412481600000 + } + ] + }, + { + "name": "America/Campo_Grande", + "rules": [ + { + "e": 1203217200000, + "s": 1224388800000 + }, + { + "e": 1234666800000, + "s": 1255838400000 + }, + { + "e": 1266721200000, + "s": 1287288000000 + }, + { + "e": 1298170800000, + "s": 1318737600000 + }, + { + "e": 1330225200000, + "s": 1350792000000 + }, + { + "e": 1361070000000, + "s": 1382241600000 + }, + { + "e": 1392519600000, + "s": 1413691200000 + } + ] + }, + { + "name": "America/Goose_Bay", + "rules": [ + { + "e": 1225594860000, + "s": 1205035260000 + }, + { + "e": 1257044460000, + "s": 1236484860000 + }, + { + "e": 1289098860000, + "s": 1268539260000 + }, + { + "e": 1320555600000, + "s": 1299988860000 + }, + { + "e": 1352005200000, + "s": 1331445600000 + }, + { + "e": 1383454800000, + "s": 1362895200000 + }, + { + "e": 1414904400000, + "s": 1394344800000 + } + ] + }, + { + "name": "America/Havana", + "rules": [ + { + "e": 1224997200000, + "s": 1205643600000 + }, + { + "e": 1256446800000, + "s": 1236488400000 + }, + { + "e": 1288501200000, + "s": 1268542800000 + }, + { + "e": 1321160400000, + "s": 1300597200000 + }, + { + "e": 1352005200000, + "s": 1333256400000 + }, + { + "e": 1383454800000, + "s": 1362891600000 + }, + { + "e": 1414904400000, + "s": 1394341200000 + } + ] + }, + { + "name": "America/Mazatlan", + "rules": [ + { + "e": 1225008000000, + "s": 1207472400000 + }, + { + "e": 1256457600000, + "s": 1238922000000 + }, + { + "e": 1288512000000, + "s": 1270371600000 + }, + { + "e": 1319961600000, + "s": 1301821200000 + }, + { + "e": 1351411200000, + "s": 1333270800000 + }, + { + "e": 1382860800000, + "s": 1365325200000 + }, + { + "e": 1414310400000, + "s": 1396774800000 + } + ] + }, + { + "name": "America/Mexico_City", + "rules": [ + { + "e": 1225004400000, + "s": 1207468800000 + }, + { + "e": 1256454000000, + "s": 1238918400000 + }, + { + "e": 1288508400000, + "s": 1270368000000 + }, + { + "e": 1319958000000, + "s": 1301817600000 + }, + { + "e": 1351407600000, + "s": 1333267200000 + }, + { + "e": 1382857200000, + "s": 1365321600000 + }, + { + "e": 1414306800000, + "s": 1396771200000 + } + ] + }, + { + "name": "America/Miquelon", + "rules": [ + { + "e": 1225598400000, + "s": 1205038800000 + }, + { + "e": 1257048000000, + "s": 1236488400000 + }, + { + "e": 1289102400000, + "s": 1268542800000 + }, + { + "e": 1320552000000, + "s": 1299992400000 + }, + { + "e": 1352001600000, + "s": 1331442000000 + }, + { + "e": 1383451200000, + "s": 1362891600000 + }, + { + "e": 1414900800000, + "s": 1394341200000 + } + ] + }, + { + "name": "America/Santa_Isabel", + "rules": [ + { + "e": 1225011600000, + "s": 1207476000000 + }, + { + "e": 1256461200000, + "s": 1238925600000 + }, + { + "e": 1288515600000, + "s": 1270375200000 + }, + { + "e": 1319965200000, + "s": 1301824800000 + }, + { + "e": 1351414800000, + "s": 1333274400000 + }, + { + "e": 1382864400000, + "s": 1365328800000 + }, + { + "e": 1414314000000, + "s": 1396778400000 + } + ] + }, + { + "name": "America/Santiago", + "rules": [ + { + "e": 1206846000000, + "s": 1223784000000 + }, + { + "e": 1237086000000, + "s": 1255233600000 + }, + { + "e": 1270350000000, + "s": 1286683200000 + }, + { + "e": 1304823600000, + "s": 1313899200000 + }, + { + "e": 1335668400000, + "s": 1346558400000 + }, + { + "e": 1367118000000, + "s": 1378612800000 + }, + { + "e": 1398567600000, + "s": 1410062400000 + } + ] + }, + { + "name": "America/Sao_Paulo", + "rules": [ + { + "e": 1203213600000, + "s": 1224385200000 + }, + { + "e": 1234663200000, + "s": 1255834800000 + }, + { + "e": 1266717600000, + "s": 1287284400000 + }, + { + "e": 1298167200000, + "s": 1318734000000 + }, + { + "e": 1330221600000, + "s": 1350788400000 + }, + { + "e": 1361066400000, + "s": 1382238000000 + }, + { + "e": 1392516000000, + "s": 1413687600000 + } + ] + }, + { + "name": "Asia/Amman", + "rules": [ + { + "e": 1225404000000, + "s": 1206655200000 + }, + { + "e": 1256853600000, + "s": 1238104800000 + }, + { + "e": 1288303200000, + "s": 1269554400000 + }, + { + "e": 1319752800000, + "s": 1301608800000 + }, + false, + false, + { + "e": 1414706400000, + "s": 1395957600000 + } + ] + }, + { + "name": "Asia/Damascus", + "rules": [ + { + "e": 1225486800000, + "s": 1207260000000 + }, + { + "e": 1256850000000, + "s": 1238104800000 + }, + { + "e": 1288299600000, + "s": 1270159200000 + }, + { + "e": 1319749200000, + "s": 1301608800000 + }, + { + "e": 1351198800000, + "s": 1333058400000 + }, + { + "e": 1382648400000, + "s": 1364508000000 + }, + { + "e": 1414702800000, + "s": 1395957600000 + } + ] + }, + { + "name": "Asia/Dubai", + "rules": [ + false, + false, + false, + false, + false, + false, + false + ] + }, + { + "name": "Asia/Gaza", + "rules": [ + { + "e": 1219957200000, + "s": 1206655200000 + }, + { + "e": 1252015200000, + "s": 1238104800000 + }, + { + "e": 1281474000000, + "s": 1269640860000 + }, + { + "e": 1312146000000, + "s": 1301608860000 + }, + { + "e": 1348178400000, + "s": 1333058400000 + }, + { + "e": 1380229200000, + "s": 1364508000000 + }, + { + "e": 1414098000000, + "s": 1395957600000 + } + ] + }, + { + "name": "Asia/Irkutsk", + "rules": [ + { + "e": 1224957600000, + "s": 1206813600000 + }, + { + "e": 1256407200000, + "s": 1238263200000 + }, + { + "e": 1288461600000, + "s": 1269712800000 + }, + false, + false, + false, + false + ] + }, + { + "name": "Asia/Jerusalem", + "rules": [ + { + "e": 1223161200000, + "s": 1206662400000 + }, + { + "e": 1254006000000, + "s": 1238112000000 + }, + { + "e": 1284246000000, + "s": 1269561600000 + }, + { + "e": 1317510000000, + "s": 1301616000000 + }, + { + "e": 1348354800000, + "s": 1333065600000 + }, + { + "e": 1382828400000, + "s": 1364515200000 + }, + { + "e": 1414278000000, + "s": 1395964800000 + } + ] + }, + { + "name": "Asia/Kamchatka", + "rules": [ + { + "e": 1224943200000, + "s": 1206799200000 + }, + { + "e": 1256392800000, + "s": 1238248800000 + }, + { + "e": 1288450800000, + "s": 1269698400000 + }, + false, + false, + false, + false + ] + }, + { + "name": "Asia/Krasnoyarsk", + "rules": [ + { + "e": 1224961200000, + "s": 1206817200000 + }, + { + "e": 1256410800000, + "s": 1238266800000 + }, + { + "e": 1288465200000, + "s": 1269716400000 + }, + false, + false, + false, + false + ] + }, + { + "name": "Asia/Omsk", + "rules": [ + { + "e": 1224964800000, + "s": 1206820800000 + }, + { + "e": 1256414400000, + "s": 1238270400000 + }, + { + "e": 1288468800000, + "s": 1269720000000 + }, + false, + false, + false, + false + ] + }, + { + "name": "Asia/Vladivostok", + "rules": [ + { + "e": 1224950400000, + "s": 1206806400000 + }, + { + "e": 1256400000000, + "s": 1238256000000 + }, + { + "e": 1288454400000, + "s": 1269705600000 + }, + false, + false, + false, + false + ] + }, + { + "name": "Asia/Yakutsk", + "rules": [ + { + "e": 1224954000000, + "s": 1206810000000 + }, + { + "e": 1256403600000, + "s": 1238259600000 + }, + { + "e": 1288458000000, + "s": 1269709200000 + }, + false, + false, + false, + false + ] + }, + { + "name": "Asia/Yekaterinburg", + "rules": [ + { + "e": 1224968400000, + "s": 1206824400000 + }, + { + "e": 1256418000000, + "s": 1238274000000 + }, + { + "e": 1288472400000, + "s": 1269723600000 + }, + false, + false, + false, + false + ] + }, + { + "name": "Asia/Yerevan", + "rules": [ + { + "e": 1224972000000, + "s": 1206828000000 + }, + { + "e": 1256421600000, + "s": 1238277600000 + }, + { + "e": 1288476000000, + "s": 1269727200000 + }, + { + "e": 1319925600000, + "s": 1301176800000 + }, + false, + false, + false + ] + }, + { + "name": "Australia/Lord_Howe", + "rules": [ + { + "e": 1207407600000, + "s": 1223134200000 + }, + { + "e": 1238857200000, + "s": 1254583800000 + }, + { + "e": 1270306800000, + "s": 1286033400000 + }, + { + "e": 1301756400000, + "s": 1317483000000 + }, + { + "e": 1333206000000, + "s": 1349537400000 + }, + { + "e": 1365260400000, + "s": 1380987000000 + }, + { + "e": 1396710000000, + "s": 1412436600000 + } + ] + }, + { + "name": "Australia/Perth", + "rules": [ + { + "e": 1206813600000, + "s": 1224957600000 + }, + false, + false, + false, + false, + false, + false + ] + }, + { + "name": "Europe/Helsinki", + "rules": [ + { + "e": 1224982800000, + "s": 1206838800000 + }, + { + "e": 1256432400000, + "s": 1238288400000 + }, + { + "e": 1288486800000, + "s": 1269738000000 + }, + { + "e": 1319936400000, + "s": 1301187600000 + }, + { + "e": 1351386000000, + "s": 1332637200000 + }, + { + "e": 1382835600000, + "s": 1364691600000 + }, + { + "e": 1414285200000, + "s": 1396141200000 + } + ] + }, + { + "name": "Europe/Minsk", + "rules": [ + { + "e": 1224979200000, + "s": 1206835200000 + }, + { + "e": 1256428800000, + "s": 1238284800000 + }, + { + "e": 1288483200000, + "s": 1269734400000 + }, + false, + false, + false, + false + ] + }, + { + "name": "Europe/Moscow", + "rules": [ + { + "e": 1224975600000, + "s": 1206831600000 + }, + { + "e": 1256425200000, + "s": 1238281200000 + }, + { + "e": 1288479600000, + "s": 1269730800000 + }, + false, + false, + false, + false + ] + }, + { + "name": "Pacific/Apia", + "rules": [ + false, + false, + false, + { + "e": 1301752800000, + "s": 1316872800000 + }, + { + "e": 1333202400000, + "s": 1348927200000 + }, + { + "e": 1365256800000, + "s": 1380376800000 + }, + { + "e": 1396706400000, + "s": 1411826400000 + } + ] + }, + { + "name": "Pacific/Fiji", + "rules": [ + false, + false, + { + "e": 1269698400000, + "s": 1287842400000 + }, + { + "e": 1327154400000, + "s": 1319292000000 + }, + { + "e": 1358604000000, + "s": 1350741600000 + }, + { + "e": 1390050000000, + "s": 1382796000000 + }, + { + "e": 1421503200000, + "s": 1414850400000 + } + ] + }, + { + "name": "Europe/London", + "rules": [ + { + "e": 1224982800000, + "s": 1206838800000 + }, + { + "e": 1256432400000, + "s": 1238288400000 + }, + { + "e": 1288486800000, + "s": 1269738000000 + }, + { + "e": 1319936400000, + "s": 1301187600000 + }, + { + "e": 1351386000000, + "s": 1332637200000 + }, + { + "e": 1382835600000, + "s": 1364691600000 + }, + { + "e": 1414285200000, + "s": 1396141200000 + } + ] + } + ] +}; +if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = jstz; +} else if ((typeof define !== 'undefined' && define !== null) && (define.amd != null)) { + define([], function() { + return jstz; + }); +} else { + if (typeof root === 'undefined') { + window.jstz = jstz; + } else { + root.jstz = jstz; + } +} +}()); From fc1b95b68423a4bcafc156c1b2dc61c5dfbb576c Mon Sep 17 00:00:00 2001 From: Timur Valeev Date: Tue, 24 May 2016 11:05:57 +0500 Subject: [PATCH 3/4] Version bump --- lib/jstz-rails/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jstz-rails/version.rb b/lib/jstz-rails/version.rb index 987c742..2372e80 100644 --- a/lib/jstz-rails/version.rb +++ b/lib/jstz-rails/version.rb @@ -1,5 +1,5 @@ module Jstz module Rails - VERSION = "1.0.4.1" + VERSION = "1.0.6" end end From 11bf98460de3e4298e8304be95393faf46c5bb73 Mon Sep 17 00:00:00 2001 From: Timur Valeev Date: Tue, 24 May 2016 11:25:06 +0500 Subject: [PATCH 4/4] Update README.md --- README.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b6d1f55..f0671a0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Jstz::Rails -This is [jstz.js aka jsTimezoneDetect](https://bitbucket.org/pellepim/jstimezonedetect/) GEMified for the Rails >= 3.1 asset pipeline through the following: +This is [jstz.js aka jsTimezoneDetect](https://bitbucket.org/pellepim/jstimezonedetect/) GEMified for the Rails >= 4.1 asset pipeline through the following: bundle gem jstz-rails cd jstz-rails @@ -57,20 +57,31 @@ Or install it yourself as: Add to **application.js** - //= require jstz.js + //= require jstz Add to **your.js** to write browser detected timezone to a cookie - - document.cookie = 'time_zone='+jstz.determine().timezone.name()+';'; + + var timeZone = jstz.determine(); + document.cookie = 'time_zone='+timeZone.name()+';'; Add to **application_controller.rb** to set application's timezone from cookie before_filter :set_timezone private def set_timezone - Time.zone = cookies["time_zone"] + Time.zone = cookies[:time_zone] end +Another example of cookie usage in **application_controller.rb** + + around_action :set_timezone + private + def set_timezone + Time.use_zone(cookies[:time_zone]) do + yield + end + end + Or add to view to set default from cookie (e.g. simple_form) <%= f.input :time_zone, priority: /US/, :default => ActiveSupport::TimeZone.all.reject {|zone| zone.tzinfo != TZInfo::Timezone.get(cookies["time_zone"])}.first.name %>