Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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:
4842535
1b38737
  • Loading branch information...
commit ccad803bf44fe30602a041ff0ab1cbe985bc3840 1 parent d704c1c
@pixeltrix pixeltrix authored
View
6 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.
View
11 activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -49,10 +49,15 @@ def current
# 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
View
37 activesupport/test/core_ext/time_ext_test.rb
@@ -785,6 +785,12 @@ def test_at_with_datetime
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 @@ def test_at_with_time_with_zone
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"]) )
Please sign in to comment.
Something went wrong with that request. Please try again.