diff options
author | Andrew White <andyw@pixeltrix.co.uk> | 2013-07-09 13:34:24 +0100 |
---|---|---|
committer | Andrew White <andyw@pixeltrix.co.uk> | 2013-07-09 13:43:56 +0100 |
commit | 1b3873730b96035a238dbff7627bd5942e6dc4e7 (patch) | |
tree | 72259583e746b6eacf773e2db3e84fc31b710be3 /activesupport | |
parent | 484253515c0e05760541dc48946361185c9e6904 (diff) | |
download | rails-1b3873730b96035a238dbff7627bd5942e6dc4e7.tar.gz rails-1b3873730b96035a238dbff7627bd5942e6dc4e7.tar.bz2 rails-1b3873730b96035a238dbff7627bd5942e6dc4e7.zip |
Retain UTC offset when using Time.at_with_coercion
The standard Ruby behavior for Time.at is to return the same type of
time when passing an instance of Time as a single argument. Since the
an ActiveSupport::TimeWithZone instance may be a different timezone than
the system timezone and DateTime just understands offsets the best we
can do is to return an instance of Time with the correct offset.
Fixes #11350.
Diffstat (limited to 'activesupport')
-rw-r--r-- | activesupport/CHANGELOG.md | 6 | ||||
-rw-r--r-- | activesupport/lib/active_support/core_ext/time/calculations.rb | 11 | ||||
-rw-r--r-- | activesupport/test/core_ext/time_ext_test.rb | 33 |
3 files changed, 47 insertions, 3 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 221ceb532a..e29dc636df 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,9 @@ +* Make `Time.at_with_coercion` retain the second fraction and offset from UTC. + + Fixes #11350 + + *Neer Friedman*, *Andrew White* + * Make `HashWithIndifferentAccess#select` always return the hash, even when `Hash#select!` returns `nil`, to allow further chaining. diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 8270093dc7..20e7e0b303 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -33,10 +33,15 @@ class Time # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime # instances can be used when called with a single argument def at_with_coercion(*args) - if args.size == 1 && args.first.acts_like?(:time) - at_without_coercion(args.first.to_f) + return at_without_coercion(*args) if args.size != 1 + + # Time.at can be called with a time or numerical value + time_or_number = args.first + + if time_or_number.is_a?(ActiveSupport::TimeWithZone) || time_or_number.is_a?(DateTime) + at_without_coercion(time_or_number.to_f).getlocal(time_or_number.utc_offset) else - at_without_coercion(*args) + at_without_coercion(time_or_number) end end alias_method :at_without_coercion, :at diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index 1681702bda..63fddd0cfd 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -700,6 +700,12 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end end + def test_at_with_datetime_maintains_offset + with_env_tz 'US/Eastern' do + assert_equal 3600, Time.at(DateTime.civil(2000, 1, 1, 0, 0, 0, '+1')).utc_offset + end + end + def test_at_with_time_with_zone assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'])) @@ -711,10 +717,37 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end end + def test_at_with_time_with_zone_maintains_offset + with_env_tz 'US/Eastern' do + assert_equal 0, Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['London'])).utc_offset + assert_equal 3600, Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 7, 1, 0, 0, 0), ActiveSupport::TimeZone['London'])).utc_offset + end + end + def test_at_with_time_microsecond_precision assert_equal Time.at(Time.utc(2000, 1, 1, 0, 0, 0, 111)).to_f, Time.utc(2000, 1, 1, 0, 0, 0, 111).to_f end + def test_at_with_utc_time + with_env_tz 'US/Eastern' do + assert_equal Time.utc(2000), Time.at(Time.utc(2000)) + assert_equal 0, Time.at(Time.utc(2000)).utc_offset + assert_equal 'UTC', Time.at(Time.utc(2000)).zone + end + end + + def test_at_with_local_time + with_env_tz 'US/Eastern' do + assert_equal Time.local(2000), Time.at(Time.local(2000)) + assert_equal -18000, Time.at(Time.local(2000)).utc_offset + assert_equal 'EST', Time.at(Time.local(2000)).zone + + assert_equal Time.local(2000, 7, 1), Time.at(Time.local(2000, 7, 1)) + assert_equal -14400, Time.at(Time.local(2000, 7, 1)).utc_offset + assert_equal 'EDT', Time.at(Time.local(2000, 7, 1)).zone + end + end + def test_eql? assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) ) assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Hawaii"]) ) |