import { isDate, isISO8601 } from "class-validator"; import { DateOptions } from "../Column"; import { format, parse, parseISO } from "date-fns"; import { utcToZonedTime, zonedTimeToUtc } from "date-fns-tz"; import { zhCN } from "date-fns/locale"; export enum TimeFormat { TwelveHour = "12hour", TwentyFourHour = "24hour", } export enum AwareDate { LLL = "LLL", // 12小时 lll = "lll", // 24小时 LL = "LL", // 日期 L = "L", // 年月 } // 目前没有时区功能,默认设置为中国时区 export enum DateFormat { Local = "Local", Friendly = "Friendly", US = "US", European = "European", ISO = "ISO", } export type LocaleFormat = Record; type CustomLocale = { format: LocaleFormat; }; const zhCNLocale: CustomLocale = { format: { [AwareDate.L]: "yyyy年MM月", [AwareDate.LL]: "yyyy年MM月dd日", [AwareDate.LLL]: "yyyy年MM月dd日 hh:mm a", [AwareDate.lll]: "yyyy年MM月dd日 HH:mm", }, }; const euLocale: CustomLocale = { format: { [AwareDate.L]: "MM/yyyy", [AwareDate.LL]: "dd/MM/yyyy", [AwareDate.LLL]: "dd/MM/yyyy hh:mm a", [AwareDate.lll]: "dd/MM/yyyy HH:mm", }, }; const enUSLocale: CustomLocale = { format: { [AwareDate.L]: "MM/yyyy", [AwareDate.LL]: "MM/dd/yyyy", [AwareDate.LLL]: "MM/dd/yyyy hh:mm a", [AwareDate.lll]: "MM/dd/yyyy HH:mm", }, }; const ISOLocale: CustomLocale = { format: { [AwareDate.L]: "yyyy-MM", [AwareDate.LL]: "yyyy-MM-dd", [AwareDate.LLL]: "yyyy-MM-dd hh:mm a", [AwareDate.lll]: "yyyy-MM-dd HH:mm", }, }; const locals = { [DateFormat.Friendly]: zhCNLocale, [DateFormat.Local]: ISOLocale, [DateFormat.ISO]: ISOLocale, [DateFormat.European]: euLocale, [DateFormat.US]: enUSLocale, }; export function dateToString( dateOptions: DateOptions, dateStr: string | null ): string { if (!dateStr) { return ""; } const date = new Date(dateStr); if (!isDate(date)) { return ""; } else { const zonedDate = utcToZonedTime(date, "Asia/Shanghai"); let awareDate: AwareDate; if (!dateOptions.isDate) { awareDate = AwareDate.L; } else { awareDate = AwareDate.LL; if (dateOptions.isDateTime) { if (dateOptions.timeFormat === TimeFormat.TwelveHour) { awareDate = AwareDate.LLL; } else { awareDate = AwareDate.lll; } } } const locale = locals[dateOptions.dateFormat]; return format(zonedDate, locale.format[awareDate], { locale: zhCN }); } } function parseLocaleDateText(dateStr: string, locale: CustomLocale) { const parseDate = (format: AwareDate) => { const date = parse(dateStr, locale.format[format], new Date(), { locale: zhCN, }); if (isDate(date)) { return date; } return null; }; let date = parseDate(AwareDate.LLL); // 12小时 if (!date) { date = parseDate(AwareDate.lll); // 24小时 } if (!date) { date = parseDate(AwareDate.LL); // 日期 } if (!date) { date = parseDate(AwareDate.L); // 年月 } return date; } export function parseDateByString(dateStr: string) { if (!dateStr) { return null; } let date = parseLocaleDateText(dateStr, zhCNLocale); // yyyy年M月dd日 if (!date) { date = parseLocaleDateText(dateStr, ISOLocale); // yyyy-MM-dd } if (!date) { date = parseLocaleDateText(dateStr, enUSLocale); // MM-dd-yyyy } if (!date) { date = parseLocaleDateText(dateStr, euLocale); // dd-MM-yyyy } if (date) { return zonedTimeToUtc(date, "Asia/Shanghai"); // 非ISO字符串转换日期需要当作北京时间(+8)转为UTC(0) } if (isISO8601(dateStr, { strict: true })) { const isoDate = parseISO(dateStr); if (isDate(isoDate)) { return isoDate; } } return date; }