chinese-days
Version:
中国节假日、调休日、工作日、24节气查询,农历阳历互转,支持 TS、CommonJS、UMD 模块化使用,提供 ics 日历格式,可供 Google Calendar、Apple Calendar、Microsoft Outlook 等客户端订阅。
241 lines (218 loc) • 7.12 kB
text/typescript
/* 自己实现一个简易的 dayjs,供项目中使用 */
export type ConfigType = string | number | Date | Dayjs | null | undefined;
export class Dayjs {
private _date: Date;
private static daysOfWeek = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
];
constructor(date?: ConfigType) {
if (date instanceof Dayjs) {
this._date = new Date(date.toDate());
} else if (date instanceof Date) {
this._date = new Date(date);
} else if (typeof date === 'string' || typeof date === 'number') {
if (typeof date === 'string') {
// Regex to match YYYY-MM-DD or YYYY-M-D
const match = date.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
if (match) {
// Parse as UTC explicitly to ensure consistency and avoid Local/UTC mixing
// This handles '2004-10-9' (Local in V8) vs '2004-10-10' (UTC in V8) inconsistency
this._date = new Date(Date.UTC(
parseInt(match[1], 10),
parseInt(match[2], 10) - 1,
parseInt(match[3], 10)
));
} else if (isNaN(new Date(date).getTime())) {
// Fallback for slash format or other formats
this._date = new Date(date.replace(/-/g, '/'));
} else {
this._date = new Date(date);
}
} else {
this._date = new Date(date);
}
} else {
this._date = new Date();
}
}
toDate(): Date {
return this._date;
}
isValid(): boolean {
return !isNaN(this._date.getTime());
}
diff(
date: string | number | Date | Dayjs | null | undefined,
unit: 'day' | 'month' | 'year' = 'day'
): number {
const targetDate = new Dayjs(date).toDate();
const diffTime = this._date.getTime() - targetDate.getTime();
switch (unit) {
case 'year':
return this._date.getFullYear() - targetDate.getFullYear();
case 'month':
return (
(this._date.getFullYear() - targetDate.getFullYear()) * 12 +
(this._date.getMonth() - targetDate.getMonth())
);
case 'day':
default:
return Math.floor(diffTime / (1000 * 60 * 60 * 24));
}
}
startOf(unit?: 'year' | 'month' | 'day'): Dayjs {
const newDate = new Date(this._date);
switch (unit) {
case 'year':
newDate.setMonth(0);
newDate.setDate(1);
newDate.setHours(0, 0, 0, 0);
break;
case 'month':
newDate.setDate(1);
newDate.setHours(0, 0, 0, 0);
break;
case 'day':
newDate.setHours(0, 0, 0, 0);
break;
}
return new Dayjs(newDate);
}
endOf(unit?: 'year' | 'month' | 'day'): Dayjs {
const newDate = new Date(this._date);
switch (unit) {
case 'year':
newDate.setMonth(11);
newDate.setDate(31);
newDate.setHours(23, 59, 59, 999);
break;
case 'month':
newDate.setDate(
new Date(newDate.getFullYear(), newDate.getMonth() + 1, 0).getDate()
);
newDate.setHours(23, 59, 59, 999);
break;
case 'day':
newDate.setHours(23, 59, 59, 999);
break;
}
return new Dayjs(newDate);
}
add(value: number, unit: 'year' | 'month' | 'day'): Dayjs {
const newDate = new Date(this._date);
switch (unit) {
case 'year':
newDate.setFullYear(newDate.getFullYear() + value);
break;
case 'month':
newDate.setMonth(newDate.getMonth() + value);
break;
case 'day':
newDate.setDate(newDate.getDate() + value);
break;
}
return new Dayjs(newDate);
}
subtract(value: number, unit: 'year' | 'month' | 'day'): Dayjs {
return this.add(-value, unit);
}
format(formatStr: string): string {
const map: { [key: string]: number | string } = {
YYYY: this._date.getFullYear(),
MM: (this._date.getMonth() + 1).toString().padStart(2, '0'),
DD: this._date.getDate().toString().padStart(2, '0'),
HH: this._date.getHours().toString().padStart(2, '0'),
mm: this._date.getMinutes().toString().padStart(2, '0'),
ss: this._date.getSeconds().toString().padStart(2, '0'),
dddd: Dayjs.daysOfWeek[this._date.getDay()],
};
return formatStr.replace(/YYYY|MM|DD|HH|mm|ss|dddd/g, matched => {
return map[matched].toString();
});
}
year(): number;
year(year: number): Dayjs;
year(year?: number): number | Dayjs {
if (year === undefined) return this._date.getFullYear();
const newDate = new Date(this._date);
newDate.setFullYear(year);
return new Dayjs(newDate);
}
month(): number;
month(month: number): Dayjs;
month(month?: number): number | Dayjs {
if (month === undefined) return this._date.getMonth();
const newDate = new Date(this._date);
newDate.setMonth(month);
return new Dayjs(newDate);
}
date(): number;
date(day: number): Dayjs;
date(day?: number): number | Dayjs {
if (day === undefined) return this._date.getDate();
const newDate = new Date(this._date);
newDate.setDate(day);
return new Dayjs(newDate);
}
day(): number;
day(day: number): Dayjs;
day(day?: number): number | Dayjs {
if (day === undefined) {
return this._date.getDay();
} else {
const currentDay = this._date.getDay();
const diff = day - currentDay;
const newDate = new Date(this._date);
newDate.setDate(this._date.getDate() + diff);
return new Dayjs(newDate);
}
}
isBefore(date: string | number | Date | Dayjs | null | undefined): boolean {
const targetDate = new Dayjs(date).toDate();
return this._date.getTime() < targetDate.getTime();
}
isAfter(date: string | number | Date | Dayjs | null | undefined): boolean {
const targetDate = new Dayjs(date).toDate();
return this._date.getTime() > targetDate.getTime();
}
isSame(
date: string | number | Date | Dayjs | null | undefined,
unit: 'year' | 'month' | 'day' = 'day'
): boolean {
const targetDate = new Dayjs(date).toDate();
switch (unit) {
case 'year':
return this._date.getFullYear() === targetDate.getFullYear();
case 'month':
return (
this._date.getFullYear() === targetDate.getFullYear() &&
this._date.getMonth() === targetDate.getMonth()
);
case 'day':
default:
return (
this._date.getFullYear() === targetDate.getFullYear() &&
this._date.getMonth() === targetDate.getMonth() &&
this._date.getDate() === targetDate.getDate()
);
}
}
isBetween(
startDate: string | number | Date | Dayjs | null | undefined,
endDate: string | number | Date | Dayjs | null | undefined,
unit?: 'year' | 'month' | 'day'
): boolean {
const start = new Dayjs(startDate).startOf(unit).toDate();
const end = new Dayjs(endDate).endOf(unit).toDate();
const current = this.toDate();
return current >= start && current <= end;
}
}
const simpleDayjs = (date?: ConfigType): Dayjs => new Dayjs(date);
export default simpleDayjs;