Skip to content

Commit 4d0059b

Browse files
authored
Merge pull request #316 from davhdavh/main
feat: add support for time-zone attribute
2 parents 33cde64 + 39a8ec0 commit 4d0059b

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ So, a relative date phrase is used for up to a month and then the actual date is
8080
| `month` | `month` | `'numeric'\|'2-digit'\|'short'\|'long'\|'narrow'\|undefined` | <sup>***</sup> |
8181
| `year` | `year` | `'numeric'\|'2-digit'\|undefined` | <sup>****</sup> |
8282
| `timeZoneName` | `time-zone-name` | `'long'\|'short'\|'shortOffset'\|'longOffset'` `\|'shortGeneric'\|'longGeneric'\|undefined` | `undefined` |
83+
| `timeZone` | `time-zone` | `string\|undefined` | Browser default time zone |
8384
| `noTitle` | `no-title` | `-` | `-` |
8485

8586
<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'`.
@@ -139,6 +140,19 @@ The `duration` format will display the time remaining (or elapsed time) from the
139140
- `4 hours`
140141
- `8 days, 30 minutes, 1 second`
141142

143+
##### time-zone (`string`)
144+
145+
The`time-zone` attribute allows you to specify the IANA time zone name (e.g., `America/New_York`, `Europe/London`) used for formatting the date and time.
146+
147+
You can set the time zone either as an attribute or property:
148+
```html
149+
<relative-time datetime="2024-06-01T12:00:00Z" ... time-zone="America/New_York">
150+
June 1, 2024 8:00am EDT
151+
</relative-time>
152+
```
153+
154+
If the individual element does not have a `time-zone` attribute then it will traverse upwards in the tree to find the closest element that does, or default the `time-zone` to the browsers default.
155+
142156
###### Deprecated Formats
143157

144158
###### `format=elapsed`

src/relative-time-element.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
9090
}
9191
}
9292

93+
get timeZone() {
94+
// Prefer attribute, then closest, then document
95+
const tz =
96+
this.closest('[time-zone]')?.getAttribute('time-zone') ||
97+
this.ownerDocument.documentElement.getAttribute('time-zone')
98+
return tz || undefined
99+
}
100+
93101
#renderRoot: Node = this.shadowRoot ? this.shadowRoot : this.attachShadow ? this.attachShadow({mode: 'open'}) : this
94102

95103
static get observedAttributes() {
@@ -113,6 +121,7 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
113121
'lang',
114122
'title',
115123
'aria-hidden',
124+
'time-zone',
116125
]
117126
}
118127

@@ -129,6 +138,7 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
129138
hour: 'numeric',
130139
minute: '2-digit',
131140
timeZoneName: 'short',
141+
timeZone: this.timeZone,
132142
}).format(date)
133143
}
134144

@@ -198,6 +208,7 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
198208
month: this.month,
199209
year: this.year,
200210
timeZoneName: this.timeZoneName,
211+
timeZone: this.timeZone,
201212
})
202213
return `${this.prefix} ${formatter.format(date)}`.trim()
203214
}

test/relative-time.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,4 +2586,62 @@ suite('relative-time', function () {
25862586
})
25872587
}
25882588
})
2589+
2590+
suite('[timeZone]', function () {
2591+
test('updates when the time-zone attribute is set', async () => {
2592+
const el = document.createElement('relative-time')
2593+
el.setAttribute('datetime', '2020-01-01T12:00:00.000Z')
2594+
el.setAttribute('time-zone', 'America/New_York')
2595+
el.setAttribute('format', 'datetime')
2596+
el.setAttribute('hour', 'numeric')
2597+
el.setAttribute('minute', '2-digit')
2598+
el.setAttribute('second', '2-digit')
2599+
el.setAttribute('time-zone-name', 'longGeneric')
2600+
await Promise.resolve()
2601+
assert.equal(el.shadowRoot.textContent, 'Wed, Jan 1, 2020, 7:00:00 AM Eastern Time')
2602+
})
2603+
2604+
test('updates when the time-zone attribute changes', async () => {
2605+
const el = document.createElement('relative-time')
2606+
el.setAttribute('datetime', '2020-01-01T12:00:00.000Z')
2607+
el.setAttribute('time-zone', 'America/New_York')
2608+
el.setAttribute('format', 'datetime')
2609+
el.setAttribute('hour', 'numeric')
2610+
el.setAttribute('minute', '2-digit')
2611+
el.setAttribute('second', '2-digit')
2612+
await Promise.resolve()
2613+
const initial = el.shadowRoot.textContent
2614+
el.setAttribute('time-zone', 'Asia/Tokyo')
2615+
await Promise.resolve()
2616+
assert.notEqual(el.shadowRoot.textContent, initial)
2617+
assert.equal(el.shadowRoot.textContent, 'Wed, Jan 1, 2020, 9:00:00 PM')
2618+
})
2619+
2620+
test('ignores empty time-zone attributes', async () => {
2621+
const el = document.createElement('relative-time')
2622+
el.setAttribute('datetime', '2020-01-01T12:00:00.000Z')
2623+
el.setAttribute('time-zone', '')
2624+
el.setAttribute('format', 'datetime')
2625+
el.setAttribute('hour', 'numeric')
2626+
el.setAttribute('minute', '2-digit')
2627+
el.setAttribute('second', '2-digit')
2628+
await Promise.resolve()
2629+
// Should fallback to default or system time zone
2630+
assert.equal(el.shadowRoot.textContent, 'Wed, Jan 1, 2020, 4:00:00 PM')
2631+
})
2632+
2633+
test('uses html time-zone if element time-zone is empty', async () => {
2634+
const time = document.createElement('relative-time')
2635+
time.setAttribute('datetime', '2020-01-01T12:00:00.000Z')
2636+
time.setAttribute('time-zone', '')
2637+
document.documentElement.setAttribute('time-zone', 'Asia/Tokyo')
2638+
time.setAttribute('format', 'datetime')
2639+
time.setAttribute('hour', 'numeric')
2640+
time.setAttribute('minute', '2-digit')
2641+
time.setAttribute('second', '2-digit')
2642+
await Promise.resolve()
2643+
assert.equal(time.shadowRoot.textContent, 'Wed, Jan 1, 2020, 9:00:00 PM')
2644+
document.documentElement.removeAttribute('time-zone')
2645+
})
2646+
})
25892647
})

0 commit comments

Comments
 (0)