Repository navigation
feat(intl)!: make relativetime() take a moment and pick the unit by the distance - #287
Merged
Merged
Conversation
… the distance `relativetime()` took a count of one fixed unit, so the app measured the distance to now, picked the unit and rounded on its own: a list showing "5 minutes ago" or "yesterday" kept a formatter per unit and a table of their lengths. It now takes a moment, like `datetime()`, and formats the distance to `relativeTo`, the current time by default, in the largest unit between `largestUnit` and `smallestUnit` that the distance fills, truncated. `relativeTo` may be a signal or an accessor, so a message follows a ticking clock. A month counts as 30 days and a year as 365. Zero of a time unit, from hours down, reads as "now", and zero of a calendar unit as "today" or "this week", as `Intl.RelativeTimeFormat` writes them with `numeric: 'auto'`. BREAKING CHANGE: `relativetime()` takes a moment, a date, a timestamp or a date string, instead of a count of units, and its `unit` option is gone, so a call that passes it no longer compiles. Format in one unit with `largestUnit` and `smallestUnit` set to it, and format a count of units with `Intl.RelativeTimeFormat` or a `plural()` message.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #287 +/- ##
==========================================
+ Coverage 83.20% 83.22% +0.02%
==========================================
Files 228 228
Lines 4823 4835 +12
Branches 1065 1071 +6
==========================================
+ Hits 4013 4024 +11
- Misses 574 575 +1
Partials 236 236 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merged
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Why
relativetime()took a count of one fixed unit, a thin wrapper overIntl.RelativeTimeFormat.prototype.format(value, unit). Everything that makes relative time useful stayed with the app: the distance to now, the unit and the rounding. An activity list that shows "5 minutes ago" or "yesterday" kept sevenrelativetime()formatters, one per unit, a table of unit lengths and a function to pick one, and its messages still did not follow the clock. A count of units is rare in real data, which carries timestamps: even the docs exampleformatStartsIn(1)leaves the app to count the days.What
relativetime()takes a moment, likedatetime(): a date, a timestamp or a date string.relativeToin the largest unit the distance fills at least once, truncated, assince()anduntil()of Temporal round by default. A month counts as 30 days and a year as 365: the distance picks the unit, not the calendar.largestUnitandsmallestUnit, named as in Temporal, bound the unit. By default the range runs fromyeartosecond, and both set to one unit format in it.quarteris not in the range.relativeTo, named as in Temporal, is the moment to count from, the current time by default. A signal or an accessor is read inside the message, so the message follows a ticking clock, for example a computed overinterval().numeric: 'auto',Intl.RelativeTimeFormatwrites zero minutes as "this minute" and zero hours as "this hour", which a list does not show.numeric,styleandlocaleMatchergo toIntl.RelativeTimeFormatas before.relativetimeis rewritten for the new input: 13 cases cover the unit choice, both bounds, one unit, zero, dates and date strings, the default clock, a signal clock, the raw mode and fallbacks.With
numeric: 'auto'inen:smallestUnit: 'minute'smallestUnit: 'day'Breaking change
relativetime()takes a moment instead of a count of units, and theunitoption is gone. Keepingunitwith the new input would turnformatStartsIn(1)into "56 years ago" without a type error, so a call that passesunitno longer compiles. Format in one unit withlargestUnitandsmallestUnitset to it, and format a count of units withIntl.RelativeTimeFormator aplural()message. The release PR #227 prepares 2.0.0 already.Size
All publics of intl grow by 203 B gzip, 2031 → 2234 B, and by 186 B brotli, 1888 → 2074 B, so their limits go up to 2.25 and 2.1 kB. The minimal and basic sets do not include
relativetime()and do not change, and an app that does not import it pays nothing. On an esbuild bench of the whole of intl, the app code that picks the unit over the currentrelativetime()adds 284 B gzip, and this change adds 206 B. Writing the unit lengths as products of literals changes nothing under the rolldown of size-limit, and named constants cost 7 B more.Notes
smallestUnit: 'day'an event 23 hours ago reads "today". The same goes for thresholds in the style of moment, where 45 seconds already count as a minute, and for a switch to an absolute date after a threshold, asthresholdof GitHub'srelative-timedoes.relativetimesection ofintl/api.mdxand itsformatStartsIn(1)example need an update before the 2.0.0 release.tscand the unit tests of intl pass, 133 of them, and so does the pre-pushpnpm test.