import { format, formatISO, isBefore, isEqual, isWithinInterval, parse, parseISO as stdParseISO } from 'date-fns'; import type { OptionalString } from '../utils'; export const STANDARD_DATE_FORMAT = 'yyyy-MM-dd'; export const STANDARD_DATE_AND_TIME_FORMAT = 'yyyy-MM-dd HH:mm'; export type DateOrString = Date | string; type NullableDate = DateOrString | null; export const now = () => new Date(); export const isDateObject = (date: DateOrString): date is Date => typeof date !== 'string'; const formatDateFromFormat = (date?: NullableDate, theFormat?: string): OptionalString => { if (!date || !isDateObject(date)) { return date; } return theFormat ? format(date, theFormat) : formatISO(date); }; export const formatDate = (theFormat = STANDARD_DATE_FORMAT) => (date?: NullableDate) => formatDateFromFormat( date, theFormat, ); export const formatIsoDate = (date?: NullableDate) => formatDateFromFormat(date, undefined); export const formatInternational = formatDate(); export const formatHumanFriendly = formatDate(STANDARD_DATE_AND_TIME_FORMAT); export const parseDate = (date: string, theFormat: string) => parse(date, theFormat, now()); export const parseISO = (date: DateOrString): Date => (isDateObject(date) ? date : stdParseISO(date)); export const dateOrNull = (date?: string): Date | null => (date ? parseISO(date) : null); export const isBetween = (date: DateOrString, start?: DateOrString, end?: DateOrString): boolean => { try { return isWithinInterval(parseISO(date), { start: parseISO(start ?? date), end: parseISO(end ?? date) }); } catch (e) { return false; } }; export const isBeforeOrEqual = (date: Date | number, dateToCompare: Date | number) => isEqual(date, dateToCompare) || isBefore(date, dateToCompare);