| | 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; |
| |
|