* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat
*
* Time stamps are given in milliseconds since the epoch.
*/
import cockpit from "cockpit";
const _ = cockpit.gettext;
export const dateFormatLang = (): string => cockpit.language.replace('_', '-');
type Time = Date | number;
export const formatter = (options?: Intl.DateTimeFormatOptions) => new Intl.DateTimeFormat(dateFormatLang(), options);
export const time = (t: Time): string => formatter({ timeStyle: "short" }).format(t);
export const timeSeconds = (t: Time): string => formatter({ timeStyle: "medium" }).format(t);
export const date = (t: Time): string => formatter({ dateStyle: "long" }).format(t);
export const dateShort = (t: Time): string => formatter().format(t);
export const dateTime = (t: Time): string => formatter({ dateStyle: "medium", timeStyle: "short" }).format(t);
export const dateTimeUTC = (t: Time): string => formatter({ dateStyle: "medium", timeStyle: "short", timeZone: "UTC" }).format(t);
export const dateTimeSeconds = (t: Time): string => formatter({ dateStyle: "medium", timeStyle: "medium" }).format(t);
export const dateTimeNoYear = (t: Time): string => formatter({ month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }).format(t);
export const weekdayDate = (t: Time): string => formatter({ dateStyle: "full" }).format(t);
const units: { name: Intl.RelativeTimeFormatUnit, max: number }[] = [
{ name: "second", max: 60 },
{ name: "minute", max: 3600 },
{ name: "hour", max: 86400 },
{ name: "day", max: 86400 * 7 },
{ name: "week", max: 86400 * 30 },
{ name: "month", max: 86400 * 365 },
{ name: "year", max: Infinity },
];
export function distanceToNow(t: Time): string {
const t_timestamp = t?.valueOf() ?? t;
const secondsDiff = Math.round((t_timestamp - Date.now()) / 1000);
if (secondsDiff <= 0 && secondsDiff > -60)
return _("less than a minute ago");
if (secondsDiff > 0 && secondsDiff < 60)
return _("in less than a minute");
const unitIndex = units.findIndex(u => u.max > Math.abs(secondsDiff));
const divisor = unitIndex ? units[unitIndex - 1].max : 1;
const formatter = new Intl.RelativeTimeFormat(dateFormatLang(), { numeric: "auto" });
return formatter.format(Math.round(secondsDiff / divisor), units[unitIndex].name);
}
* sorely missing from Intl: https://github.com/tc39/ecma402/issues/6
* based on https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/weekData.json#L59
* However, we don't have translations for most locales, and cockpit.language does not even contain
* the country in most cases, so this is just an approximation.
* Most locales start the week on Monday (day 1), so default to that and enumerate the others.
*/
const first_dow_sun = ['en', 'ja', 'ko', 'pt', 'pt_BR', 'sv', 'zh_CN', 'zh_TW'];
export function firstDayOfWeek(): number {
return first_dow_sun.indexOf(cockpit.language) >= 0 ? 0 : 1;
}