| | import type { FormatOptions as DateFnsFormatOptions } from "date-fns"; |
| |
|
| | import type { DateLibOptions } from "../../classes/DateLib.js"; |
| | import { getMonthCode } from "../utils/calendarMath.js"; |
| | import { toHebrewDate } from "../utils/dateConversion.js"; |
| | import { hebrewMonthNumber } from "../utils/serial.js"; |
| |
|
| | const fallbackMonthNames: Record<string, { en: string; he: string }> = { |
| | tishrei: { en: "Tishrei", he: "转砖专讬" }, |
| | cheshvan: { en: "Cheshvan", he: "讞砖讜讜谉" }, |
| | kislev: { en: "Kislev", he: "讻住诇讜" }, |
| | tevet: { en: "Tevet", he: "讟讘转" }, |
| | shevat: { en: "Shevat", he: "砖讘讟" }, |
| | adarI: { en: "Adar I", he: "讗讚专 讗壮" }, |
| | adar: { en: "Adar", he: "讗讚专" }, |
| | nisan: { en: "Nisan", he: "谞讬住谉" }, |
| | iyar: { en: "Iyar", he: "讗讬讬专" }, |
| | sivan: { en: "Sivan", he: "住讬讜讜谉" }, |
| | tamuz: { en: "Tammuz", he: "转诪讜讝" }, |
| | av: { en: "Av", he: "讗讘" }, |
| | elul: { en: "Elul", he: "讗诇讜诇" }, |
| | }; |
| |
|
| | const fallbackWeekdayNames = { |
| | long: { |
| | en: [ |
| | "Sunday", |
| | "Monday", |
| | "Tuesday", |
| | "Wednesday", |
| | "Thursday", |
| | "Friday", |
| | "Saturday", |
| | ], |
| | he: [ |
| | "讬讜诐 专讗砖讜谉", |
| | "讬讜诐 砖谞讬", |
| | "讬讜诐 砖诇讬砖讬", |
| | "讬讜诐 专讘讬注讬", |
| | "讬讜诐 讞诪讬砖讬", |
| | "讬讜诐 砖讬砖讬", |
| | "砖讘转", |
| | ], |
| | }, |
| | narrow: { |
| | en: ["S", "M", "T", "W", "T", "F", "S"], |
| | he: ["讗", "讘", "讙", "讚", "讛", "讜", "砖"], |
| | }, |
| | }; |
| |
|
| | const getLocaleCode = (options?: DateLibOptions): string => { |
| | return options?.locale?.code ?? "he"; |
| | }; |
| |
|
| | const getMonthCodeForDate = (date: Date) => { |
| | const hebrew = toHebrewDate(date); |
| | return getMonthCode(hebrew.year, hebrew.monthIndex); |
| | }; |
| |
|
| | const formatMonthName = (date: Date, localeCode: string): string => { |
| | try { |
| | return new Intl.DateTimeFormat(localeCode, { |
| | month: "long", |
| | calendar: "hebrew", |
| | }).format(date); |
| | } catch { |
| | const code = getMonthCodeForDate(date); |
| | const isHebrew = localeCode.startsWith("he"); |
| | return isHebrew ? fallbackMonthNames[code].he : fallbackMonthNames[code].en; |
| | } |
| | }; |
| |
|
| | const formatWeekdayName = ( |
| | date: Date, |
| | localeCode: string, |
| | width: "long" | "narrow", |
| | ): string => { |
| | try { |
| | return new Intl.DateTimeFormat(localeCode, { |
| | weekday: width, |
| | calendar: "hebrew", |
| | }).format(date); |
| | } catch { |
| | const index = date.getDay(); |
| | const isHebrew = localeCode.startsWith("he"); |
| | return isHebrew |
| | ? fallbackWeekdayNames[width].he[index] |
| | : fallbackWeekdayNames[width].en[index]; |
| | } |
| | }; |
| |
|
| | const formatDateStyle = ( |
| | date: Date, |
| | localeCode: string, |
| | style: "long" | "full", |
| | ): string => { |
| | try { |
| | return new Intl.DateTimeFormat(localeCode, { |
| | dateStyle: style, |
| | calendar: "hebrew", |
| | }).format(date); |
| | } catch { |
| | const hebrew = toHebrewDate(date); |
| | const month = formatMonthName(date, localeCode); |
| | if (style === "full") { |
| | const weekday = formatWeekdayName(date, localeCode, "long"); |
| | return `${weekday}, ${month} ${hebrew.day}, ${hebrew.year}`; |
| | } |
| | return `${month} ${hebrew.day}, ${hebrew.year}`; |
| | } |
| | }; |
| |
|
| | const formatNumber = (value: number): string => { |
| | return value.toString(); |
| | }; |
| |
|
| | const buildTimeFormat = ( |
| | date: Date, |
| | localeCode: string, |
| | formatStr: string, |
| | ): string => { |
| | const hour12 = formatStr.includes("a"); |
| | return new Intl.DateTimeFormat(localeCode, { |
| | hour: "numeric", |
| | minute: "numeric", |
| | hour12, |
| | }).format(date); |
| | }; |
| |
|
| | |
| | export function format( |
| | date: Date, |
| | formatStr: string, |
| | options?: DateFnsFormatOptions, |
| | ): string { |
| | const extendedOptions = options as DateLibOptions | undefined; |
| | const localeCode = getLocaleCode(extendedOptions); |
| | const hebrew = toHebrewDate(date); |
| | const monthNumber = hebrewMonthNumber(hebrew.monthIndex); |
| |
|
| | switch (formatStr) { |
| | case "LLLL y": |
| | case "LLLL yyyy": |
| | return `${formatMonthName(date, localeCode)} ${formatNumber(hebrew.year)}`; |
| | case "LLLL": |
| | return formatMonthName(date, localeCode); |
| | case "PPP": |
| | return formatDateStyle(date, localeCode, "long"); |
| | case "PPPP": |
| | return formatDateStyle(date, localeCode, "full"); |
| | case "cccc": |
| | return formatWeekdayName(date, localeCode, "long"); |
| | case "cccccc": |
| | return formatWeekdayName(date, localeCode, "narrow"); |
| | case "yyyy": |
| | case "y": |
| | return formatNumber(hebrew.year); |
| | case "yyyy-MM": |
| | return `${formatNumber(hebrew.year)}-${formatNumber(monthNumber).padStart(2, "0")}`; |
| | case "yyyy-MM-dd": |
| | return `${formatNumber(hebrew.year)}-${formatNumber(monthNumber).padStart(2, "0")}-${formatNumber(hebrew.day).padStart(2, "0")}`; |
| | case "MM": |
| | return formatNumber(monthNumber).padStart(2, "0"); |
| | case "M": |
| | return formatNumber(monthNumber); |
| | case "dd": |
| | return formatNumber(hebrew.day).padStart(2, "0"); |
| | case "d": |
| | return formatNumber(hebrew.day); |
| | default: |
| | if (/[Hh]/.test(formatStr) && /m/.test(formatStr)) { |
| | return buildTimeFormat(date, localeCode, formatStr); |
| | } |
| | return `${formatNumber(hebrew.day)}/${formatNumber(monthNumber)}/${formatNumber(hebrew.year)}`; |
| | } |
| | } |
| |
|