Workaround for Ruby UTC offset bug

Some Ruby versions have a bug when creating a Time object backed by a
timezone object where they create a fractional-second UTC offset.

For the added test, without this workaround, on Ruby 3.3.0:

      1) Failure:
    TimeExtCalculationsTest#test_change_preserves_fractional_seconds_on_zoned_time [./test/core_ext/time_ext_test.rb:528]:
    --- expected
    +++ actual
    @@ -1 +1,3 @@
    -"2005-01-30 00:00:00.99 -0500"
    +# encoding: US-ASCII
    +#    valid: true
    +"2005-01-30 00:00:00.99 -045959"

This is fixed in Ruby 3.3.1 and 3.2.4. We can remove the workaround when
we expect users to be on those versions or newer.
This commit is contained in:
John Hawthorn 2024-07-16 15:42:06 -07:00
parent 55c4adeb36
commit 44ca0f0f4d
2 changed files with 17 additions and 0 deletions

View File

@ -147,6 +147,13 @@ class Time
elsif zone.respond_to?(:utc_to_local)
new_time = ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
# Some versions of Ruby have a bug where Time.new with a zone object and
# fractional seconds will end up with a broken utc_offset.
# This is fixed in Ruby 3.3.1 and 3.2.4
unless new_time.utc_offset.integer?
new_time += 0
end
# When there are two occurrences of a nominal time due to DST ending,
# `Time.new` chooses the first chronological occurrence (the one with a
# larger UTC offset). However, for `change`, we want to choose the

View File

@ -519,6 +519,16 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
end
end
def test_change_preserves_fractional_seconds_on_zoned_time
with_tz_default "US/Eastern" do
time = Time.new(2005, 10, 30, 00, 00, 0.99r, Time.zone) + 0
time2 = time.change(month: 1)
assert_equal "2005-10-30 00:00:00.99 -0400", time.inspect
assert_equal "2005-01-30 00:00:00.99 -0500", time2.inspect
end
end
def test_change_preserves_fractional_hour_offset_for_local_times_around_end_of_dst
with_env_tz "Australia/Lord_Howe" do
# DST ended just before 2005-03-27 2:00:00 AM in Australia/Lord_Howe, and