Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ The `micro` format displays relative dates in a more compact format. Similar to

If the `threshold` attribute is explicitly set, `micro` will display compact relative dates within the threshold and absolute dates outside of it. If `threshold` is not set, `micro` will continue to display compact relative dates without applying the default threshold.

When `tense` is set to `past` or `future`, `micro` uses `Intl.RelativeTimeFormat` with `style: 'narrow'` to include localized tense phrasing such as `2w ago` or `in 3d`. With the default `tense=auto`, `micro` preserves the compact duration output such as `2w`.

Code that uses `format=micro` should consider migrating to `format=relative` (perhaps with `formatStyle=narrow`), as `format=micro` can be difficult for users to understand, and can cause issues with assistive technologies. For example some screen readers (such as VoiceOver for mac) will read out `1m` as `1 meter`.

###### Cheatsheet
Expand All @@ -182,15 +184,15 @@ Code that uses `format=micro` should consider migrating to `format=relative` (pe

If `format` is `'datetime'` then this value will be ignored.

Tense can be used to prevent `duration` or `relative` formatted dates displaying dates in a tense other than the one specified. Setting `tense=past` will always display future `relative` dates as `now` and `duration` dates as `0 seconds`, while setting it to `future` will always display past dates `relative` as `now` and past `duration` dates as `0 seconds`.
Tense can be used to prevent `duration` or `relative` formatted dates displaying dates in a tense other than the one specified. Setting `tense=past` will always display future `relative` dates as `now` and `duration` dates as `0 seconds`, while setting it to `future` will always display past dates `relative` as `now` and past `duration` dates as `0 seconds`. For `format=micro`, `tense=past` and `tense=future` add localized compact tense phrasing.

For example when the given `datetime` is 40 seconds behind of the current date:

| `tense=` | format=duration | format=relative |
| :------: | :-------------: | :-------------: |
| future | 0s | now |
| past | 40s | 40s ago |
| auto | 40s | 40s ago |
| `tense=` | format=duration | format=relative | format=micro |
| :------: | :-------------: | :-------------: | :----------: |
| future | 0s | now | in 1m |
| past | 40s | 40s ago | 1m ago |
| auto | 40s | 40s ago | 1m |

```html
<relative-time datetime="2038-04-01T16:30:00-08:00" tense="past">
Expand Down
37 changes: 28 additions & 9 deletions src/relative-time-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,22 +236,37 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
return 'datetime'
}

#getMicroDuration(duration: Duration): Duration {
duration = roundToSingleUnit(duration)
// Allow month-level durations to pass through even with mismatched tense
if (
duration.months === 0 &&
((this.tense === 'past' && duration.sign !== -1) || (this.tense === 'future' && duration.sign !== 1))
) {
return microEmptyDuration
}
return duration
}

#getMicroRelativeFormat(duration: Duration): string {
const relativeFormat = new Intl.RelativeTimeFormat(this.#lang, {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This uses Intl.RelativeTimeFormat rather than string-concatenating English ago / in, so the compact tense output still follows lang.

numeric: 'always',
style: 'narrow',
})
duration = this.#getMicroDuration(duration)
const [int, unit] = getRelativeTimeUnit(duration.blank ? microEmptyDuration : duration)
return relativeFormat.format(Math.abs(int) * (this.tense === 'past' ? -1 : 1), unit)
}

#getDurationFormat(duration: Duration): string {
const locale = this.#lang
const format = this.format
const style = this.formatStyle
const tense = this.tense
let empty = emptyDuration
if (format === 'micro') {
duration = roundToSingleUnit(duration)
duration = this.#getMicroDuration(duration)
empty = microEmptyDuration
// Allow month-level durations to pass through even with mismatched tense
if (
duration.months === 0 &&
((this.tense === 'past' && duration.sign !== -1) || (this.tense === 'future' && duration.sign !== 1))
) {
duration = microEmptyDuration
}
} else if ((tense === 'past' && duration.sign !== -1) || (tense === 'future' && duration.sign !== 1)) {
duration = empty
}
Expand Down Expand Up @@ -624,7 +639,11 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
newText = this.#getUserPreferredAbsoluteTimeFormat(date)
} else {
if (format === 'duration') {
newText = this.#getDurationFormat(duration)
if (this.format === 'micro' && this.tense !== 'auto' && Intl.RelativeTimeFormat) {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tense phrasing is intentionally limited to micro duration output. Datetime fallback from #354 and user-preferred absolute output bypass this path, so we do not produce strings like Jan 1, 2024 ago.

newText = this.#getMicroRelativeFormat(duration)
} else {
newText = this.#getDurationFormat(duration)
}
} else if (format === 'relative') {
newText = this.#getRelativeFormat(duration)
} else {
Expand Down
Loading