UNPKG

jtc-utils

Version:
106 lines (98 loc) 2.91 kB
import { isValid, parse, parseISO } from "date-fns"; import { JapaneseEra } from "./JapaneseEra.cjs"; import { type Locale, enUS, ja } from "./locale/index.cjs"; import { DateFormat } from "./util/DateFormat.cjs"; import { getLocale } from "./util/getLocale.cjs"; import { getTimeZone } from "./util/getTimeZone.cjs"; import { getTimeZoneOffset } from "./util/getTimeZoneOffset.cjs"; declare type ParseDateOptions = { locale?: Locale; timeZone?: string; }; export function parseDate( str: string, format?: string, options?: ParseDateOptions, ): Date; export function parseDate( str: null | undefined, format?: string, options?: ParseDateOptions, ): undefined; export function parseDate( str: string | null | undefined, format?: string, options?: ParseDateOptions, ) { if (str == null) { return undefined; } const locale = options?.locale ?? (/^ja(-|$)/i.test(getLocale()) ? ja : enUS); const timeZone = options?.timeZone; try { let dDate: Date; if (!format) { dDate = parseISO(str); if (!isValid(dDate)) { return null; } if ( timeZone && timeZone !== getTimeZone() && !/(Z|[+-][0-9]{2}(:?[0-9]{2})?)$/.test(str) ) { dDate = new Date(dDate.getTime() + getTimeZoneOffset(dDate, timeZone)); } } else { const parseOptions: Parameters<typeof parse>[3] = { locale }; let era: JapaneseEra | undefined; if (locale.code && /^ja-JP-u-ca-japanese$/i.test(locale.code)) { parseOptions.locale = <Locale>{ ...locale, match: { ...locale.match, era(dateString: string, options: Record<string, unknown>) { let m: RegExpExecArray | null; if ( (m = /^([MTSHR]|明治?|大正?|昭和?|平成?|令和?)/.exec( dateString, )) != null ) { era = JapaneseEra.from(m[0], { locale: "ja" }); return { value: 1, rest: dateString.substring(m[0].length), }; } else { return locale.match?.era(dateString, options); } }, }, }; } dDate = parse(str, format, new Date(), parseOptions); if (!isValid(dDate)) { return null; } if (era) { dDate.setFullYear(dDate.getFullYear() + era.start.getFullYear() - 1); } if ( timeZone && timeZone !== getTimeZone() && !DateFormat.get(format).parts.some( (part) => part.type === "pattern" && /^[xX]/.test(part.text), ) ) { dDate = new Date(dDate.getTime() + getTimeZoneOffset(dDate, timeZone)); } } return dDate; } catch (err) { if (err instanceof RangeError) { return null; } else { throw err; } } }