omniserror
Version:
Abstraction over common javascript date management libraries
346 lines (275 loc) • 8.57 kB
text/typescript
import defaultDayjs from "dayjs";
import customParseFormatPlugin from "dayjs/plugin/customParseFormat";
import localizedFormatPlugin from "dayjs/plugin/localizedFormat";
import isBetweenPlugin from "dayjs/plugin/isBetween";
import { IUtils, DateIOFormats } from "@date-io/core/IUtils";
defaultDayjs.extend(customParseFormatPlugin);
defaultDayjs.extend(localizedFormatPlugin);
defaultDayjs.extend(isBetweenPlugin);
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 = (...args: Parameters<typeof defaultDayjs>) => Dayjs;
const withLocale = (dayjs: typeof defaultDayjs, locale?: string): Constructor =>
!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",
minutes: "mm",
hours12h: "hh",
hours24h: "HH",
seconds: "ss",
fullTime: "LT",
fullTime12h: "hh:mm A",
fullTime24h: "HH:mm",
fullDate: "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"
};
const localizedFormats = {
fullTime12h: "LT",
fullTime24h: "LT",
keyboardDate: "L",
keyboardDateTime12h: "L LT",
keyboardDateTime24h: "L LT"
};
export default class DayjsUtils implements IUtils<defaultDayjs.Dayjs> {
public rawDayJsInstance: typeof defaultDayjs;
public dayjs: Constructor;
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] ?? token;
}
return token;
})
.join("")
.replace(/a/gi, "(a|p)m")
.toLocaleLowerCase();
}
public parse(value: any, format: any) {
if (value === "") {
return null;
}
return this.dayjs(value, format);
}
public date(value?: any) {
if (value === null) {
return null;
}
return this.dayjs(value);
}
public toJsDate(value: Dayjs) {
return value.toDate();
}
public isValid(value: any) {
return this.dayjs(value).isValid();
}
public isNull(date: Dayjs) {
return date === null;
}
public getDiff(date: Dayjs, comparing: Dayjs, units?: any, float?: any) {
return date.diff(comparing, units, float);
}
public isAfter(date: Dayjs, value: Dayjs) {
return date.isAfter(value);
}
public isBefore(date: Dayjs, value: Dayjs) {
return date.isBefore(value);
}
public isAfterDay(date: Dayjs, value: Dayjs) {
return date.isAfter(value, "day");
}
public isBeforeDay(date: Dayjs, value: Dayjs) {
return date.isBefore(value, "day");
}
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: Dayjs) {
return date.clone().startOf("day");
}
public endOfDay(date: Dayjs) {
return date.clone().endOf("day");
}
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 addDays(date: Dayjs, count: number) {
return count < 0 ? date.subtract(Math.abs(count), "day") : date.add(count, "day");
}
public addMonths(date: Dayjs, count: number) {
return count < 0 ? date.subtract(Math.abs(count), "month") : date.add(count, "month");
}
public setMonth(date: Dayjs, count: number) {
return date.set("month", count);
}
public setHours(date: Dayjs, count: number) {
return date.set("hour", count);
}
public getMinutes(date: Dayjs) {
return date.minute();
}
public setMinutes(date: Dayjs, count: number) {
return date.clone().set("minute", count);
}
public getSeconds(date: Dayjs) {
return date.second();
}
public setSeconds(date: Dayjs, count: number) {
return date.clone().set("second", count);
}
public getMonth(date: Dayjs) {
return date.month();
}
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 startOfMonth(date: Dayjs) {
return date.clone().startOf("month");
}
public endOfMonth(date: Dayjs) {
return date.clone().endOf("month");
}
public startOfWeek(date: Dayjs) {
return date.clone().startOf("week");
}
public endOfWeek(date: Dayjs) {
return date.clone().endOf("week");
}
public getNextMonth(date: Dayjs) {
return date.clone().add(1, "month");
}
public getPreviousMonth(date: Dayjs) {
return date.clone().subtract(1, "month");
}
public getMonthArray(date: Dayjs) {
const firstMonth = date.clone().startOf("year");
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.clone().set("year", year);
}
public mergeDateAndTime(date: Dayjs, time: Dayjs) {
return date
.hour(time.hour())
.minute(time.minute())
.second(time.second());
}
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: Dayjs) {
const start = this.dayjs(date)
.clone()
.startOf("month")
.startOf("week");
const end = this.dayjs(date)
.clone()
.endOf("month")
.endOf("week");
let count = 0;
let current = start;
const nestedWeeks: Dayjs[][] = [];
while (current.isBefore(end)) {
const weekNumber = Math.floor(count / 7);
nestedWeeks[weekNumber] = nestedWeeks[weekNumber] || [];
nestedWeeks[weekNumber].push(current);
current = current.clone().add(1, "day");
count += 1;
}
return nestedWeeks;
}
public getYearRange(start: Dayjs, end: Dayjs) {
const startDate = this.dayjs(start).startOf("year");
const endDate = this.dayjs(end).endOf("year");
const years: Dayjs[] = [];
let current = startDate;
while (current.isBefore(endDate)) {
years.push(current);
current = current.clone().add(1, "year");
}
return years;
}
public isWithinRange(date: Dayjs, [start, end]: [Dayjs, Dayjs]) {
return date.isBetween(start, end, null, "[]");
}
}