@date-io/luxon
Version:
Abstraction over common javascript date management libraries
438 lines (346 loc) • 11.1 kB
text/typescript
import { DateTime, Settings, Info } from "luxon";
import { IUtils, DateIOFormats, Unit } from "@date-io/core/IUtils";
const defaultFormats: DateIOFormats = {
dayOfMonth: "d",
fullDate: "DD",
fullDateWithWeekday: "DDDD",
fullDateTime: "ff",
fullDateTime12h: "DD, hh:mm a",
fullDateTime24h: "DD, T",
fullTime: "t",
fullTime12h: "hh:mm a",
fullTime24h: "HH:mm",
hours12h: "hh",
hours24h: "HH",
keyboardDate: "D",
keyboardDateTime: "D t",
keyboardDateTime12h: "D hh:mm a",
keyboardDateTime24h: "D T",
minutes: "mm",
seconds: "ss",
month: "LLLL",
monthAndDate: "MMMM d",
monthAndYear: "LLLL yyyy",
monthShort: "MMM",
weekday: "cccc",
weekdayShort: "ccc",
normalDate: "d MMMM",
normalDateWithWeekday: "EEE, MMM d",
shortDate: "MMM d",
year: "yyyy",
};
export default class LuxonUtils implements IUtils<DateTime, string> {
public lib = "luxon";
public locale: string;
public formats: DateIOFormats;
constructor({
locale,
formats,
}: { formats?: Partial<DateIOFormats>; locale?: string } = {}) {
this.locale = locale || "en-US";
this.formats = Object.assign({}, defaultFormats, formats);
}
date<
TArg extends unknown = undefined,
TRes extends unknown = TArg extends null
? null
: TArg extends undefined
? DateTime
: DateTime | null
>(value?: TArg): TRes {
if (typeof value === "undefined") {
return DateTime.local() as TRes;
}
if (value === null) {
return null as TRes;
}
if (typeof value === "string") {
return DateTime.fromJSDate(new Date(value), { locale: this.locale }) as TRes;
}
if (DateTime.isDateTime(value)) {
return value as TRes;
}
if (value instanceof Date) {
return DateTime.fromJSDate(value, { locale: this.locale }) as TRes;
}
/* istanbul ignore next */
return DateTime.local() as TRes;
}
public toJsDate = (value: DateTime) => {
return value.toJSDate();
};
public parseISO = (isoString: string) => {
return DateTime.fromISO(isoString);
};
public toISO = (value: DateTime) => {
return value.toISO({ format: "extended" });
};
public parse = (value: string, formatString: string) => {
if (value === "") {
return null;
}
return DateTime.fromFormat(value, formatString, { locale: this.locale });
};
/* istanbul ignore next */
public is12HourCycleInCurrentLocale = () => {
if (typeof Intl === "undefined" || typeof Intl.DateTimeFormat === "undefined") {
return true; // Luxon defaults to en-US if Intl not found
}
return Boolean(
new Intl.DateTimeFormat(this.locale, { hour: "numeric" })?.resolvedOptions()?.hour12
);
};
public getFormatHelperText = (format: string) => {
// Unfortunately there is no way for luxon to retrieve readable formats from localized format
return "";
};
/* istanbul ignore next */
public getCurrentLocaleCode = () => {
return this.locale || Settings.defaultLocale;
};
public addSeconds = (date: DateTime, count: number) => {
return date.plus({ seconds: count });
};
public addMinutes = (date: DateTime, count: number) => {
return date.plus({ minutes: count });
};
public addHours = (date: DateTime, count: number) => {
return date.plus({ hours: count });
};
public addDays = (date: DateTime, count: number) => {
return date.plus({ days: count });
};
public addWeeks = (date: DateTime, count: number) => {
return date.plus({ weeks: count });
};
public addMonths = (date: DateTime, count: number) => {
return date.plus({ months: count });
};
public addYears = (date: DateTime, count: number) => {
return date.plus({ years: count });
};
public isValid = (value: any) => {
if (DateTime.isDateTime(value)) {
return value.isValid;
}
if (value === null) {
return false;
}
return this.date(value)?.isValid ?? false;
};
public isEqual = (value: any, comparing: any) => {
if (value === null && comparing === null) {
return true;
}
// make sure that null will not be passed to this.date
if (value === null || comparing === null) {
return false;
}
if (!this.date(comparing)) {
/* istanbul ignore next */
return false;
}
return this.date(value)?.equals(this.date(comparing) as DateTime) ?? false;
};
public isSameDay = (date: DateTime, comparing: DateTime) => {
return date.hasSame(comparing, "day");
};
public isSameMonth = (date: DateTime, comparing: DateTime) => {
return date.hasSame(comparing, "month");
};
public isSameYear = (date: DateTime, comparing: DateTime) => {
return date.hasSame(comparing, "year");
};
public isSameHour = (date: DateTime, comparing: DateTime) => {
return date.hasSame(comparing, "hour");
};
public isAfter = (value: DateTime, comparing: DateTime) => {
return value > comparing;
};
public isBefore = (value: DateTime, comparing: DateTime) => {
return value < comparing;
};
public isBeforeDay = (value: DateTime, comparing: DateTime) => {
const diff = value.diff(comparing.startOf("day"), "days").toObject();
return diff.days! < 0;
};
public isAfterDay = (value: DateTime, comparing: DateTime) => {
const diff = value.diff(comparing.endOf("day"), "days").toObject();
return diff.days! > 0;
};
public isBeforeMonth = (value: DateTime, comparing: DateTime) => {
const diff = value.diff(comparing.startOf("month"), "months").toObject();
return diff.months! < 0;
};
public isAfterMonth = (value: DateTime, comparing: DateTime) => {
const diff = value.diff(comparing.startOf("month"), "months").toObject();
return diff.months! > 0;
};
public isBeforeYear = (value: DateTime, comparing: DateTime) => {
const diff = value.diff(comparing.startOf("year"), "years").toObject();
return diff.years! < 0;
};
public isAfterYear = (value: DateTime, comparing: DateTime) => {
const diff = value.diff(comparing.endOf("year"), "years").toObject();
return diff.years! > 0;
};
public getDiff = (value: DateTime, comparing: DateTime | string, unit?: Unit) => {
if (typeof comparing === "string") {
comparing = DateTime.fromJSDate(new Date(comparing));
}
if (!comparing.isValid) {
return 0;
}
if (unit) {
return Math.floor(value.diff(comparing).as(unit));
}
return value.diff(comparing).as("millisecond");
};
public startOfDay = (value: DateTime) => {
return value.startOf("day");
};
public endOfDay = (value: DateTime) => {
return value.endOf("day");
};
public format = (date: DateTime, formatKey: keyof DateIOFormats) => {
return this.formatByString(date, this.formats[formatKey]);
};
public formatByString = (date: DateTime, format: string) => {
return date.setLocale(this.locale).toFormat(format);
};
public formatNumber = (numberToFormat: string) => {
return numberToFormat;
};
public getHours = (value: DateTime) => {
return value.get("hour");
};
public setHours = (value: DateTime, count: number) => {
return value.set({ hour: count });
};
public getMinutes = (value: DateTime) => {
return value.get("minute");
};
public setMinutes = (value: DateTime, count: number) => {
return value.set({ minute: count });
};
public getSeconds = (value: DateTime) => {
return value.get("second");
};
public setSeconds = (value: DateTime, count: number) => {
return value.set({ second: count });
};
public getWeek = (value: DateTime) => {
return value.get("weekNumber");
};
public getMonth = (value: DateTime) => {
// See https://github.com/moment/luxon/blob/master/docs/moment.md#major-functional-differences
return value.get("month") - 1;
};
public getDaysInMonth = (value: DateTime) => {
return value.daysInMonth;
};
public setMonth = (value: DateTime, count: number) => {
return value.set({ month: count + 1 });
};
public getYear = (value: DateTime) => {
return value.get("year");
};
public setYear = (value: DateTime, year: number) => {
return value.set({ year });
};
public getDate = (value: DateTime) => {
return value.get("day");
};
public setDate = (value: DateTime, day: number) => {
return value.set({ day });
};
public mergeDateAndTime = (date: DateTime, time: DateTime) => {
return date.set({
second: time.second,
hour: time.hour,
minute: time.minute,
});
};
public startOfYear = (value: DateTime) => {
return value.startOf("year");
};
public endOfYear = (value: DateTime) => {
return value.endOf("year");
};
public startOfMonth = (value: DateTime) => {
return value.startOf("month");
};
public endOfMonth = (value: DateTime) => {
return value.endOf("month");
};
public startOfWeek = (value: DateTime) => {
return value.startOf("week");
};
public endOfWeek = (value: DateTime) => {
return value.endOf("week");
};
public getNextMonth = (value: DateTime) => {
return value.plus({ months: 1 });
};
public getPreviousMonth = (value: DateTime) => {
return value.minus({ months: 1 });
};
public getMonthArray = (date: DateTime) => {
const firstMonth = date.startOf("year");
const monthArray = [firstMonth];
while (monthArray.length < 12) {
const prevMonth = monthArray[monthArray.length - 1];
monthArray.push(this.getNextMonth(prevMonth));
}
return monthArray;
};
public getWeekdays = () => {
return Info.weekdaysFormat("short", { locale: this.locale });
};
public getWeekArray = (date: DateTime) => {
const { days } = date
.endOf("month")
.endOf("week")
.diff(date.startOf("month").startOf("week"), "days")
.toObject();
const weeks: DateTime[][] = [];
new Array<number>(Math.round(days!))
.fill(0)
.map((_, i) => i)
.map((day) => date.startOf("month").startOf("week").plus({ days: day }))
.forEach((v, i) => {
if (i === 0 || (i % 7 === 0 && i > 6)) {
weeks.push([v]);
return;
}
weeks[weeks.length - 1].push(v);
});
return weeks;
};
public getYearRange = (start: DateTime, end: DateTime) => {
const startDate = start.startOf("year");
const endDate = end.endOf("year");
let current = startDate;
const years: DateTime[] = [];
while (current < endDate) {
years.push(current);
current = current.plus({ year: 1 });
}
return years;
};
public getMeridiemText = (ampm: "am" | "pm") => {
return Info.meridiems({ locale: this.locale }).find(
(v) => v.toLowerCase() === ampm.toLowerCase()
)!;
};
public isNull = (date: DateTime | null) => {
return date === null;
};
public isWithinRange = (date: DateTime, [start, end]: [DateTime, DateTime]) => {
return (
date.equals(start) ||
date.equals(end) ||
(this.isAfter(date, start) && this.isBefore(date, end))
);
};
}