Skip to content

Commit 0f48a5e

Browse files
silverwindclaude
andcommitted
Address review comments
- Use resolvedOptions().hour12 instead of whitespace heuristic for browser hour cycle detection - Pass hourCycle directly to Intl.DateTimeFormat instead of converting to hour12, preserving h11/h12/h23/h24 distinctions - Remove isHour12() helper, no longer needed - Validate hourCycle getter against allowed values - Add positive assertion to h24 test - Fix README formatting for hourCycle default value Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f5dd512 commit 0f48a5e

3 files changed

Lines changed: 15 additions & 15 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ So, a relative date phrase is used for up to a month and then the actual date is
7575
| `year` | `year` | `'numeric'\|'2-digit'\|undefined` | <sup>\*\*\*\*</sup> |
7676
| `timeZoneName` | `time-zone-name` | `'long'\|'short'\|'shortOffset'\|'longOffset'` `\|'shortGeneric'\|'longGeneric'\|undefined` | `undefined` |
7777
| `timeZone` | `time-zone` | `string\|undefined` | Browser default time zone |
78-
| `hourCycle` | `hour-cycle` | `'h11'\|'h12'\|'h23'\|'h24'\|undefined` | 'h12' or 'h23' based on browser |
78+
| `hourCycle` | `hour-cycle` | `'h11'\|'h12'\|'h23'\|'h24'\|undefined` | `'h12'` or `'h23'` based on browser |
7979
| `noTitle` | `no-title` | `-` | `-` |
8080

8181
<sup>\*</sup>: If unspecified, `formatStyle` will return `'narrow'` if `format` is `'elapsed'` or `'micro'`, `'short'` if the format is `'relative'` or `'datetime'`, otherwise it will be `'long'`.

src/relative-time-element.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,14 @@ function getUnitFactor(el: RelativeTimeElement): number {
3232
return 60 * 60 * 1000
3333
}
3434

35-
// Determine whether the user has a 12 (vs. 24) hour cycle preference. This relies on the hour formatting in
36-
// a 12 hour preference being formatted like "1 AM" including a space, while with a 24 hour preference, the
37-
// same is formatted as "01" without a space. In the future `Intl.Locale.prototype.getHourCycles()` could be
38-
// used but it is not as well-supported as this method.
39-
function isBrowser12hCycle() {
40-
return Boolean(/\s/.exec(new Intl.DateTimeFormat([], {hour: 'numeric'}).format(new Date(0))))
41-
}
42-
43-
function isHour12(hourCycle: Intl.DateTimeFormatOptions['hourCycle']) {
44-
return hourCycle === 'h11' || hourCycle === 'h12'
35+
// Determine whether the user has a 12 (vs. 24) hour cycle preference via the
36+
// browser's resolved DateTimeFormat options.
37+
function isBrowser12hCycle(): boolean {
38+
try {
39+
return new Intl.DateTimeFormat([], {hour: 'numeric'}).resolvedOptions().hour12 === true
40+
} catch {
41+
return false
42+
}
4543
}
4644

4745
const dateObserver = new (class {
@@ -115,7 +113,8 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
115113
const hc =
116114
this.closest('[hour-cycle]')?.getAttribute('hour-cycle') ||
117115
this.ownerDocument.documentElement.getAttribute('hour-cycle')
118-
return (hc || (isBrowser12hCycle() ? 'h12' : 'h23')) as Intl.DateTimeFormatOptions['hourCycle']
116+
if (hc === 'h11' || hc === 'h12' || hc === 'h23' || hc === 'h24') return hc
117+
return isBrowser12hCycle() ? 'h12' : 'h23'
119118
}
120119

121120
#renderRoot: Node = this.shadowRoot ? this.shadowRoot : this.attachShadow ? this.attachShadow({mode: 'open'}) : this
@@ -160,7 +159,7 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
160159
minute: '2-digit',
161160
timeZoneName: 'short',
162161
timeZone: this.timeZone,
163-
hour12: isHour12(this.hourCycle),
162+
hourCycle: this.hourCycle,
164163
}).format(date)
165164
}
166165

@@ -235,7 +234,7 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
235234
year: this.year,
236235
timeZoneName: this.timeZoneName,
237236
timeZone: this.timeZone,
238-
hour12: isHour12(this.hourCycle),
237+
hourCycle: this.hourCycle,
239238
})
240239
return `${this.prefix} ${formatter.format(date)}`.trim()
241240
}
@@ -269,7 +268,7 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
269268
minute: '2-digit',
270269
timeZoneName: 'short',
271270
timeZone: this.timeZone,
272-
hour12: isHour12(this.hourCycle),
271+
hourCycle: this.hourCycle,
273272
}
274273

275274
if (this.#isToday(date)) {

test/relative-time.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,6 +2866,7 @@ suite('relative-time', function () {
28662866
el.setAttribute('hour-cycle', 'h24')
28672867
await Promise.resolve()
28682868
assert.notMatch(el.shadowRoot.textContent, /AM|PM/i)
2869+
assert.match(el.shadowRoot.textContent, /15:00/)
28692870
})
28702871

28712872
test('title uses hour-cycle setting', async () => {

0 commit comments

Comments
 (0)