import { DateTime } from 'luxon'; const DEFAULT_TIMEZONE = 'Etc/UTC'; const TimeEnumInSeconds = { SECOND: 1, MINUTE: 60, HOUR: 3600, DAY: 86400, }; const TimeEnumInMiliseconds = { SECOND: 1000, MINUTE: 60000, HOUR: 3600000, DAY: 86400000, }; const NumericDateToShortString = { '01': 'Jan', '02': 'Feb', '03': 'Mar', '04': 'Apr', '05': 'May', '06': 'Jun', '07': 'Jul', '08': 'Aug', '09': 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec', }; const currentBrowserTimezone = (): string => { return Intl.DateTimeFormat().resolvedOptions().timeZone; }; const timezoneAbbreviation = (timezone = DEFAULT_TIMEZONE): string => { return DateTime.fromObject({ zone: timezone ?? DEFAULT_TIMEZONE }).offsetNameShort; }; /** * Returns a signed integer representing the timezone offset in hours. */ const timezoneOffset = (timezone = DEFAULT_TIMEZONE): number => { return DateTime.fromObject({ zone: timezone ?? DEFAULT_TIMEZONE }).offset / TimeEnumInSeconds.MINUTE; }; const formattedTimezoneWithOffset = (timezone = DEFAULT_TIMEZONE): string => { const offset = timezoneOffset(timezone); return `${timezoneAbbreviation(timezone)} ${offset >= 0 ? `(+${offset}:00)` : `(${offset}:00)`}`; }; const now = (timezone: string = DEFAULT_TIMEZONE): number => { return DateTime.fromMillis(DateTime.now().toMillis(), { zone: timezone }).toMillis(); }; const fromNow = (millis: number | string, timezone = DEFAULT_TIMEZONE): number => { if (typeof millis === 'string') millis = Number(millis); return now(timezone) + millis; }; const date = (millis: number | string, timezone = DEFAULT_TIMEZONE): DateTime => { if (typeof millis === 'string') millis = Number(millis); return DateTime.fromMillis(millis, { zone: timezone }); }; const dateFromIso = (isoDate: string, timezone = DEFAULT_TIMEZONE): DateTime => { return DateTime.fromISO(isoDate, { zone: timezone }); }; const dateToIso = (millis: number): string => { return DateTime.fromMillis(millis).toISO(); }; const dateToSeconds = (millis: number): number => { return Math.round(millis / 1000); }; const dateToLocaleDateString = (millis: number): string => { const date = new Date(millis); return date.toLocaleDateString(); }; const is24HoursLater = (millis: number): boolean => { const now = new Date().getTime(); const oneDayLater = millis + (1000 * 60 * 60 * 24); return now > oneDayLater; }; /** * See https://moment.github.io/luxon/#/formatting?id=table-of-tokens * for formatting rules */ const format = (millis: number | string, format: string = 'DD', timezone: string = DEFAULT_TIMEZONE): string => { if (typeof millis === 'string') millis = Number(millis); return date(millis, timezone).toFormat(format); }; const yearStart = function (year: number | undefined = undefined, timezone = DEFAULT_TIMEZONE): number { const rightNow = DateTime.fromMillis(now(), { zone: timezone }); return DateTime.local(year ?? rightNow.year).toMillis(); }; const dayStart = function (millis: number, timezone = DEFAULT_TIMEZONE): number { const date = DateTime.fromMillis(millis, { zone: timezone }); return DateTime.utc(date.year, date.month, date.day).toMillis(); }; export const formattedCountDown = (millisStart: number, millisEnd: number): string => { const totalSeconds = millisEnd - millisStart; const days = Math.floor(totalSeconds / 86400000); const hours = Math.floor((totalSeconds % 86400000) / 3600000); const minutes = Math.floor(((totalSeconds % 86400000) % 3600000) / 60000); const seconds = Math.floor((((totalSeconds % 86400000) % 3600000) % 60000) / 1000); if (minutes === 0 && hours === 0 && days === 0) return `${seconds}s`; if (hours === 0 && days === 0) return `${minutes}m ${seconds}s`; if (days === 0) return `${hours}h ${minutes}m ${seconds}s`; return `${days}d ${hours}h ${minutes}m ${seconds}s`; }; const TimeUtil = { TimeEnumInSeconds, TimeEnumInMiliseconds, NumericDateToShortString, currentBrowserTimezone, timezoneAbbreviation, formattedTimezoneWithOffset, timezoneOffset, now, fromNow, date, dateFromIso, dateToIso, dateToSeconds, dateToLocaleDateString, format, yearStart, dayStart, formattedCountDown, is24HoursLater, }; export default TimeUtil;