Skip to content

Commit 67fb441

Browse files
authored
Merge pull request rails#50236 from 907th/fix-travel-to
Fix `Time.now`/`DateTime.now`/`Date.today` to return results in a system timezone after `#travel_to`
2 parents 90daef6 + aedb808 commit 67fb441

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

activesupport/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
* Fix `Time.now/DateTime.now/Date.today' to return results in a system timezone after `#travel_to'.
2+
3+
There is a bug in the current implementation of #travel_to:
4+
it remembers a timezone of its argument, and all stubbed methods start
5+
returning results in that remembered timezone. However, the expected
6+
behaviour is to return results in a system timezone.
7+
8+
*Aleksei Chernenkov*
9+
110
* Add `ErrorReported#unexpected` to report precondition violations.
211

312
For example:

activesupport/lib/active_support/testing/time_helpers.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ def travel_to(date_or_time, with_usec: false)
169169
now = date_or_time.to_time.change(usec: 0)
170170
end
171171

172+
# +now+ must be in local system timezone, because +Time.at(now)+
173+
# and +now.to_date+ (see stubs below) will use +now+'s timezone too!
174+
now = now.getlocal
175+
172176
stubs = simple_stubs
173177
stubbed_time = Time.now if stubs.stubbing(Time, :now)
174178
stubs.stub_object(Time, :now) { at(now) }

activesupport/test/time_travel_test.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,44 @@ def test_time_helper_travel_to_with_time_zone
122122
end
123123
end
124124

125+
def test_time_helper_travel_to_with_different_system_and_application_time_zones
126+
with_env_tz "US/Eastern" do # system time zone: -05
127+
expected_time_in_2021 = Time.new(2021)
128+
129+
with_tz_default ActiveSupport::TimeZone["Ekaterinburg"] do # application time zone: +05
130+
destination_time = Time.new(2023, 12, 1, 5, 6, 7, 5 * 3600)
131+
132+
# All stubbed methods are expected to return values in system (-05) time zone
133+
expected_utc_offset = -5 * 3600
134+
expected_time = Time.new(2023, 11, 30, 19, 6, 7, expected_utc_offset)
135+
expected_datetime = DateTime.new(2023, 11, 30, 19, 6, 7, -Rational(5, 24))
136+
expected_date = Date.new(2023, 11, 30)
137+
138+
travel_to destination_time do
139+
assert_equal expected_time, Time.now
140+
assert_equal expected_time.to_fs(:db), Time.now.to_fs(:db)
141+
assert_equal expected_utc_offset, Time.now.utc_offset
142+
143+
assert_equal expected_datetime, DateTime.now
144+
assert_equal expected_datetime.to_fs(:db), DateTime.now.to_fs(:db)
145+
assert_equal expected_utc_offset, DateTime.now.utc_offset
146+
147+
assert_equal expected_date, Date.today
148+
149+
# Time.new with no args equals to Time.now
150+
assert_equal expected_time, Time.new
151+
assert_equal expected_time.to_fs(:db), Time.new.to_fs(:db)
152+
assert_equal expected_utc_offset, Time.new.utc_offset
153+
154+
# Time.new with any args falls back to original Ruby implementation
155+
assert_equal expected_time_in_2021, Time.new(2021)
156+
assert_equal expected_time_in_2021.to_fs(:db), Time.new(2021).to_fs(:db)
157+
assert_equal expected_time_in_2021.utc_offset, Time.new(2021).utc_offset
158+
end
159+
end
160+
end
161+
end
162+
125163
def test_time_helper_travel_to_with_string_for_time_zone
126164
with_env_tz "US/Eastern" do
127165
with_tz_default ActiveSupport::TimeZone["UTC"] do

0 commit comments

Comments
 (0)