import { differenceInDays, format, formatDistanceToNow, startOfDay, startOfMinute, startOfMonth, startOfWeek, startOfYear } from "date-fns"; export type DateFormatType = "YYYY-MM-DD" | "DD-MM-YYYY" | "MM-DD-YYYY" | "diff"; export const DateFormats: { name: string; value: DateFormatType; labelKey: string }[] = [ { name: "YYYY-MM-DD", value: "YYYY-MM-DD", labelKey: "formats.date.ymd" }, { name: "DD-MM-YYYY", value: "DD-MM-YYYY", labelKey: "formats.date.dmy" }, { name: "MM-DD-YYYY", value: "MM-DD-YYYY", labelKey: "formats.date.mdy" }, { name: "Difference", value: "diff", labelKey: "formats.date.diff" }, ]; export type DateDisplay = "ymd" | "ago" | "dm" | "mdy" | "hms" | "ymdhms" | "ymdhmsms"; const coerce = (value: Date | string | null | undefined): Date => { if (value === null || value === undefined) return new Date(); return value instanceof Date ? value : new Date(value); }; const fmt = (value: Date | string | null | undefined, pattern: string): string => { return format(coerce(value), pattern); }; const dateAgo = (value: Date | string | null | undefined): string => { const at = coerce(value); const days = Math.abs(differenceInDays(new Date(), at)); if (days <= 1) { return formatDistanceToNow(startOfMinute(at), { addSuffix: true }); } else if (days <= 7) { return formatDistanceToNow(startOfDay(at), { addSuffix: true }); } else if (days <= 30) { return formatDistanceToNow(startOfWeek(at), { addSuffix: true }); } else if (days <= 30 * 12) { return formatDistanceToNow(startOfMonth(at), { addSuffix: true }); } else if (days <= 30 * 12 * 2) { return formatDistanceToNow(startOfYear(at), { addSuffix: true }); } else { return fmt(at, "yyyy-MM-dd"); } }; const dateYMD = (value: Date | string | null | undefined): string => fmt(value, "yyyy-MM-dd"); const dateDMY = (value: Date | string | null | undefined): string => fmt(value, "dd-MM-yyyy"); const dateMDY = (value: Date | string | null | undefined): string => fmt(value, "MM-dd-yyyy"); const dateLL = (value: Date | string | null | undefined): string => fmt(value, "yyyy-MM-dd"); const dateYMDHM = (value: Date | string | null | undefined): string => fmt(value, "yyyy-MM-dd HH:mm"); const dateYMDHMS = (value: Date | string | null | undefined): string => fmt(value, "yyyy-MM-dd HH:mm:ss"); const dateYMDHMSMS = (value: Date | string | null | undefined): string => fmt(value, "yyyy-MM-dd HH:mm:ss.SSS"); const dateMonthName = (value: Date | string | null | undefined): string => fmt(value, "MMMM yyyy"); const dateDM = (value: Date | string | null | undefined): string => fmt(value, "d MMM"); const dateMonthDayYear = (value: Date | string | null | undefined): string => fmt(value, "MMMM d, yyyy"); const dateMonthDay = (value: Date | string | null | undefined): string => fmt(value, "MMM d"); const dateHMS = (value: Date | string | null | undefined): string => fmt(value, "HH:mm:ss"); const daysFromDate = (value: Date, days: number) => { return new Date(new Date().setDate(value.getDate() + days)); }; const diffDays = (a: Date, b: Date) => { const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()); const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate()); const _MS_PER_DAY = 1000 * 60 * 60 * 24; return (utc2 - utc1) / _MS_PER_DAY; }; const add = (value: Date, days: number) => { return new Date(new Date().setDate(value.getDate() + days)); }; const getMonths = () => { return ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; }; const getMonthName = (month: number): string => { const months: string[] = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; if (month >= 1 && month <= 12) { return months[month - 1].substring(0, 3); } return ""; }; const isCurrentMonth = (year: number, month: number): boolean => { const today = new Date(); return today.getFullYear() === year && today.getMonth() + 1 === month; }; const gteFromFilter = (filter: string, from?: Date) => { let gte: Date | undefined = undefined; if (!from) { from = new Date(); } if (filter === "all-time") { gte = undefined; } else if (filter === "last-24-hours") { gte = daysFromDate(from, 1 * -1); } else if (filter === "last-7-days") { gte = daysFromDate(from, 7 * -1); } else if (filter === "last-30-days") { gte = daysFromDate(from, 30 * -1); } else if (filter === "last-3-months") { gte = daysFromDate(from, 30 * 3 * -1); } else if (filter === "last-6-months") { gte = daysFromDate(from, 30 * 6 * -1); } else if (filter === "last-year") { gte = daysFromDate(from, 30 * 12 * -1); } else if (filter === "year-to-date") { gte = new Date(from.getFullYear(), 0, 1); } else if (filter === "month-to-date") { gte = new Date(from.getFullYear(), from.getMonth(), 1); } else if (filter === "week-to-date") { gte = new Date(from.getFullYear(), from.getMonth(), from.getDate() - from.getDay()); } else if (filter === "last-hour") { gte = new Date(from.getTime() - 60 * 60 * 1000); } else if (filter === "last-10-minutes") { gte = new Date(from.getTime() - 10 * 60 * 1000); } return gte; }; const getDuration = ({ start, end, format = "s" }: { start: Date; end: Date; format: "ms" | "s" | "m" | "h" | "d" | "w" | "M" | "y" }) => { const diff = +new Date(end) - +new Date(start); const seconds = Math.floor(diff / 1000); switch (format) { case "ms": return diff; case "s": return seconds; case "m": return Math.floor(seconds / 60); case "h": return Math.floor(seconds / 3600); case "d": return Math.floor(seconds / 86400); case "w": return Math.floor(seconds / 604800); case "M": return Math.floor(seconds / 2592000); case "y": return Math.floor(seconds / 31536000); default: return diff; } }; function getDurationInSeconds({ start, end }: { start: Date | null; end: Date | null }) { if (start && end) { const diff = +new Date(end) - +new Date(start); const seconds = Math.floor(diff / 1000); if (seconds < 60) { return `${seconds}s`; } else { return `${Math.floor(seconds / 60)}m ${seconds % 60}s`; } } return "-"; } function getDateStartOfDay(date: Date) { return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0); } function getDateEndOfDay(date: Date) { return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999); } export default { dateAgo, dateYMD, dateDMY, dateMDY, dateLL, dateYMDHM, dateYMDHMS, dateYMDHMSMS, dateMonthName, dateDM, dateHMS, dateMonthDayYear, dateMonthDay, daysFromDate, diffDays, add, getMonths, getMonthName, isCurrentMonth, gteFromFilter, getDuration, getDurationInSeconds, getDateStartOfDay, getDateEndOfDay, };