Don't emit to_time deprecations in known-safe contexts

If the value is already a local time, there's no difference, so no need
to warn.

Correspondingly, avoid calling to_time in the handful of places we were
using it internally: it's easy to do, and we know we don't care about
the zone.
This commit is contained in:
Matthew Draper 2024-06-06 08:43:18 +00:00 committed by John Hawthorn
parent 8000217130
commit d47c37183a
5 changed files with 55 additions and 5 deletions

@ -162,7 +162,7 @@ def current_time_from_proper_timezone
def max_updated_column_timestamp
timestamp_attributes_for_update_in_model
.filter_map { |attr| self[attr]&.to_time }
.filter_map { |attr| (v = self[attr]) && (v.is_a?(::Time) ? v : v.to_time) }
.max
end

@ -319,7 +319,12 @@ def compare_with_coercion(other)
if other.class == Time
compare_without_coercion(other)
elsif other.is_a?(Time)
compare_without_coercion(other.to_time)
# also avoid ActiveSupport::TimeWithZone#to_time before Rails 8.0
if other.respond_to?(:comparable_time)
compare_without_coercion(other.comparable_time)
else
compare_without_coercion(other.to_time)
end
else
to_datetime <=> other
end

@ -13,4 +13,20 @@ class Time
def to_time
preserve_timezone ? self : getlocal
end
def preserve_timezone # :nodoc:
active_support_local_zone == zone || super
end
private
@@active_support_local_tz = nil
def active_support_local_zone
@@active_support_local_zone = nil if @@active_support_local_tz != ENV["TZ"]
@@active_support_local_zone ||=
begin
@@active_support_local_tz = ENV["TZ"]
Time.new.zone
end
end
end

@ -163,10 +163,10 @@ def travel_to(date_or_time, with_usec: false)
now = date_or_time.midnight.to_time
elsif date_or_time.is_a?(String)
now = Time.zone.parse(date_or_time)
elsif with_usec
now = date_or_time.to_time
else
now = date_or_time.to_time.change(usec: 0)
now = date_or_time
now = now.to_time unless now.is_a?(Time)
now = now.change(usec: 0) unless with_usec
end
# +now+ must be in local system timezone, because +Time.at(now)+

@ -43,6 +43,35 @@ def test_time_to_time_does_not_preserve_time_zone
end
end
def test_time_to_time_without_preserve_configured
with_preserve_timezone(nil) do
with_env_tz "US/Eastern" do
source = Time.new(2016, 4, 23, 15, 11, 12)
# No warning because it's already local
base_time = source.to_time
utc_time = base_time.getutc
converted_time = assert_deprecated(ActiveSupport.deprecator) { utc_time.to_time }
assert_equal source, base_time
assert_equal source, converted_time
assert_equal @system_offset, base_time.utc_offset
assert_equal @system_offset, converted_time.utc_offset
end
end
with_preserve_timezone(nil) do
with_env_tz "US/Eastern" do
foreign_time = Time.new(2016, 4, 23, 15, 11, 12, in: "-0700")
converted_time = assert_deprecated(ActiveSupport.deprecator) { foreign_time.to_time }
assert_equal foreign_time, converted_time
assert_equal @system_offset, converted_time.utc_offset
assert_not_equal foreign_time.utc_offset, converted_time.utc_offset
end
end
end
def test_time_to_time_frozen_preserves_timezone
with_preserve_timezone(true) do
with_env_tz "US/Eastern" do