blob: 6fd085d9c7967c6f658189195b3a7fa6a795aa96 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
// Temporal display helpers: format ISO instants for the viewer's timezone.
/** Format an ISO instant in the viewer's timezone. */
export function formatInstant(
iso: string,
options: Intl.DateTimeFormatOptions,
): string {
return Temporal.Instant.from(iso)
.toZonedDateTimeISO(Temporal.Now.timeZoneId())
.toLocaleString('fr-FR', options);
}
/** Short day-month stamp ("8 sept."). */
export function formatDayMonth(iso: string): string {
return formatInstant(iso, { day: 'numeric', month: 'short' });
}
/** Day-month-year stamp ("8 sept. 2026"). */
export function formatDayMonthYear(iso: string): string {
return formatInstant(iso, {
day: 'numeric',
month: 'short',
year: 'numeric',
});
}
const ONE_DAY_MS = 86_400_000;
/**
* Stamp to store for a `YYYY-MM-DD` form day: noon UTC — a midnight stamp can
* read back as the wrong day in a timezone ahead of UTC. Clamped to `now` when
* the day is still ahead of the clock, and null for a malformed day or one
* more than a day in the future (timezones ahead of UTC make "today" fuzzy).
*/
export function instantFromDay(
day: string,
now: Temporal.Instant,
): string | null {
let midnight: Temporal.Instant;
try {
midnight = Temporal.PlainDate.from(day.trim())
.toZonedDateTime('UTC')
.toInstant();
} catch {
return null;
}
const noon = midnight.add({ hours: 12 });
if (noon.epochMilliseconds - now.epochMilliseconds > ONE_DAY_MS) return null;
const stamp = Temporal.Instant.compare(noon, now) > 0 ? now : noon;
return stamp.toString({ smallestUnit: 'millisecond' });
}
|