Running on your device · 0 bytes uploaded

Date Math

Add durations to a date and diff two dates — wall-clock versus elapsed time across DST, both stated.

Start date
One zone owns the arithmetic — no silent machine default.
naive input = wall time in the zone · an offset (Z or ±HH:MM) = that exact instant
Duration
years/months/weeks/days on the wall clock · hours/minutes/seconds as elapsed time
Result

2026-03-02T09:30:00.000-05:00

Monday, March 2, 2026 at 9:30:00 AM

  • years/months/weeks/days were added on the wall clock; hours/minutes/seconds as elapsed time (date-fns `add` order).
  • Month-end clamped: day 31 does not exist in the shorter target month, so the result lands on its last day (2) — no rollover to the next month.
epoch 1772461800 s · offset -05:00
Rules this tool follows
  • One zone owns the arithmetic. A naive input (2026-03-07 03:00) is wall time IN the selected zone; an input with an offset (…Z or …-05:00) is that exact instant, re-expressed in the zone. Both rules are stated, never guessed.
  • Calendar fields are wall-clock operations, clock fields are elapsed: 2026-03-07 03:00 New York + 1 day = 03:00 next day (23 real hours across spring-forward); + 24 hours = 04:00. Both facts are the engine’s, test-pinned.
  • Month ends clamp, they never roll over: 2026-01-31 + 1 month = 2026-02-28, and the note says the clamp fired.
  • Diffs state two answers on purpose: exact elapsed time and the calendar decomposition. Across a DST transition they legitimately disagree — the page shows both, labeled.
  • Every field is a bounded whole number (years ±1,000, days ±100,000, …) so a typo cannot ask for a nonsensical date; impossible dates (February 30) are refused.
Done

Finished here in the tab. Nothing was uploaded.

engine: date-fns over @date-fns/tz — the zone is part of the computation, not the display