mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-05 04:57:42 +03:00
refactor formatUnixTimestampToDateTime
Use date-fns style instead of using strftime. This requires changing the i18n keys to the way date-fns represents dates (eg: "MMM d, h:mm:ss aaa" instead of "%b %-d, %H:%M"
This commit is contained in:
parent
5dda6f8f54
commit
6829843e8d
@ -1,5 +1,6 @@
|
|||||||
import strftime from "strftime";
|
|
||||||
import { fromUnixTime, intervalToDuration, formatDuration } from "date-fns";
|
import { fromUnixTime, intervalToDuration, formatDuration } from "date-fns";
|
||||||
|
import { Locale } from "date-fns/locale";
|
||||||
|
import { formatInTimeZone } from "date-fns-tz";
|
||||||
export const longToDate = (long: number): Date => new Date(long * 1000);
|
export const longToDate = (long: number): Date => new Date(long * 1000);
|
||||||
export const epochToLong = (date: number): number => date / 1000;
|
export const epochToLong = (date: number): number => date / 1000;
|
||||||
export const dateToLong = (date: Date): number => epochToLong(date.getTime());
|
export const dateToLong = (date: Date): number => epochToLong(date.getTime());
|
||||||
@ -108,11 +109,19 @@ const getResolvedTimeZone = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type DateTimeStyle = {
|
||||||
|
timezone?: string;
|
||||||
|
time_format?: "browser" | "12hour" | "24hour";
|
||||||
|
date_style?: "full" | "long" | "medium" | "short";
|
||||||
|
time_style?: "full" | "long" | "medium" | "short";
|
||||||
|
date_format?: string;
|
||||||
|
locale?: string | Locale;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Formats a Unix timestamp into a human-readable date/time string.
|
* Formats a Unix timestamp into a human-readable date/time string.
|
||||||
*
|
*
|
||||||
* The format of the output string is determined by a configuration object passed as an argument, which
|
* The format of the output string is determined by a configuration object passed as an argument, which
|
||||||
* may specify a time zone, 12- or 24-hour time, and various stylistic options for the date and time.
|
* may specify a time zone, 12- or 24-hour time, various stylistic options for the date and time, and a locale.
|
||||||
* If these options are not specified, the function will use system defaults or sensible fallbacks.
|
* If these options are not specified, the function will use system defaults or sensible fallbacks.
|
||||||
*
|
*
|
||||||
* The function is robust to environments where the Intl API is not fully supported, and includes a
|
* The function is robust to environments where the Intl API is not fully supported, and includes a
|
||||||
@ -126,53 +135,71 @@ const getResolvedTimeZone = () => {
|
|||||||
*/
|
*/
|
||||||
export const formatUnixTimestampToDateTime = (
|
export const formatUnixTimestampToDateTime = (
|
||||||
unixTimestamp: number,
|
unixTimestamp: number,
|
||||||
config: {
|
config: DateTimeStyle = {},
|
||||||
timezone?: string;
|
|
||||||
time_format?: "browser" | "12hour" | "24hour";
|
|
||||||
date_style?: "full" | "long" | "medium" | "short";
|
|
||||||
time_style?: "full" | "long" | "medium" | "short";
|
|
||||||
strftime_fmt?: string;
|
|
||||||
},
|
|
||||||
): string => {
|
): string => {
|
||||||
const { timezone, time_format, date_style, time_style, strftime_fmt } =
|
const { timezone, time_format, date_style, time_style, date_format, locale } =
|
||||||
config;
|
config;
|
||||||
const locale = window.navigator?.language || "en-US";
|
|
||||||
|
// Determine the locale to use
|
||||||
|
let localeCode: string;
|
||||||
|
let dateFnsLocale: Locale | undefined;
|
||||||
|
if (typeof locale === "string") {
|
||||||
|
localeCode = locale;
|
||||||
|
} else if (locale && "code" in locale) {
|
||||||
|
localeCode = (locale as Locale).code || "en-US";
|
||||||
|
dateFnsLocale = locale as Locale;
|
||||||
|
} else {
|
||||||
|
localeCode = window.navigator?.language || "en-US";
|
||||||
|
}
|
||||||
|
|
||||||
if (isNaN(unixTimestamp)) {
|
if (isNaN(unixTimestamp)) {
|
||||||
return "Invalid time";
|
return "Invalid time";
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const date = new Date(unixTimestamp * 1000);
|
const date = new Date(unixTimestamp * 1000);
|
||||||
const resolvedTimeZone = getResolvedTimeZone();
|
|
||||||
|
|
||||||
// use strftime_fmt if defined in config
|
if (date_format) {
|
||||||
if (strftime_fmt) {
|
const resolvedTimeZone = timezone || getResolvedTimeZone();
|
||||||
const offset = getUTCOffset(date, timezone || resolvedTimeZone);
|
let formatted = formatInTimeZone(date, resolvedTimeZone, date_format, {
|
||||||
const strftime_locale = strftime.timezone(offset);
|
locale: dateFnsLocale,
|
||||||
return strftime_locale(strftime_fmt, date);
|
});
|
||||||
|
// Uppercase AM/PM for 12-hour formats
|
||||||
|
if (date_format.includes("a") || date_format.includes("aaa")) {
|
||||||
|
formatted = formatted.replace(/am|pm/gi, (match) =>
|
||||||
|
match.toUpperCase(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DateTime format options
|
// DateTime format options
|
||||||
const options: Intl.DateTimeFormatOptions = {
|
const options: Intl.DateTimeFormatOptions = {
|
||||||
dateStyle: date_style,
|
dateStyle: date_style,
|
||||||
timeStyle: time_style,
|
timeStyle: time_style,
|
||||||
hour12: time_format !== "browser" ? time_format == "12hour" : undefined,
|
hour12: time_format !== "browser" ? time_format === "12hour" : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only set timeZone option when resolvedTimeZone does not match UTC±HH:MM format, or when timezone is set in config
|
// Only set timeZone option when resolvedTimeZone does not match UTC±HH:MM format, or when timezone is set in config
|
||||||
|
const resolvedTimeZone = getResolvedTimeZone();
|
||||||
const isUTCOffsetFormat = /^UTC[+-]\d{2}:\d{2}$/.test(resolvedTimeZone);
|
const isUTCOffsetFormat = /^UTC[+-]\d{2}:\d{2}$/.test(resolvedTimeZone);
|
||||||
if (timezone || !isUTCOffsetFormat) {
|
if (timezone || !isUTCOffsetFormat) {
|
||||||
options.timeZone = timezone || resolvedTimeZone;
|
options.timeZone = timezone || resolvedTimeZone;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatter = new Intl.DateTimeFormat(locale, options);
|
const formatter = new Intl.DateTimeFormat(localeCode, options);
|
||||||
const formattedDateTime = formatter.format(date);
|
let formattedDateTime = formatter.format(date);
|
||||||
|
|
||||||
// Regex to check for existence of time. This is needed because dateStyle/timeStyle is not always supported.
|
if (options.hour12) {
|
||||||
|
formattedDateTime = formattedDateTime.replace(/am|pm/gi, (match) =>
|
||||||
|
match.toUpperCase(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regex to check for existence of time
|
||||||
const containsTime = /\d{1,2}:\d{1,2}/.test(formattedDateTime);
|
const containsTime = /\d{1,2}:\d{1,2}/.test(formattedDateTime);
|
||||||
|
|
||||||
// fallback if the browser does not support dateStyle/timeStyle in Intl.DateTimeFormat
|
// fallback if the browser does not support dateStyle/timeStyle
|
||||||
// This works even tough the timezone is undefined, it will use the runtime's default time zone
|
|
||||||
if (!containsTime) {
|
if (!containsTime) {
|
||||||
const dateOptions = {
|
const dateOptions = {
|
||||||
...formatMap[date_style ?? ""]?.date,
|
...formatMap[date_style ?? ""]?.date,
|
||||||
@ -185,10 +212,17 @@ export const formatUnixTimestampToDateTime = (
|
|||||||
hour12: options.hour12,
|
hour12: options.hour12,
|
||||||
};
|
};
|
||||||
|
|
||||||
return `${date.toLocaleDateString(
|
let fallbackFormatted = `${date.toLocaleDateString(
|
||||||
locale,
|
localeCode,
|
||||||
dateOptions,
|
dateOptions,
|
||||||
)} ${date.toLocaleTimeString(locale, timeOptions)}`;
|
)} ${date.toLocaleTimeString(localeCode, timeOptions)}`;
|
||||||
|
// Uppercase AM/PM in fallback
|
||||||
|
if (options.hour12) {
|
||||||
|
fallbackFormatted = fallbackFormatted.replace(/am|pm/gi, (match) =>
|
||||||
|
match.toUpperCase(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return fallbackFormatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
return formattedDateTime;
|
return formattedDateTime;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user