Hey everyone, I was chasing down some flaky tests related to time parsing and wanted to share what I found. Let me know if I’m misunderstanding anything. Here’s the behavior I observed and the PR that came out of it.
I noticed that when Timecop freezes time and you parse a string that only contains hours and minutes (e.g., "01:00"), the resulting DateTime can depend on the host clock instead of the frozen date. The fallback path in DateTime.parse_with_mock_date uses:
travel_offset_days = (@travel_offset / 86400).round
Since @travel_offset is the difference between the frozen moment and the real system time, things get unstable when that difference is roughly +/-12 hours from a whole number of days. In those cases, the rounding flips and the parsed DateTime lands a full day earlier or later.
Example:
Timecop.freeze(Time.utc(2017, 8, 10, 10, 0, 0))
# Host clock is 2025-11-13 22:00 UTC
DateTime.parse("01:00")
# => Wed, 09 Aug 2017 01:00:00 +0000 (one day too early)
But if the host clock is just one hour earlier (21:00 UTC):
# => Thu, 10 Aug 2017 01:00:00 +0000
This reproduces cleanly using faketime:
faketime '2025-11-13 22:00:00' bundle exec rails c
Timecop.freeze(Time.utc(2017, 8, 10, 10, 0, 0))
DateTime.parse("01:00") # => 2017-08-09 01:00:00
So tests that rely on parsing time-only strings can become flaky depending on what time of day the host is at.
Proposed fix / PR
#440
Happy to adjust if I’ve misunderstood how this path is meant to behave.
Hey everyone, I was chasing down some flaky tests related to time parsing and wanted to share what I found. Let me know if I’m misunderstanding anything. Here’s the behavior I observed and the PR that came out of it.
I noticed that when Timecop freezes time and you parse a string that only contains hours and minutes (e.g.,
"01:00"), the resultingDateTimecan depend on the host clock instead of the frozen date. The fallback path inDateTime.parse_with_mock_dateuses:Since
@travel_offsetis the difference between the frozen moment and the real system time, things get unstable when that difference is roughly +/-12 hours from a whole number of days. In those cases, the rounding flips and the parsedDateTimelands a full day earlier or later.Example:
But if the host clock is just one hour earlier (21:00 UTC):
# => Thu, 10 Aug 2017 01:00:00 +0000This reproduces cleanly using faketime:
So tests that rely on parsing time-only strings can become flaky depending on what time of day the host is at.
Proposed fix / PR
#440
Happy to adjust if I’ve misunderstood how this path is meant to behave.