diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index b9766a236a..03b324764b 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -310,13 +310,15 @@ module ActiveSupport end def tzinfo - @tzinfo ||= find_tzinfo + @tzinfo ||= TimeZone.find_tzinfo(name) end # TODO: Preload instead of lazy load for thread safety - def find_tzinfo + def self.find_tzinfo(name) require 'tzinfo' unless defined?(::TZInfo) - ::TZInfo::Timezone.get(MAPPING[name]) + ::TZInfo::Timezone.get(MAPPING[name] || name) + rescue TZInfo::InvalidTimezoneIdentifier + nil end unless const_defined?(:ZONES) @@ -330,7 +332,6 @@ module ActiveSupport end ZONES.sort! ZONES.freeze - ZONES_MAP.freeze US_ZONES = ZONES.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ } US_ZONES.freeze @@ -361,7 +362,7 @@ module ActiveSupport def [](arg) case arg when String - ZONES_MAP[arg] + ZONES_MAP[arg] ||= lookup(arg) when Numeric, ActiveSupport::Duration arg *= 3600 if arg.abs <= 13 all.find { |z| z.utc_offset == arg.to_i } @@ -375,6 +376,12 @@ module ActiveSupport def us_zones US_ZONES end + + private + + def lookup(name) + (tzinfo = find_tzinfo(name)) && create(tzinfo.name.freeze) + end end end end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index ce43c6507d..68027f7c94 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -75,6 +75,14 @@ class TimeZoneTest < Test::Unit::TestCase end end + def test_unknown_timezones_delegation_to_tzinfo + zone = ActiveSupport::TimeZone['America/Montevideo'] + assert_equal ActiveSupport::TimeZone, zone.class + assert_equal zone.object_id, ActiveSupport::TimeZone['America/Montevideo'].object_id + assert_equal Time.utc(2010, 1, 31, 22), zone.utc_to_local(Time.utc(2010, 2)) # daylight saving offset -0200 + assert_equal Time.utc(2010, 3, 31, 21), zone.utc_to_local(Time.utc(2010, 4)) # standard offset -0300 + end + def test_today Time.stubs(:now).returns(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today