@date-io/dayjs
Version:
Abstraction over common javascript date management libraries
436 lines (349 loc) • 11.4 kB
text/typescript
import defaultDayjs, { QUnitType } from "dayjs";
import customParseFormatPlugin from "dayjs/plugin/customParseFormat";
import localizedFormatPlugin from "dayjs/plugin/localizedFormat";
import isBetweenPlugin from "dayjs/plugin/isBetween";
import weekOfYear from "dayjs/plugin/weekOfYear";
import { IUtils, DateIOFormats, Unit } from "@date-io/core/IUtils";
defaultDayjs.extend(customParseFormatPlugin);
defaultDayjs.extend(localizedFormatPlugin);
defaultDayjs.extend(isBetweenPlugin);
defaultDayjs.extend(weekOfYear);
interface Opts {
locale?: string;
/** Make sure that your dayjs instance extends customParseFormat and advancedFormat */
instance?: typeof defaultDayjs;
formats?: Partial<DateIOFormats>;
}
type Dayjs = defaultDayjs.Dayjs;
type Constructor<TDate extends Dayjs> = (
...args: Parameters<typeof defaultDayjs>
) => TDate;
const withLocale = <TDate extends Dayjs>(
dayjs: any,
locale?: string
): Constructor<TDate> => (!locale ? dayjs : (...args) => dayjs(...args).locale(locale));
const defaultFormats: DateIOFormats = {
normalDateWithWeekday: "ddd, MMM D",
normalDate: "D MMMM",
shortDate: "MMM D",
monthAndDate: "MMMM D",
dayOfMonth: "D",
year: "YYYY",
month: "MMMM",
monthShort: "MMM",
monthAndYear: "MMMM YYYY",
weekday: "dddd",
weekdayShort: "ddd",
minutes: "mm",
hours12h: "hh",
hours24h: "HH",
seconds: "ss",
fullTime: "LT",
fullTime12h: "hh:mm A",
fullTime24h: "HH:mm",
fullDate: "ll",
fullDateWithWeekday: "dddd, LL",
fullDateTime: "lll",
fullDateTime12h: "ll hh:mm A",
fullDateTime24h: "ll HH:mm",
keyboardDate: "L",
keyboardDateTime: "L LT",
keyboardDateTime12h: "L hh:mm A",
keyboardDateTime24h: "L HH:mm",
};
export default class DayjsUtils<TDate extends Dayjs = Dayjs>
implements IUtils<TDate, string>
{
public rawDayJsInstance: typeof defaultDayjs;
public lib = "dayjs";
public dayjs: Constructor<TDate>;
public locale?: string;
public formats: DateIOFormats;
constructor({ locale, formats, instance }: Opts = {}) {
this.rawDayJsInstance = instance || defaultDayjs;
this.dayjs = withLocale(this.rawDayJsInstance, locale);
this.locale = locale;
this.formats = Object.assign({}, defaultFormats, formats);
}
public is12HourCycleInCurrentLocale = () => {
/* istanbul ignore next */
return /A|a/.test(this.rawDayJsInstance.Ls[this.locale || "en"]?.formats?.LT ?? "");
};
public getCurrentLocaleCode = () => {
return this.locale || "en";
};
public getFormatHelperText = (format: string) => {
// @see https://github.com/iamkun/dayjs/blob/dev/src/plugin/localizedFormat/index.js
var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?)|./g;
return (
format
.match(localFormattingTokens)
?.map((token) => {
var firstCharacter = token[0];
if (firstCharacter === "L") {
/* istanbul ignore next */
return (
this.rawDayJsInstance.Ls[this.locale || "en"]?.formats[
token as keyof ILocale["formats"]
] ?? token
);
}
return token;
})
.join("")
.replace(/a/gi, "(a|p)m")
.toLocaleLowerCase() ?? format
);
};
public parseISO = (isoString: string) => {
return this.dayjs(isoString);
};
public toISO = (value: Dayjs) => {
return value.toISOString();
};
public parse = (value: any, format: string) => {
if (value === "") {
return null;
}
return this.dayjs(value, format, this.locale, true);
};
date<
TArg extends unknown = undefined,
TRes extends unknown = TArg extends null
? null
: TArg extends undefined
? TDate
: TDate | null
>(value?: TArg): TRes {
if (value === null) {
return null as TRes;
}
return this.dayjs(value as any) as unknown as TRes;
}
public toJsDate = (value: Dayjs) => {
return value.toDate();
};
public isValid = (value: any) => {
return this.dayjs(value).isValid();
};
public isNull = (date: Dayjs | null) => {
return date === null;
};
public getDiff = (date: TDate, comparing: TDate | string, units?: Unit) => {
if (typeof comparing === "string") {
comparing = this.dayjs(comparing);
}
if (!comparing.isValid()) {
return 0;
}
return date.diff(comparing, units as QUnitType);
};
public isAfter = (date: TDate, value: TDate) => {
return date.isAfter(value);
};
public isBefore = (date: TDate, value: TDate) => {
return date.isBefore(value);
};
public isAfterDay = (date: TDate, value: TDate) => {
return date.isAfter(value, "day");
};
public isBeforeDay = (date: Dayjs, value: Dayjs) => {
return date.isBefore(value, "day");
};
public isAfterMonth = (date: Dayjs, value: Dayjs) => {
return date.isAfter(value, "month");
};
public isBeforeMonth = (date: Dayjs, value: Dayjs) => {
return date.isBefore(value, "month");
};
public isBeforeYear = (date: Dayjs, value: Dayjs) => {
return date.isBefore(value, "year");
};
public isAfterYear = (date: Dayjs, value: Dayjs) => {
return date.isAfter(value, "year");
};
public startOfDay = (date: TDate) => {
return date.startOf("day") as TDate;
};
public endOfDay = (date: TDate) => {
return date.endOf("day") as TDate;
};
public format = (date: Dayjs, formatKey: keyof DateIOFormats) => {
return this.formatByString(date, this.formats[formatKey]);
};
public formatByString = (date: Dayjs, formatString: string) => {
return this.dayjs(date).format(formatString);
};
public formatNumber = (numberToFormat: string) => {
return numberToFormat;
};
public getHours = (date: Dayjs) => {
return date.hour();
};
public addSeconds = (date: TDate, count: number) => {
return count < 0
? (date.subtract(Math.abs(count), "second") as TDate)
: (date.add(count, "second") as TDate);
};
public addMinutes = (date: Dayjs, count: number) => {
return count < 0
? (date.subtract(Math.abs(count), "minute") as TDate)
: (date.add(count, "minute") as TDate);
};
public addHours = (date: Dayjs, count: number) => {
return count < 0
? (date.subtract(Math.abs(count), "hour") as TDate)
: (date.add(count, "hour") as TDate);
};
public addDays = (date: Dayjs, count: number) => {
return count < 0
? (date.subtract(Math.abs(count), "day") as TDate)
: (date.add(count, "day") as TDate);
};
public addWeeks = (date: Dayjs, count: number) => {
return count < 0
? (date.subtract(Math.abs(count), "week") as TDate)
: (date.add(count, "week") as TDate);
};
public addMonths = (date: Dayjs, count: number) => {
return count < 0
? (date.subtract(Math.abs(count), "month") as TDate)
: (date.add(count, "month") as TDate);
};
public addYears = (date: Dayjs, count: number) => {
return count < 0
? (date.subtract(Math.abs(count), "year") as TDate)
: (date.add(count, "year") as TDate);
};
public setMonth = (date: Dayjs, count: number) => {
return date.set("month", count) as TDate;
};
public setHours = (date: Dayjs, count: number) => {
return date.set("hour", count) as TDate;
};
public getMinutes = (date: Dayjs) => {
return date.minute();
};
public setMinutes = (date: Dayjs, count: number) => {
return date.set("minute", count) as TDate;
};
public getSeconds = (date: Dayjs) => {
return date.second();
};
public setSeconds = (date: Dayjs, count: number) => {
return date.set("second", count) as TDate;
};
public getWeek = (date: Dayjs) => {
return date.week();
};
public getMonth = (date: Dayjs) => {
return date.month();
};
public getDate = (date: Dayjs) => {
return date.date();
};
public setDate = (date: Dayjs, count: number) => {
return date.set("date", count) as TDate;
};
public getDaysInMonth = (date: Dayjs) => {
return date.daysInMonth();
};
public isSameDay = (date: Dayjs, comparing: Dayjs) => {
return date.isSame(comparing, "day");
};
public isSameMonth = (date: Dayjs, comparing: Dayjs) => {
return date.isSame(comparing, "month");
};
public isSameYear = (date: Dayjs, comparing: Dayjs) => {
return date.isSame(comparing, "year");
};
public isSameHour = (date: Dayjs, comparing: Dayjs) => {
return date.isSame(comparing, "hour");
};
public getMeridiemText = (ampm: "am" | "pm") => {
return ampm === "am" ? "AM" : "PM";
};
public startOfYear = (date: Dayjs) => {
return date.startOf("year") as TDate;
};
public endOfYear = (date: Dayjs) => {
return date.endOf("year") as TDate;
};
public startOfMonth = (date: Dayjs) => {
return date.startOf("month") as TDate;
};
public endOfMonth = (date: Dayjs) => {
return date.endOf("month") as TDate;
};
public startOfWeek = (date: Dayjs) => {
return date.startOf("week") as TDate;
};
public endOfWeek = (date: Dayjs) => {
return date.endOf("week") as TDate;
};
public getNextMonth = (date: Dayjs) => {
return date.add(1, "month") as TDate;
};
public getPreviousMonth = (date: Dayjs) => {
return date.subtract(1, "month") as TDate;
};
public getMonthArray = (date: TDate) => {
const firstMonth = date.startOf("year") as TDate;
const monthArray = [firstMonth];
while (monthArray.length < 12) {
const prevMonth = monthArray[monthArray.length - 1];
monthArray.push(this.getNextMonth(prevMonth));
}
return monthArray;
};
public getYear = (date: Dayjs) => {
return date.year();
};
public setYear = (date: Dayjs, year: number) => {
return date.set("year", year) as TDate;
};
public mergeDateAndTime = (date: TDate, time: TDate) => {
return date.hour(time.hour()).minute(time.minute()).second(time.second()) as TDate;
};
public getWeekdays = () => {
const start = this.dayjs().startOf("week");
return [0, 1, 2, 3, 4, 5, 6].map((diff) =>
this.formatByString(start.add(diff, "day"), "dd")
);
};
public isEqual = (value: any, comparing: any) => {
if (value === null && comparing === null) {
return true;
}
return this.dayjs(value).isSame(comparing);
};
public getWeekArray = (date: TDate) => {
const start = this.dayjs(date).startOf("month").startOf("week") as TDate;
const end = this.dayjs(date).endOf("month").endOf("week") as TDate;
let count = 0;
let current = start;
const nestedWeeks: TDate[][] = [];
while (current.isBefore(end)) {
const weekNumber = Math.floor(count / 7);
nestedWeeks[weekNumber] = nestedWeeks[weekNumber] || [];
nestedWeeks[weekNumber].push(current);
current = current.add(1, "day") as TDate;
count += 1;
}
return nestedWeeks;
};
public getYearRange = (start: TDate, end: TDate) => {
const startDate = this.dayjs(start).startOf("year");
const endDate = this.dayjs(end).endOf("year");
const years: TDate[] = [];
let current = startDate;
while (current.isBefore(endDate)) {
years.push(current as TDate);
current = current.add(1, "year");
}
return years;
};
public isWithinRange = (date: TDate, [start, end]: [TDate, TDate]) => {
return date.isBetween(start, end, null, "[]");
};
}