aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
authorAndrew White <andyw@pixeltrix.co.uk>2013-07-09 14:04:49 +0100
committerAndrew White <andyw@pixeltrix.co.uk>2013-07-09 14:04:49 +0100
commitccad803bf44fe30602a041ff0ab1cbe985bc3840 (patch)
tree22636c9a0829b7c7f5ec5c65fd7e5ebfe67c8d7b /activesupport
parentd704c1cb9850bd563b7ad99762e75b9b3cb7aebf (diff)
downloadrails-ccad803bf44fe30602a041ff0ab1cbe985bc3840.tar.gz
rails-ccad803bf44fe30602a041ff0ab1cbe985bc3840.tar.bz2
rails-ccad803bf44fe30602a041ff0ab1cbe985bc3840.zip
Retain offset and fraction 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. It also maintains the correct fractional second value as well. Fixes #11350. Backports: 484253515c0e05760541dc48946361185c9e6904 1b3873730b96035a238dbff7627bd5942e6dc4e7
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/CHANGELOG.md6
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb11
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb37
3 files changed, 51 insertions, 3 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 79bccf6d7e..21a726bfc1 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,11 @@
## unreleased ##
+* Make `Time.at_with_coercion` retain the second fraction and offset from UTC.
+
+ Fixes #11350
+
+ *Neer Friedman*, *Andrew White*
+
* Fix `ActiveSupport::TaggedLogging` incorrectly providing program name the same as log message
even when block is not provided.
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 7524063efb..9663edb0ad 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -49,10 +49,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_i)
+ 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 a22e161279..57ead2edc5 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -785,6 +785,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']))
@@ -796,6 +802,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"]) )