From 420730b10b46be7e40d806007bb28d3b17c7519f Mon Sep 17 00:00:00 2001 From: Alexey Shein Date: Thu, 21 Apr 2016 03:53:48 +0500 Subject: Do not cache ActiveSupport::TimeZone#utc_offset This can be an issue when TZInfo::TimeZone#current_period is refreshed due to timezone period transition, but it's not reflected in ActiveSupport::TimeZone object. For example, on Sun, 26 Oct 2014 22:00 UTC, Moscow changed its TZ from MSK +04:00 to MSK +03:00 (-1 hour). If ActiveSupport::TimeZone['Moscow'] happens to be initialized just before the timezone transition, it will cache its stale utc_offset even after the timezone transition. This commit removes cache and fixes this issue. Signed-off-by: Jeremy Daer --- activesupport/CHANGELOG.md | 6 ++++++ activesupport/lib/active_support/values/time_zone.rb | 4 +--- activesupport/test/time_zone_test.rb | 11 +++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 2be567c2f7..e4497e1756 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,9 @@ +* Time zones: Ensure that the UTC offset reflects DST changes that occurred + since the app started. Removes UTC offset caching, reducing performance, + but this is still relatively quick and isn't in any hot paths. + + *Alexey Shein* + * Make `getlocal` and `getutc` always return instances of `Time` for `ActiveSupport::TimeWithZone` and `DateTime`. This eliminates a possible stack level too deep error in `to_time` where `ActiveSupport::TimeWithZone` diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 00fdb22c31..19420cee5e 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -278,7 +278,6 @@ module ActiveSupport @name = name @utc_offset = utc_offset @tzinfo = tzinfo || TimeZone.find_tzinfo(name) - @current_period = nil end # Returns the offset of this time zone from UTC in seconds. @@ -286,8 +285,7 @@ module ActiveSupport if @utc_offset @utc_offset else - @current_period ||= tzinfo.current_period if tzinfo - @current_period.utc_offset if @current_period + tzinfo.current_period.utc_offset if tzinfo && tzinfo.current_period end end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index d0674eb03a..a15d5c6a0e 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -395,6 +395,17 @@ class TimeZoneTest < ActiveSupport::TestCase assert_equal(-18_000, zone.utc_offset) end + def test_utc_offset_is_not_cached_when_current_period_gets_stale + tz = ActiveSupport::TimeZone.create('Moscow') + travel_to(Time.utc(2014, 10, 25, 21)) do # 1 hour before TZ change + assert_equal 14400, tz.utc_offset, 'utc_offset should be initialized according to current_period' + end + + travel_to(Time.utc(2014, 10, 25, 22)) do # after TZ change + assert_equal 10800, tz.utc_offset, 'utc_offset should not be cached when current_period gets stale' + end + end + def test_seconds_to_utc_offset_with_colon assert_equal "-06:00", ActiveSupport::TimeZone.seconds_to_utc_offset(-21_600) assert_equal "+00:00", ActiveSupport::TimeZone.seconds_to_utc_offset(0) -- cgit v1.2.3