Skip to content

Instantly share code, notes, and snippets.

@jkintscher
Created May 20, 2013 16:19
Show Gist options
  • Select an option

  • Save jkintscher/5613347 to your computer and use it in GitHub Desktop.

Select an option

Save jkintscher/5613347 to your computer and use it in GitHub Desktop.
class this.jsTimezone
timezone: null
@local: () ->
tz = new jsTimezone()
tz.determine()
###
Gets the offset in minutes from UTC for a certain date.
@param Date date
@returns Number
###
get_date_offset: (date) ->
offset = -date.getTimezoneOffset()
if offset is null then 0 else offset
get_january_offset: () ->
@get_date_offset(new Date(2010, 0, 1, 0, 0, 0, 0))
get_june_offset: () ->
@get_date_offset(new Date(2010, 5, 1, 0, 0, 0, 0))
###
Checks whether a given date is in daylight savings time.
If the date supplied is after june, we assume that we're checking for southern hemisphere DST.
@private
@param Date date
@returns Boolean
###
_date_is_dst: (date) ->
base_offset = if date.getMonth() > 5 then @get_june_offset() else @get_january_offset()
date_offset = @get_date_offset(date)
(base_offset - date_offset) isnt 0
###
Uses get_timezone_info() to formulate a key to use in the olson.timezones dictionary.
@returns String The name of the timezone
###
determine: () ->
@timezone = new Timezone(@get_january_offset(), @get_june_offset())
@_ambiguity_check() if @_is_ambiguous()
@timezone
###
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: () ->
for tz in olson.ambiguity_list[@timezone.name]
return @timezone.name = tz if @_date_is_dst(olson.dst_start_dates[tz])
# Checks if it is possible that the timezone is ambiguous.
_is_ambiguous: () ->
typeof(olson.ambiguity_list[@timezone.name]) != 'undefined'
class Timezone
name: ''
offset: 0
has_dst: no
is_southern: no
constructor: (january_offset, june_offset) ->
diff = january_offset - june_offset
if diff < 0
@offset = january_offset
@has_dst = yes
else if diff > 0
@offset = june_offset
@has_dst = yes
@is_southern = yes
else
@offset = january_offset
@hours = @offset / 60
@name = olson.timezones[@build_key()]
###
@returns String A key that can be used to do lookups in olson.timezones
###
build_key: () ->
"#{@offset},#{if @has_dst then 1 else 0}#{if @is_southern then ',s' else ''}"
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.
###
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/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' : '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,1' : 'Europe/Moscow'
'180,0' : 'Asia/Baghdad'
'210,1' : 'Asia/Tehran'
'240,0' : 'Asia/Dubai'
'240,1' : 'Asia/Yerevan'
'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'
###
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.
###
olson.dst_start_dates =
'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)
'Atlantic/Stanley': new Date(2011, 8, 4, 7, 0, 0, 0)
'America/Asuncion': new Date(2011, 9, 2, 3, 0, 0, 0)
'America/Santiago': new Date(2011, 9, 9, 3, 0, 0, 0)
'America/Campo_Grande': new Date(2011, 9, 16, 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(2011, 2, 13, 2, 0, 0, 0)
'America/New_York': new Date(2011, 2, 13, 7, 0, 0, 0)
'Asia/Gaza': new Date(2011, 2, 26, 23, 0, 0, 0)
'Asia/Beirut': new Date(2011, 2, 27, 1, 0, 0, 0)
'Europe/Minsk': new Date(2011, 2, 27, 2, 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)
'Africa/Cairo': new Date(2010, 3, 30, 4, 0, 0, 0)
'Asia/Yerevan': new Date(2011, 2, 27, 4, 0, 0, 0)
'Asia/Baku': new Date(2011, 2, 27, 8, 0, 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)
###
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.
###
olson.ambiguity_list =
'America/Denver' : ['America/Denver', 'America/Mazatlan']
'America/Chicago' : ['America/Chicago', 'America/Mexico_City']
'America/Asuncion' : ['Atlantic/Stanley', 'America/Asuncion', 'America/Santiago', 'America/Campo_Grande']
'America/Montevideo' : ['America/Montevideo', 'America/Sao_Paulo']
'Asia/Beirut' : ['Asia/Gaza', 'Asia/Beirut', 'Europe/Minsk', 'Europe/Helsinki', 'Europe/Istanbul', 'Asia/Damascus', 'Asia/Jerusalem', 'Africa/Cairo']
'Asia/Yerevan' : ['Asia/Yerevan', 'Asia/Baku']
'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']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment