blakeblackshear.frigate/web/src/utils/dateUtil.ts

132 lines
5.1 KiB
TypeScript
Raw Normal View History

import strftime from 'strftime';
import { fromUnixTime, intervalToDuration, formatDuration } from 'date-fns';
2022-02-27 15:04:12 +01:00
export const longToDate = (long: number): Date => new Date(long * 1000);
export const epochToLong = (date: number): number => date / 1000;
export const dateToLong = (date: Date): number => epochToLong(date.getTime());
const getDateTimeYesterday = (dateTime: Date): Date => {
const twentyFourHoursInMilliseconds = 24 * 60 * 60 * 1000;
return new Date(dateTime.getTime() - twentyFourHoursInMilliseconds);
2022-02-26 20:11:00 +01:00
};
2022-02-27 15:04:12 +01:00
const getNowYesterday = (): Date => {
return getDateTimeYesterday(new Date());
2022-02-26 20:11:00 +01:00
};
2022-02-27 15:04:12 +01:00
export const getNowYesterdayInLong = (): number => {
return dateToLong(getNowYesterday());
};
/**
* This function takes in a Unix timestamp, configuration options for date/time display, and an optional strftime format string,
* and returns a formatted date/time string.
*
* If the Unix timestamp is not provided, it returns "Invalid time".
*
* The configuration options determine how the date and time are formatted.
* The `timezone` option allows you to specify a specific timezone for the output, otherwise the user's browser timezone will be used.
* The `use12hour` option allows you to display time in a 12-hour format if true, and 24-hour format if false.
* The `dateStyle` and `timeStyle` options allow you to specify pre-defined formats for displaying the date and time.
* The `strftime_fmt` option allows you to specify a custom format using the strftime syntax.
*
* If both `strftime_fmt` and `dateStyle`/`timeStyle` are provided, `strftime_fmt` takes precedence.
*
* @param unixTimestamp The Unix timestamp to format
* @param config An object containing the configuration options for date/time display
* @returns The formatted date/time string, or "Invalid time" if the Unix timestamp is not provided or invalid.
*/
interface DateTimeStyle {
timezone: string;
time_format: 'browser' | '12hour' | '24hour';
date_style: 'full' | 'long' | 'medium' | 'short';
time_style: 'full' | 'long' | 'medium' | 'short';
strftime_fmt: string;
}
export const formatUnixTimestampToDateTime = (unixTimestamp: number, config: DateTimeStyle): string => {
const { timezone, time_format, date_style, time_style, strftime_fmt } = config;
const locale = window.navigator?.language || 'en-us';
if (isNaN(unixTimestamp)) {
return 'Invalid time';
}
try {
const date = new Date(unixTimestamp * 1000);
// use strftime_fmt if defined in config file
if (strftime_fmt) {
const strftime_locale = strftime.timezone(getUTCOffset(date, timezone)).localizeByIdentifier(locale);
return strftime_locale(strftime_fmt, date);
}
// else use Intl.DateTimeFormat
const formatter = new Intl.DateTimeFormat(locale, {
dateStyle: date_style,
timeStyle: time_style,
timeZone: timezone || Intl.DateTimeFormat().resolvedOptions().timeZone,
hour12: time_format !== 'browser' ? time_format == '12hour' : undefined,
});
return formatter.format(date);
} catch (error) {
return 'Invalid time';
}
};
interface DurationToken {
xSeconds: string;
xMinutes: string;
xHours: string;
}
/**
* This function takes in start and end time in unix timestamp,
* and returns the duration between start and end time in hours, minutes and seconds.
* If end time is not provided, it returns 'In Progress'
* @param start_time: number - Unix timestamp for start time
* @param end_time: number|null - Unix timestamp for end time
* @returns string - duration or 'In Progress' if end time is not provided
*/
export const getDurationFromTimestamps = (start_time: number, end_time: number | null): string => {
if (isNaN(start_time)) {
return 'Invalid start time';
}
let duration = 'In Progress';
if (end_time !== null) {
if (isNaN(end_time)) {
return 'Invalid end time';
}
const start = fromUnixTime(start_time);
const end = fromUnixTime(end_time);
const formatDistanceLocale: DurationToken = {
xSeconds: '{{count}}s',
xMinutes: '{{count}}m',
xHours: '{{count}}h',
};
const shortEnLocale = {
formatDistance: (token: keyof DurationToken, count: number) =>
formatDistanceLocale[token].replace('{{count}}', count.toString()),
};
duration = formatDuration(intervalToDuration({ start, end }), {
format: ['hours', 'minutes', 'seconds'],
locale: shortEnLocale,
});
}
return duration;
};
/**
* Adapted from https://stackoverflow.com/a/29268535 this takes a timezone string and
* returns the offset of that timezone from UTC in minutes.
* @param timezone string representation of the timezone the user is requesting
* @returns number of minutes offset from UTC
*/
const getUTCOffset = (date: Date, timezone: string): number => {
const utcDate = new Date(date.getTime() - (date.getTimezoneOffset() * 60 * 1000));
// locale of en-CA is required for proper locale format
let iso = utcDate.toLocaleString('en-CA', { timeZone: timezone, hour12: false }).replace(', ', 'T');
iso += `.${utcDate.getMilliseconds().toString().padStart(3, '0')}`;
const target = new Date(`${iso}Z`);
return (target.getTime() - utcDate.getTime()) / 60 / 1000;
}