You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Use calendar days for "yesterday"/"tomorrow" rounding - #393
roundToSingleUnit turned N days + H hours into days by rounding the hours (days += Math.round(hours / 24)). "Yesterday" is a calendar concept, so a date 36–37 hours ago that is still on the previous calendar day showed as "2 days ago", while 38h ago (also yesterday) showed "yesterday" again.
Example from the issue (local time): now is Apr 30 13:53, date is Apr 29 00:53 → -P1DT13H → was "2 days ago", now "yesterday".
Change
When a duration has days but no weeks/months/years, days is the number of calendar days between relativeTo and the target date (applyDuration(relativeTo, duration)), compared at local midnight and rounded so DST days of 23h/25h still count as one day. Other cases keep the existing rounding.
The element passes the now it used for elapsedTime as relativeTo, plus the exact date, to the relative and micro formatters. Calendar days are counted from the real date rather than one rebuilt from the precision-truncated duration (dropped milliseconds, precision="hour"/"day"), and both rounding passes in the micro path agree.
On a 25 hour DST day, a full day of elapsed time can stay on one calendar date; that case stays in hours ("24 hours ago") instead of rounding away.
The duration format without micro doesn't call roundToSingleUnit and is unaffected.
Tests
New roundToSingleUnit cases for the issue scenario (past and future), for the 2 days + under 1 hour window right after/before midnight, and a case that stays at 2 days.
P1DT20H / P1DT18H used the default relativeTo (midnight), where +1d20h is calendar "tomorrow". They now use noon, which gives P2D in both directions.
Cases for the exact date option (truncated milliseconds, precision="day") and the DST same-day case.
npm test passes (647 tests).
The rewrite proposed in #301 also counts calendar days and would cover this issue.
"yesterday" and "tomorrow" were decided by rounding the hours part, so a
date 36-37 hours ago (still yesterday on the calendar) showed as
"2 days ago". When a duration has days but no weeks/months/years, count
the calendar days between relativeTo and the target date instead.
The element now also passes the `now` it used for elapsedTime as
relativeTo, so both calculations agree near midnight.
Fixesgithub#313
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Unresolved DST handling and fractional-second truncation defects produce incorrect relative times, including “now” for a 24-hour-old timestamp and off-by-one future day counts.
This PR addresses #313 by using local calendar-day differences for day-level relative-time rounding, so “yesterday” and “tomorrow” better match calendar dates.
Changes:
Replaces hour-based day rounding with local calendar-day counting for durations without weeks, months, or years.
Passes the same reference time through elapsed-time calculation and relative/micro formatting.
Adds regression cases for past and future dates near midnight.
File
Description
test/duration.ts
Adds calendar-day regression cases and explicit reference times.
src/relative-time-element.ts
Shares the reference time with relative and micro formatters.
src/duration.ts
Adds local calendar-day counting to single-unit rounding.
Rebuilding the target date from a precision-truncated duration could
cross midnight (dropped milliseconds, precision="hour"/"day"), and
re-rounding an already rounded micro duration could do the same across
DST. roundToSingleUnit now accepts the exact `date` and the element
passes it along with relativeTo.
On a 25 hour DST day a full day of elapsed time can stay on one
calendar date; keep that in hours instead of rounding it to "now".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Unresolved calendar-day rounding issues produce incorrect durations, ignore the configured time zone, and leave labels stale across midnight, while existing tests have become clock-dependent.
- Pass the resolved time zone into calendar-day rounding
- Pick the micro unit from the already-rounded duration instead of rounding twice
- Schedule an update at the next midnight for hour-scale dates
- Freeze the clock in micro day-format tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Unresolved date-handling bugs delay refreshes when DST skips across midnight and treat timestamp 0 as missing, producing incorrect relative-day output.
The new date option accepts numeric timestamps, but this truthiness check treats the Unix epoch (0) as missing. With relativeTo: new Date('1969-12-30T10:00:00.500Z'), date: 0, timeZone: 'UTC', and duration P1DT13H59M59S, the fallback reconstructs December 31 just before midnight and returns P1D instead of P2D. Check against undefined so numeric zero receives the same exact-date handling as new Date(0).
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The helper misses backward calendar-date changes, leaving labels stale for 30 minutes, and performs unnecessary time-zone formatting calls on every observer tick.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human review is needed to assess a spring-forward boundary case where elapsed-hour rounding understates calendar-day differences and produces an incorrect relative-day label.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed because date reconstruction around the year 0099–0100 boundary can cause duration rounding to report hundreds of thousands of calendar days instead of one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #313
Problem
roundToSingleUnitturnedN days + H hoursinto days by rounding the hours (days += Math.round(hours / 24)). "Yesterday" is a calendar concept, so a date 36–37 hours ago that is still on the previous calendar day showed as "2 days ago", while 38h ago (also yesterday) showed "yesterday" again.Example from the issue (local time): now is Apr 30 13:53, date is Apr 29 00:53 →
-P1DT13H→ was "2 days ago", now "yesterday".Change
daysis the number of calendar days betweenrelativeToand the target date (applyDuration(relativeTo, duration)), compared at local midnight and rounded so DST days of 23h/25h still count as one day. Other cases keep the existing rounding.nowit used forelapsedTimeasrelativeTo, plus the exactdate, to the relative and micro formatters. Calendar days are counted from the real date rather than one rebuilt from the precision-truncated duration (dropped milliseconds,precision="hour"/"day"), and both rounding passes in the micro path agree.The
durationformat withoutmicrodoesn't callroundToSingleUnitand is unaffected.Tests
roundToSingleUnitcases for the issue scenario (past and future), for the 2 days + under 1 hour window right after/before midnight, and a case that stays at 2 days.P1DT20H/P1DT18Hused the defaultrelativeTo(midnight), where+1d20his calendar "tomorrow". They now use noon, which givesP2Din both directions.dateoption (truncated milliseconds,precision="day") and the DST same-day case.npm testpasses (647 tests).The rewrite proposed in #301 also counts calendar days and would cover this issue.
🤖 Generated with Claude Code