1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

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.
This commit is contained in:
Andrew White 2017-11-11 15:19:29 +00:00
parent 23c41e4657
commit 2eea6458a1
4 changed files with 66 additions and 1 deletions

View file

@ -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.
```

View file

@ -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:

View file

@ -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

View file

@ -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)