Path: blob/trunk/third_party/closure/goog/i18n/timezone.js
2868 views
// Copyright 2008 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Functions to provide timezone information for use with16* date/time format.17*/1819goog.provide('goog.i18n.TimeZone');2021goog.require('goog.array');22/** @suppress {extraRequire} goog.date.DateLike represents a Date or a23* goog.Date object. It is a parameter in the following methods:24* - getDaylightAdjustment25* - getGMTString26* - getLongName27* - getOffset28* - getRFCTimeZoneString29* - getShortName30* - isDaylightTime31* - getLongNameGMT32* - getGenericLocation33* Lint warns that this require is unnecessary but the closure compiler needs34* it in order to accept a Date or a goog.Date object as a goog.date.DateLike35* parameter in any of these methods. */36goog.require('goog.date.DateLike');37goog.require('goog.object');38goog.require('goog.string');39404142/**43* TimeZone class implemented a time zone resolution and name information44* source for client applications. The time zone object is initiated from45* a time zone information object. Application can initiate a time zone46* statically, or it may choose to initiate from a data obtained from server.47* Each time zone information array is small, but the whole set of data48* is too much for client application to download. If end user is allowed to49* change time zone setting, dynamic retrieval should be the method to use.50* In case only time zone offset is known, there is a decent fallback51* that only use the time zone offset to create a TimeZone object.52* A whole set of time zone information array was available under53* http://go/js_locale_data. It is generated based on CLDR/ICU and54* Olson time zone data base, and will be updated timely.55*56* @constructor57* @final58*/59goog.i18n.TimeZone = function() {60/**61* The standard time zone id.62* @type {string}63* @private64*/65this.timeZoneId_;666768/**69* The standard, non-daylight time zone offset, in minutes WEST of UTC.70* @type {number}71* @private72*/73this.standardOffset_;747576/**77* An array of strings that can have 2 or 4 elements. The first two elements78* are the long and short names for standard time in this time zone, and the79* last two elements (if present) are the long and short names for daylight80* time in this time zone.81* @type {Array<string>}82* @private83*/84this.tzNames_;858687/**88* An object of 2 to 4 elements. The STD_* are always available, while the89* DST_* are only available when daylight saving time is available for this90* time zone.91* <ul>92* <li>STD_LONG_NAME_GMT: long GMT name for standard time</li>93* <li>STD_GENERIC_LOCATION: generic location for standard time</li>94* <li>DST_LONG_NAME_GMT: long GMT for daylight saving time</li>95* <li>DST_GENERIC_LOCATION: generic location for daylight saving time</li>96* </ul>97* @type { { STD_LONG_NAME_GMT:string, STD_GENERIC_LOCATION:string } |98* { STD_LONG_NAME_GMT:string, STD_GENERIC_LOCATION:string,99* DST_LONG_NAME_GMT:string, DST_GENERIC_LOCATION:string }100* }101* @private102*/103this.tzNamesExt_;104105106/**107* This array specifies the Daylight Saving Time transitions for this time108* zone. This is a flat array of numbers which are interpreted in pairs:109* [time1, adjustment1, time2, adjustment2, ...] where each time is a DST110* transition point given as a number of hours since 00:00 UTC, January 1,111* 1970, and each adjustment is the adjustment to apply for times after the112* DST transition, given as minutes EAST of UTC.113* @type {Array<number>}114* @private115*/116this.transitions_;117};118119120/**121* The number of milliseconds in an hour.122* @type {number}123* @private124*/125goog.i18n.TimeZone.MILLISECONDS_PER_HOUR_ = 3600 * 1000;126127128/**129* Indices into the array of time zone names.130* @enum {number}131*/132goog.i18n.TimeZone.NameType = {133STD_SHORT_NAME: 0,134STD_LONG_NAME: 1,135DLT_SHORT_NAME: 2,136DLT_LONG_NAME: 3137};138139140/**141* This factory method creates a time zone instance. It takes either an object142* containing complete time zone information, or a single number representing a143* constant time zone offset. If the latter form is used, DST functionality is144* not available.145*146* @param {number|Object} timeZoneData If this parameter is a number, it should147* indicate minutes WEST of UTC to be used as a constant time zone offset.148* Otherwise, it should be an object with these four fields:149* <ul>150* <li>id: A string ID for the time zone.151* <li>std_offset: The standard time zone offset in minutes EAST of UTC.152* <li>names: An array of four names (standard short name, standard long153* name, daylight short name, daylight long, name)154* <li>names_ext: A hash of four fields (standard long name gmt, daylight155* long name gmt, standard generic location, daylight generic156* location)157* <li>transitions: An array of numbers which are interpreted in pairs:158* [time1, adjustment1, time2, adjustment2, ...] where each time is159* a DST transition point given as a number of hours since 00:00 UTC,160* January 1, 1970, and each adjustment is the adjustment to apply161* for times after the DST transition, given as minutes EAST of UTC.162* </ul>163* @return {!goog.i18n.TimeZone} A goog.i18n.TimeZone object for the given164* time zone data.165*/166goog.i18n.TimeZone.createTimeZone = function(timeZoneData) {167if (typeof timeZoneData == 'number') {168return goog.i18n.TimeZone.createSimpleTimeZone_(timeZoneData);169}170var tz = new goog.i18n.TimeZone();171tz.timeZoneId_ = timeZoneData['id'];172tz.standardOffset_ = -timeZoneData['std_offset'];173tz.tzNames_ = timeZoneData['names'];174tz.tzNamesExt_ = timeZoneData['names_ext'];175tz.transitions_ = timeZoneData['transitions'];176return tz;177};178179180/**181* This factory method creates a time zone object with a constant offset.182* @param {number} timeZoneOffsetInMinutes Offset in minutes WEST of UTC.183* @return {!goog.i18n.TimeZone} A time zone object with the given constant184* offset. Note that the time zone ID of this object will use the POSIX185* convention, which has a reversed sign ("Etc/GMT+8" means UTC-8 or PST).186* @private187*/188goog.i18n.TimeZone.createSimpleTimeZone_ = function(timeZoneOffsetInMinutes) {189var tz = new goog.i18n.TimeZone();190tz.standardOffset_ = timeZoneOffsetInMinutes;191tz.timeZoneId_ =192goog.i18n.TimeZone.composePosixTimeZoneID_(timeZoneOffsetInMinutes);193var str = goog.i18n.TimeZone.composeUTCString_(timeZoneOffsetInMinutes);194var strGMT = goog.i18n.TimeZone.composeGMTString_(timeZoneOffsetInMinutes);195tz.tzNames_ = [str, str];196tz.tzNamesExt_ = {STD_LONG_NAME_GMT: strGMT, STD_GENERIC_LOCATION: strGMT};197tz.transitions_ = [];198return tz;199};200201202/**203* Generate a GMT-relative string for a constant time zone offset.204* @param {number} offset The time zone offset in minutes WEST of UTC.205* @return {string} The GMT string for this offset, which will indicate206* hours EAST of UTC.207* @private208*/209goog.i18n.TimeZone.composeGMTString_ = function(offset) {210var parts = ['GMT'];211parts.push(offset <= 0 ? '+' : '-');212offset = Math.abs(offset);213parts.push(214goog.string.padNumber(Math.floor(offset / 60) % 100, 2), ':',215goog.string.padNumber(offset % 60, 2));216return parts.join('');217};218219220/**221* Generate a POSIX time zone ID for a constant time zone offset.222* @param {number} offset The time zone offset in minutes WEST of UTC.223* @return {string} The POSIX time zone ID for this offset, which will indicate224* hours WEST of UTC.225* @private226*/227goog.i18n.TimeZone.composePosixTimeZoneID_ = function(offset) {228if (offset == 0) {229return 'Etc/GMT';230}231var parts = ['Etc/GMT', offset < 0 ? '-' : '+'];232offset = Math.abs(offset);233parts.push(Math.floor(offset / 60) % 100);234offset = offset % 60;235if (offset != 0) {236parts.push(':', goog.string.padNumber(offset, 2));237}238return parts.join('');239};240241242/**243* Generate a UTC-relative string for a constant time zone offset.244* @param {number} offset The time zone offset in minutes WEST of UTC.245* @return {string} The UTC string for this offset, which will indicate246* hours EAST of UTC.247* @private248*/249goog.i18n.TimeZone.composeUTCString_ = function(offset) {250if (offset == 0) {251return 'UTC';252}253var parts = ['UTC', offset < 0 ? '+' : '-'];254offset = Math.abs(offset);255parts.push(Math.floor(offset / 60) % 100);256offset = offset % 60;257if (offset != 0) {258parts.push(':', offset);259}260return parts.join('');261};262263264/**265* Convert the contents of time zone object to a timeZoneData object, suitable266* for passing to goog.i18n.TimeZone.createTimeZone.267* @return {!Object} A timeZoneData object (see the documentation for268* goog.i18n.TimeZone.createTimeZone).269*/270goog.i18n.TimeZone.prototype.getTimeZoneData = function() {271return {272'id': this.timeZoneId_,273'std_offset': -this.standardOffset_, // note createTimeZone flips the sign274'names': goog.array.clone(this.tzNames_), // avoid aliasing the array275'names_ext': goog.object.clone(this.tzNamesExt_), // avoid aliasing276'transitions': goog.array.clone(this.transitions_) // avoid aliasing277};278};279280281/**282* Return the DST adjustment to the time zone offset for a given time.283* While Daylight Saving Time is in effect, this number is positive.284* Otherwise, it is zero.285* @param {goog.date.DateLike} date The time to check.286* @return {number} The DST adjustment in minutes EAST of UTC.287*/288goog.i18n.TimeZone.prototype.getDaylightAdjustment = function(date) {289var timeInMs = Date.UTC(290date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),291date.getUTCHours(), date.getUTCMinutes());292var timeInHours = timeInMs / goog.i18n.TimeZone.MILLISECONDS_PER_HOUR_;293var index = 0;294while (index < this.transitions_.length &&295timeInHours >= this.transitions_[index]) {296index += 2;297}298return (index == 0) ? 0 : this.transitions_[index - 1];299};300301302/**303* Return the GMT representation of this time zone object.304* @param {goog.date.DateLike} date The date for which time to retrieve305* GMT string.306* @return {string} GMT representation string.307*/308goog.i18n.TimeZone.prototype.getGMTString = function(date) {309return goog.i18n.TimeZone.composeGMTString_(this.getOffset(date));310};311312313/**314* Get the long time zone name for a given date/time.315* @param {goog.date.DateLike} date The time for which to retrieve316* the long time zone name.317* @return {string} The long time zone name.318*/319goog.i18n.TimeZone.prototype.getLongName = function(date) {320return this.tzNames_[this.isDaylightTime(date) ?321goog.i18n.TimeZone.NameType.DLT_LONG_NAME :322goog.i18n.TimeZone.NameType.STD_LONG_NAME];323};324325326/**327* Get the time zone offset in minutes WEST of UTC for a given date/time.328* @param {goog.date.DateLike} date The time for which to retrieve329* the time zone offset.330* @return {number} The time zone offset in minutes WEST of UTC.331*/332goog.i18n.TimeZone.prototype.getOffset = function(date) {333return this.standardOffset_ - this.getDaylightAdjustment(date);334};335336337/**338* Get the RFC representation of the time zone for a given date/time.339* @param {goog.date.DateLike} date The time for which to retrieve the340* RFC time zone string.341* @return {string} The RFC time zone string.342*/343goog.i18n.TimeZone.prototype.getRFCTimeZoneString = function(date) {344var offset = -this.getOffset(date);345var parts = [offset < 0 ? '-' : '+'];346offset = Math.abs(offset);347parts.push(348goog.string.padNumber(Math.floor(offset / 60) % 100, 2),349goog.string.padNumber(offset % 60, 2));350return parts.join('');351};352353354/**355* Get the short time zone name for given date/time.356* @param {goog.date.DateLike} date The time for which to retrieve357* the short time zone name.358* @return {string} The short time zone name.359*/360goog.i18n.TimeZone.prototype.getShortName = function(date) {361return this.tzNames_[this.isDaylightTime(date) ?362goog.i18n.TimeZone.NameType.DLT_SHORT_NAME :363goog.i18n.TimeZone.NameType.STD_SHORT_NAME];364};365366367/**368* Return the time zone ID for this time zone.369* @return {string} The time zone ID.370*/371goog.i18n.TimeZone.prototype.getTimeZoneId = function() {372return this.timeZoneId_;373};374375376/**377* Check if Daylight Saving Time is in effect at a given time in this time zone.378* @param {goog.date.DateLike} date The time to check.379* @return {boolean} True if Daylight Saving Time is in effect.380*/381goog.i18n.TimeZone.prototype.isDaylightTime = function(date) {382return this.getDaylightAdjustment(date) > 0;383};384385386/**387* Get the long GMT time zone name for a given date/time.388* @param {!goog.date.DateLike} date The time for which to retrieve389* the long GMT time zone name.390* @return {string} The long GMT time zone name.391*/392goog.i18n.TimeZone.prototype.getLongNameGMT = function(date) {393if (this.isDaylightTime(date)) {394return (goog.isDef(this.tzNamesExt_.DST_LONG_NAME_GMT)) ?395this.tzNamesExt_.DST_LONG_NAME_GMT :396this.tzNamesExt_['DST_LONG_NAME_GMT'];397} else {398return (goog.isDef(this.tzNamesExt_.STD_LONG_NAME_GMT)) ?399this.tzNamesExt_.STD_LONG_NAME_GMT :400this.tzNamesExt_['STD_LONG_NAME_GMT'];401}402};403404405/**406* Get the generic location time zone name for a given date/time.407* @param {!goog.date.DateLike} date The time for which to retrieve408* the generic location time zone name.409* @return {string} The generic location time zone name.410*/411goog.i18n.TimeZone.prototype.getGenericLocation = function(date) {412if (this.isDaylightTime(date)) {413return (goog.isDef(this.tzNamesExt_.DST_GENERIC_LOCATION)) ?414this.tzNamesExt_.DST_GENERIC_LOCATION :415this.tzNamesExt_['DST_GENERIC_LOCATION'];416} else {417return (goog.isDef(this.tzNamesExt_.STD_GENERIC_LOCATION)) ?418this.tzNamesExt_.STD_GENERIC_LOCATION :419this.tzNamesExt_['STD_GENERIC_LOCATION'];420}421};422423424