Skip to content

Commit e05c2c0

Browse files
authored
Calculate travel_offset to align with the precision of argument to Timecop.travel (#421)
* Calculate travel_offset to align with clock precision Subtracting two `Time`s returns a `Float`, which may not be accurate down to subsecond resolution. Because `Float`s are stored as double- precision values (IEEE 754), they can have resolutions much higher than the typical minimum clock precision of 10e-9 seconds. Which can result in two `Time` object not comparing as equal when they are the same down to the nanosecond, when one has had a travel_offset applied to it. * Use the realtime clock's resolution when testing travel_offset's alignment * Improve failure message for travel_offset alignment test * Test that time_offset keeps precision of very high times passed to Timecop.travel * Mention this change in History.md
1 parent e556094 commit e05c2c0

3 files changed

Lines changed: 21 additions & 1 deletion

File tree

History.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Calculate travel_offset to align with the precision of argument to Timecop.travel ([#421](https://github.com/travisjeffery/timecop/pull/421))
6+
57
## v0.9.10
68

79
- Make Process.clock_gettime configurable and turned off by default (for backwards compatability) ([#427](https://github.com/travisjeffery/timecop/pull/427))

lib/timecop/time_stack_item.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def parse_time(*args)
157157
end
158158

159159
def compute_travel_offset
160-
time - Time.now_without_mock_time
160+
time.to_r - Time.now_without_mock_time.to_r
161161
end
162162

163163
def times_are_equal_within_epsilon t1, t2, epsilon_in_seconds

test/time_stack_item_test.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,4 +296,22 @@ def test_datetime_timezones
296296
assert_equal dt, now, "#{dt.to_f}, #{now.to_f}"
297297
end
298298
end
299+
300+
def test_travel_offset_aligns_to_clock
301+
t = Time.now
302+
stack_item = Timecop::TimeStackItem.new(:travel, t)
303+
travel_offset_denom = stack_item.travel_offset.to_r.denominator
304+
clock_resolution = Process.clock_getres(:CLOCK_REALTIME, :hertz)
305+
assert_equal 0, clock_resolution.modulo(travel_offset_denom),
306+
"travel offset precision (#{travel_offset_denom}) does not align with clock resolution (#{clock_resolution})"
307+
end
308+
309+
def test_travel_offset_aligns_to_travel_time
310+
t = Time.now + 0.001_002_003_004
311+
stack_item = Timecop::TimeStackItem.new(:travel, t)
312+
travel_offset_denom = stack_item.travel_offset.to_r.denominator
313+
travel_time_denom = t.to_r.denominator
314+
assert_equal 0, travel_time_denom.modulo(travel_offset_denom),
315+
"travel offset precision (#{travel_offset_denom}) does not align with travel time precision (#{travel_time_denom})"
316+
end
299317
end

0 commit comments

Comments
 (0)