diff --git a/ts/util/formatTimestamp.ts b/ts/util/formatTimestamp.ts new file mode 100644 index 0000000000..832ce8f02a --- /dev/null +++ b/ts/util/formatTimestamp.ts @@ -0,0 +1,17 @@ +// Copyright 2023 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { assertDev } from './assert'; + +export function formatTimestamp( + timestamp: number, + options: Intl.DateTimeFormatOptions +): string { + const locale = window.getPreferredSystemLocales(); + try { + return new Intl.DateTimeFormat(locale, options).format(timestamp); + } catch (err) { + assertDev(false, 'invalid timestamp'); + return ''; + } +} diff --git a/ts/util/timestamp.ts b/ts/util/timestamp.ts index 7732f60b2a..90134fab1b 100644 --- a/ts/util/timestamp.ts +++ b/ts/util/timestamp.ts @@ -5,6 +5,7 @@ import type { Moment } from 'moment'; import moment from 'moment'; import type { LocalizerType } from '../types/Util'; import { DAY, HOUR, MINUTE, MONTH, WEEK } from './durations'; +import { formatTimestamp } from './formatTimestamp'; type RawTimestamp = Readonly; @@ -46,8 +47,6 @@ export function formatDateTimeShort( const now = Date.now(); const diff = now - timestamp; - const locale = window.getPreferredSystemLocales(); - if (diff < HOUR || isToday(timestamp)) { return formatTime(i18n, rawTimestamp, now); } @@ -55,23 +54,21 @@ export function formatDateTimeShort( const m = moment(timestamp); if (diff < WEEK && m.isSame(now, 'month')) { - return new Intl.DateTimeFormat(locale, { weekday: 'short' }).format( - timestamp - ); + return formatTimestamp(timestamp, { weekday: 'short' }); } if (m.isSame(now, 'year')) { - return new Intl.DateTimeFormat(locale, { + return formatTimestamp(timestamp, { day: 'numeric', month: 'short', - }).format(timestamp); + }); } - return new Intl.DateTimeFormat(locale, { + return formatTimestamp(timestamp, { day: 'numeric', month: 'short', year: 'numeric', - }).format(timestamp); + }); } export function formatDateTimeForAttachment( @@ -83,8 +80,6 @@ export function formatDateTimeForAttachment( const now = Date.now(); const diff = now - timestamp; - const locale = window.getPreferredSystemLocales(); - if (diff < HOUR || isToday(timestamp)) { return formatTime(i18n, rawTimestamp, now); } @@ -92,63 +87,62 @@ export function formatDateTimeForAttachment( const m = moment(timestamp); if (diff < WEEK && m.isSame(now, 'month')) { - return new Intl.DateTimeFormat(locale, { + return formatTimestamp(timestamp, { weekday: 'short', hour: 'numeric', minute: 'numeric', - }).format(timestamp); + }); } if (m.isSame(now, 'year')) { - return new Intl.DateTimeFormat(locale, { + return formatTimestamp(timestamp, { day: 'numeric', month: 'short', hour: 'numeric', minute: 'numeric', - }).format(timestamp); + }); } - return new Intl.DateTimeFormat(locale, { + return formatTimestamp(timestamp, { day: 'numeric', month: 'short', year: 'numeric', hour: 'numeric', minute: 'numeric', - }).format(timestamp); + }); } export function formatDateTimeLong( i18n: LocalizerType, rawTimestamp: RawTimestamp ): string { - const locale = window.getPreferredSystemLocales(); const timestamp = rawTimestamp.valueOf(); if (isToday(rawTimestamp)) { return i18n('icu:timestampFormat__long--today', { - time: new Intl.DateTimeFormat(locale, { + time: formatTimestamp(timestamp, { hour: 'numeric', minute: 'numeric', - }).format(timestamp), + }), }); } if (isYesterday(rawTimestamp)) { return i18n('icu:timestampFormat__long--yesterday', { - time: new Intl.DateTimeFormat(locale, { + time: formatTimestamp(timestamp, { hour: 'numeric', minute: 'numeric', - }).format(timestamp), + }), }); } - return new Intl.DateTimeFormat(locale, { + return formatTimestamp(timestamp, { day: 'numeric', hour: 'numeric', minute: 'numeric', month: 'short', year: 'numeric', - }).format(timestamp); + }); } export function formatTime( @@ -194,22 +188,21 @@ export function formatDate( return i18n('icu:yesterday'); } - const locale = window.getPreferredSystemLocales(); const m = moment(rawTimestamp); const timestamp = rawTimestamp.valueOf(); if (Math.abs(m.diff(Date.now())) < 6 * MONTH) { - return new Intl.DateTimeFormat(locale, { + return formatTimestamp(timestamp, { day: 'numeric', month: 'short', weekday: 'short', - }).format(timestamp); + }); } - return new Intl.DateTimeFormat(locale, { + return formatTimestamp(timestamp, { day: 'numeric', month: 'short', year: 'numeric', - }).format(timestamp); + }); }