Skip to content

Preserve sub-second precision when subtracting a DateTime from a Time - #58213

Merged
byroot merged 1 commit into
rails:mainfrom
Saidbek:fix/time-minus-datetime-precision
Jul 23, 2026
Merged

Preserve sub-second precision when subtracting a DateTime from a Time#58213
byroot merged 1 commit into
rails:mainfrom
Saidbek:fix/time-minus-datetime-precision

Conversation

@Saidbek

@Saidbek Saidbek commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Time - DateTime (ActiveSupport layers this on top of Time#-) converted both sides via Float (to_f). A Float cannot represent every microsecond exactly, so the resulting difference was wrong for roughly half of all sub-second DateTime values.

Before / After

t  = Time.utc(2000, 1, 1, 0, 0, 1)
dt = DateTime.civil(2000, 1, 1, 0, 0, Rational(1, 1_000_000), "+0") # .000001s
t - dt
# before => 0.9999990463256836
# after  => (999999/1000000)

dt = DateTime.civil(2000, 1, 1, 0, 0, Rational(123_457, 1_000_000), "+0")
t - dt
# before => 0.8765430450439453
# after  => (876543/1000000)

Whole-second differences are unchanged (Time.utc(2000, 1, 2) - DateTime.civil(2000, 1, 1) is still 86400).

Why this is correct

  • It brings Time - DateTime in line with the sibling paths that already use exact rational timestamps: Time.at(DateTime) (Preserve sub-second precision when coercing a DateTime in Time.at #58085) and ActiveSupport::TimeWithZone - DateTime (via getutc).
  • The exact fractional second on a DateTime is datetime.to_i + datetime.sec_fraction; subtracting that from time.to_r preserves every microsecond.
  • Existing whole-second coverage continues to pass; new assertions lock the sub-second contract.

Time - DateTime converted both sides via to_f, so microsecond-level
DateTime values lost precision. Compute the difference from exact
rational timestamps instead, matching Time.at(DateTime) and
ActiveSupport::TimeWithZone - DateTime.
@Saidbek
Saidbek force-pushed the fix/time-minus-datetime-precision branch from d477364 to 4d24a25 Compare July 22, 2026 19:30
@byroot
byroot merged commit bbcb19c into rails:main Jul 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants