diff options
| -rw-r--r-- | activesupport/CHANGELOG.md | 27 | ||||
| -rw-r--r-- | activesupport/lib/active_support/values/time_zone.rb | 2 | ||||
| -rw-r--r-- | activesupport/test/core_ext/time_with_zone_test.rb | 12 | ||||
| -rw-r--r-- | activesupport/test/time_zone_test.rb | 26 | 
4 files changed, 66 insertions, 1 deletions
| diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 4762c7d21d..904dab0e05 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,30 @@ +*   Handle `TZInfo::AmbiguousTime` errors + +    Make `ActiveSupport::TimeWithZone` match Ruby's handling of ambiguous +    times by choosing the later period, e.g. + +    Ruby: +    ``` +    ENV["TZ"] = "Europe/Moscow" +    Time.local(2014, 10, 26, 1, 0, 0)   # => 2014-10-26 01:00:00 +0300 +    ``` + +    Before: +    ``` +    >> "2014-10-26 01:00:00".in_time_zone("Moscow") +    TZInfo::AmbiguousTime: 26/10/2014 01:00 is an ambiguous local time. +    ``` + +    After: +    ``` +    >> "2014-10-26 01:00:00".in_time_zone("Moscow") +    => Sun, 26 Oct 2014 01:00:00 MSK +03:00 +    ``` + +    Fixes #17395. + +    *Andrew White* +  *   Redis cache store.      ``` diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 4d1fbd4453..639a066e28 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -506,7 +506,7 @@ module ActiveSupport      # Available so that TimeZone instances respond like TZInfo::Timezone      # instances.      def period_for_local(time, dst = true) -      tzinfo.period_for_local(time, dst) +      tzinfo.period_for_local(time, dst) { |periods| periods.last }      end      def periods_for_local(time) #:nodoc: diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 0f80a24758..ab96568956 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -50,6 +50,12 @@ class TimeWithZoneTest < ActiveSupport::TestCase      assert_raise(ArgumentError) { @twz.in_time_zone(Object.new) }    end +  def test_in_time_zone_with_ambiguous_time +    with_env_tz "Europe/Moscow" do +      assert_equal Time.utc(2014, 10, 25, 22, 0, 0), Time.local(2014, 10, 26, 1, 0, 0).in_time_zone("Moscow") +    end +  end +    def test_localtime      assert_equal @twz.localtime, @twz.utc.getlocal      assert_instance_of Time, @twz.localtime @@ -1301,4 +1307,10 @@ class TimeWithZoneMethodsForString < ActiveSupport::TestCase      assert_raise(ArgumentError) { @u.in_time_zone(Object.new) }      assert_raise(ArgumentError) { @z.in_time_zone(Object.new) }    end + +  def test_in_time_zone_with_ambiguous_time +    with_tz_default "Moscow" do +      assert_equal Time.utc(2014, 10, 25, 22, 0, 0), "2014-10-26 01:00:00".in_time_zone +    end +  end  end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index acb0ecd226..862e872494 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -32,6 +32,12 @@ class TimeZoneTest < ActiveSupport::TestCase      end    end +  def test_period_for_local_with_ambigiuous_time +    zone = ActiveSupport::TimeZone["Moscow"] +    period = zone.period_for_local(Time.utc(2015, 1, 1)) +    assert_equal period, zone.period_for_local(Time.utc(2014, 10, 26, 1, 0, 0)) +  end +    def test_from_integer_to_map      assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone[-28800] # PST    end @@ -195,6 +201,11 @@ class TimeZoneTest < ActiveSupport::TestCase      assert_equal "EDT", twz.zone    end +  def test_local_with_ambiguous_time +    zone = ActiveSupport::TimeZone["Moscow"] +    assert_equal Time.utc(2014, 10, 25, 22, 0, 0), zone.local(2014, 10, 26, 1, 0, 0) +  end +    def test_at      zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]      secs = 946684800.0 @@ -303,6 +314,11 @@ class TimeZoneTest < ActiveSupport::TestCase      end    end +  def test_iso8601_with_ambiguous_time +    zone = ActiveSupport::TimeZone["Moscow"] +    assert_equal Time.utc(2014, 10, 25, 22, 0, 0), zone.parse("2014-10-26T01:00:00") +  end +    def test_parse      zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]      twz = zone.parse("1999-12-31 19:00:00") @@ -412,6 +428,11 @@ class TimeZoneTest < ActiveSupport::TestCase      assert_equal "argument out of range", exception.message    end +  def test_parse_with_ambiguous_time +    zone = ActiveSupport::TimeZone["Moscow"] +    assert_equal Time.utc(2014, 10, 25, 22, 0, 0), zone.parse("2014-10-26 01:00:00") +  end +    def test_rfc3339      zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]      twz = zone.rfc3339("1999-12-31T14:00:00-10:00") @@ -604,6 +625,11 @@ class TimeZoneTest < ActiveSupport::TestCase      end    end +  def test_strptime_with_ambiguous_time +    zone = ActiveSupport::TimeZone["Moscow"] +    assert_equal Time.utc(2014, 10, 25, 22, 0, 0), zone.strptime("2014-10-26 01:00:00", "%Y-%m-%d %H:%M:%S") +  end +    def test_utc_offset_lazy_loaded_from_tzinfo_when_not_passed_in_to_initialize      tzinfo = TZInfo::Timezone.get("America/New_York")      zone = ActiveSupport::TimeZone.create(tzinfo.name, nil, tzinfo) | 
