| import { TZDate } from "@date-fns/tz"; |
| import type { |
| FormatOptions as DateFnsFormatOptions, |
| EndOfWeekOptions, |
| GetMonthOptions, |
| GetWeekOptions, |
| GetYearOptions, |
| Interval, |
| StartOfWeekOptions, |
| } from "date-fns"; |
| import { |
| addDays, |
| addMonths, |
| addWeeks, |
| addYears, |
| differenceInCalendarDays, |
| differenceInCalendarMonths, |
| eachMonthOfInterval, |
| eachYearOfInterval, |
| endOfISOWeek, |
| endOfMonth, |
| endOfWeek, |
| endOfYear, |
| format, |
| getISOWeek, |
| getMonth, |
| getWeek, |
| getYear, |
| isAfter, |
| isBefore, |
| isDate, |
| isSameDay, |
| isSameMonth, |
| isSameYear, |
| max, |
| min, |
| setMonth, |
| setYear, |
| startOfDay, |
| startOfISOWeek, |
| startOfMonth, |
| startOfWeek, |
| startOfYear, |
| } from "date-fns"; |
| import type { Locale as DateFnsLocale } from "date-fns/locale"; |
| import { endOfBroadcastWeek } from "../helpers/endOfBroadcastWeek.js"; |
| import { startOfBroadcastWeek } from "../helpers/startOfBroadcastWeek.js"; |
| import { enUS } from "../locale/en-US.js"; |
| import type { Labels, Numerals } from "../types/shared.js"; |
|
|
| export type { Month as DateFnsMonth } from "date-fns"; |
|
|
| |
| |
| |
| |
| |
| export type DayPickerLocaleLabels = { |
| [K in keyof Labels]?: string | Labels[K]; |
| }; |
|
|
| |
| |
| |
| |
| |
| export interface DayPickerLocale extends DateFnsLocale { |
| |
| labels?: DayPickerLocaleLabels; |
| } |
| export type Locale = DayPickerLocale; |
|
|
| |
| |
| |
| |
| export type FormatOptions = DateLibOptions; |
| |
| |
| |
| |
| export type LabelOptions = DateLibOptions; |
|
|
| |
| export type MonthYearOrder = "month-first" | "year-first"; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export interface DateLibOptions |
| extends DateFnsFormatOptions, |
| StartOfWeekOptions, |
| EndOfWeekOptions { |
| |
| Date?: typeof Date; |
| |
| locale?: DayPickerLocale; |
| |
| |
| |
| |
| |
| timeZone?: string; |
| |
| |
| |
| |
| |
| numerals?: Numerals; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export class DateLib { |
| |
| readonly options: DateLibOptions; |
|
|
| |
| readonly overrides?: Partial<typeof DateLib.prototype>; |
|
|
| |
| |
| |
| |
| |
| |
| constructor( |
| options?: DateLibOptions, |
| overrides?: Partial<typeof DateLib.prototype>, |
| ) { |
| this.options = { locale: enUS, ...options }; |
| this.overrides = overrides; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| private getDigitMap(): Record<string, string> { |
| const { numerals = "latn" } = this.options; |
|
|
| |
| const formatter = new Intl.NumberFormat("en-US", { |
| numberingSystem: numerals, |
| }); |
|
|
| |
| const digitMap: Record<string, string> = {}; |
| for (let i = 0; i < 10; i++) { |
| digitMap[i.toString()] = formatter.format(i); |
| } |
|
|
| return digitMap; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| private replaceDigits(input: string): string { |
| const digitMap = this.getDigitMap(); |
| return input.replace(/\d/g, (digit) => digitMap[digit] || digit); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| formatNumber(value: number | string): string { |
| return this.replaceDigits(value.toString()); |
| } |
|
|
| |
| |
| |
| |
| getMonthYearOrder(): MonthYearOrder { |
| const code = this.options.locale?.code; |
| if (!code) { |
| return "month-first"; |
| } |
| return DateLib.yearFirstLocales.has(code) ? "year-first" : "month-first"; |
| } |
|
|
| |
| |
| |
| |
| |
| formatMonthYear(date: Date): string { |
| const { locale, timeZone, numerals } = this.options; |
| const localeCode = locale?.code; |
| if (localeCode && DateLib.yearFirstLocales.has(localeCode)) { |
| try { |
| const intl = new Intl.DateTimeFormat(localeCode, { |
| month: "long", |
| year: "numeric", |
| timeZone, |
| numberingSystem: numerals, |
| }); |
| const formatted = intl.format(date); |
| return formatted; |
| } catch { |
| |
| } |
| } |
|
|
| const pattern = |
| this.getMonthYearOrder() === "year-first" ? "y LLLL" : "LLLL y"; |
| return this.format(date, pattern); |
| } |
|
|
| private static readonly yearFirstLocales = new Set([ |
| "eu", |
| "hu", |
| "ja", |
| "ja-Hira", |
| "ja-JP", |
| "ko", |
| "ko-KR", |
| "lt", |
| "lt-LT", |
| "lv", |
| "lv-LV", |
| "mn", |
| "mn-MN", |
| "zh", |
| "zh-CN", |
| "zh-HK", |
| "zh-TW", |
| ]); |
|
|
| |
| |
| |
| |
| |
| Date: typeof Date = Date; |
|
|
| |
| |
| |
| |
| |
| |
| today = (): Date => { |
| if (this.overrides?.today) { |
| return this.overrides.today(); |
| } |
| if (this.options.timeZone) { |
| return TZDate.tz(this.options.timeZone); |
| } |
| return new this.Date(); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| newDate = (year: number, monthIndex: number, date: number): Date => { |
| if (this.overrides?.newDate) { |
| return this.overrides.newDate(year, monthIndex, date); |
| } |
| if (this.options.timeZone) { |
| return new TZDate(year, monthIndex, date, this.options.timeZone); |
| } |
| return new Date(year, monthIndex, date); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| addDays = (date: Date, amount: number): Date => { |
| return this.overrides?.addDays |
| ? this.overrides.addDays(date, amount) |
| : addDays(date, amount); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| addMonths = (date: Date, amount: number): Date => { |
| return this.overrides?.addMonths |
| ? this.overrides.addMonths(date, amount) |
| : addMonths(date, amount); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| addWeeks = (date: Date, amount: number): Date => { |
| return this.overrides?.addWeeks |
| ? this.overrides.addWeeks(date, amount) |
| : addWeeks(date, amount); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| addYears = (date: Date, amount: number): Date => { |
| return this.overrides?.addYears |
| ? this.overrides.addYears(date, amount) |
| : addYears(date, amount); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| differenceInCalendarDays = (dateLeft: Date, dateRight: Date): number => { |
| return this.overrides?.differenceInCalendarDays |
| ? this.overrides.differenceInCalendarDays(dateLeft, dateRight) |
| : differenceInCalendarDays(dateLeft, dateRight); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| differenceInCalendarMonths = (dateLeft: Date, dateRight: Date): number => { |
| return this.overrides?.differenceInCalendarMonths |
| ? this.overrides.differenceInCalendarMonths(dateLeft, dateRight) |
| : differenceInCalendarMonths(dateLeft, dateRight); |
| }; |
|
|
| |
| |
| |
| |
| |
| eachMonthOfInterval = (interval: Interval): Date[] => { |
| return this.overrides?.eachMonthOfInterval |
| ? this.overrides.eachMonthOfInterval(interval) |
| : eachMonthOfInterval(interval); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| eachYearOfInterval = (interval: Interval): Date[] => { |
| const years = this.overrides?.eachYearOfInterval |
| ? this.overrides.eachYearOfInterval(interval) |
| : eachYearOfInterval(interval); |
| |
| |
| const uniqueYears = new Set(years.map((d) => this.getYear(d))); |
| if (uniqueYears.size === years.length) { |
| |
| return years; |
| } |
| |
| const yearsArray: Date[] = []; |
| uniqueYears.forEach((y) => { |
| yearsArray.push(new Date(y, 0, 1)); |
| }); |
| return yearsArray; |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| endOfBroadcastWeek = (date: Date): Date => { |
| return this.overrides?.endOfBroadcastWeek |
| ? this.overrides.endOfBroadcastWeek(date) |
| : endOfBroadcastWeek(date, this); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| endOfISOWeek = (date: Date): Date => { |
| return this.overrides?.endOfISOWeek |
| ? this.overrides.endOfISOWeek(date) |
| : endOfISOWeek(date); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| endOfMonth = (date: Date): Date => { |
| return this.overrides?.endOfMonth |
| ? this.overrides.endOfMonth(date) |
| : endOfMonth(date); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| endOfWeek = (date: Date, options?: EndOfWeekOptions<Date>): Date => { |
| return this.overrides?.endOfWeek |
| ? this.overrides.endOfWeek(date, options) |
| : endOfWeek(date, this.options); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| endOfYear = (date: Date): Date => { |
| return this.overrides?.endOfYear |
| ? this.overrides.endOfYear(date) |
| : endOfYear(date); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| format = ( |
| date: Date, |
| formatStr: string, |
| _options?: DateFnsFormatOptions, |
| ): string => { |
| const formatted = this.overrides?.format |
| ? this.overrides.format(date, formatStr, this.options) |
| : format(date, formatStr, this.options); |
| if (this.options.numerals && this.options.numerals !== "latn") { |
| return this.replaceDigits(formatted); |
| } |
| return formatted; |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| getISOWeek = (date: Date): number => { |
| return this.overrides?.getISOWeek |
| ? this.overrides.getISOWeek(date) |
| : getISOWeek(date); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| getMonth = (date: Date, _options?: GetMonthOptions): number => { |
| return this.overrides?.getMonth |
| ? this.overrides.getMonth(date, this.options) |
| : getMonth(date, this.options); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| getYear = (date: Date, _options?: GetYearOptions): number => { |
| return this.overrides?.getYear |
| ? this.overrides.getYear(date, this.options) |
| : getYear(date, this.options); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| getWeek = (date: Date, _options?: GetWeekOptions): number => { |
| return this.overrides?.getWeek |
| ? this.overrides.getWeek(date, this.options) |
| : getWeek(date, this.options); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| isAfter = (date: Date, dateToCompare: Date): boolean => { |
| return this.overrides?.isAfter |
| ? this.overrides.isAfter(date, dateToCompare) |
| : isAfter(date, dateToCompare); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| isBefore = (date: Date, dateToCompare: Date): boolean => { |
| return this.overrides?.isBefore |
| ? this.overrides.isBefore(date, dateToCompare) |
| : isBefore(date, dateToCompare); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| isDate: (value: unknown) => value is Date = (value): value is Date => { |
| return this.overrides?.isDate |
| ? this.overrides.isDate(value) |
| : isDate(value); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| isSameDay = (dateLeft: Date, dateRight: Date): boolean => { |
| return this.overrides?.isSameDay |
| ? this.overrides.isSameDay(dateLeft, dateRight) |
| : isSameDay(dateLeft, dateRight); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| isSameMonth = (dateLeft: Date, dateRight: Date): boolean => { |
| return this.overrides?.isSameMonth |
| ? this.overrides.isSameMonth(dateLeft, dateRight) |
| : isSameMonth(dateLeft, dateRight); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| isSameYear = (dateLeft: Date, dateRight: Date): boolean => { |
| return this.overrides?.isSameYear |
| ? this.overrides.isSameYear(dateLeft, dateRight) |
| : isSameYear(dateLeft, dateRight); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| max = (dates: Date[]): Date => { |
| return this.overrides?.max ? this.overrides.max(dates) : max(dates); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| min = (dates: Date[]): Date => { |
| return this.overrides?.min ? this.overrides.min(dates) : min(dates); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| setMonth = (date: Date, month: number): Date => { |
| return this.overrides?.setMonth |
| ? this.overrides.setMonth(date, month) |
| : setMonth(date, month); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| setYear = (date: Date, year: number): Date => { |
| return this.overrides?.setYear |
| ? this.overrides.setYear(date, year) |
| : setYear(date, year); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| startOfBroadcastWeek = (date: Date, _dateLib: DateLib): Date => { |
| return this.overrides?.startOfBroadcastWeek |
| ? this.overrides.startOfBroadcastWeek(date, this) |
| : startOfBroadcastWeek(date, this); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| startOfDay = (date: Date): Date => { |
| return this.overrides?.startOfDay |
| ? this.overrides.startOfDay(date) |
| : startOfDay(date); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| startOfISOWeek = (date: Date): Date => { |
| return this.overrides?.startOfISOWeek |
| ? this.overrides.startOfISOWeek(date) |
| : startOfISOWeek(date); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| startOfMonth = (date: Date): Date => { |
| return this.overrides?.startOfMonth |
| ? this.overrides.startOfMonth(date) |
| : startOfMonth(date); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| startOfWeek = (date: Date, _options?: StartOfWeekOptions): Date => { |
| return this.overrides?.startOfWeek |
| ? this.overrides.startOfWeek(date, this.options) |
| : startOfWeek(date, this.options); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| startOfYear = (date: Date): Date => { |
| return this.overrides?.startOfYear |
| ? this.overrides.startOfYear(date) |
| : startOfYear(date); |
| }; |
| } |
| |
| export { enUS as defaultLocale } from "../locale/en-US.js"; |
|
|
| |
| |
| |
| |
| |
| export const defaultDateLib = new DateLib(); |
|
|
| |
| |
| |
| |
| export const dateLib = defaultDateLib; |
|
|