|
@@ -1,16 +1,16 @@
|
|
import dayjs from "../utils/dayjs";
|
|
import dayjs from "../utils/dayjs";
|
|
|
|
|
|
export enum Holiday {
|
|
export enum Holiday {
|
|
- NY = "New Year's Day,元旦,1",
|
|
|
|
- S = "Spring Festival,春节,4",
|
|
|
|
- T = "Tomb-sweeping Day,清明,1",
|
|
|
|
- L = "Labour Day,劳动节,2",
|
|
|
|
- D = "Dragon Boat Festival,端午,1",
|
|
|
|
- N = "National Day,国庆节,3",
|
|
|
|
- M = "Mid-autumn Festival,中秋,1",
|
|
|
|
|
|
+ NY = "New Year's Day,元旦",
|
|
|
|
+ S = "Spring Festival,春节",
|
|
|
|
+ T = "Tomb-sweeping Day,清明",
|
|
|
|
+ L = "Labour Day,劳动节",
|
|
|
|
+ D = "Dragon Boat Festival,端午",
|
|
|
|
+ N = "National Day,国庆节",
|
|
|
|
+ M = "Mid-autumn Festival,中秋",
|
|
|
|
|
|
/** special holidays */
|
|
/** special holidays */
|
|
- A = "Anti-Fascist 70th Day,中国人民抗日战争暨世界反法西斯战争胜利70周年纪念日,1",
|
|
|
|
|
|
+ A = "Anti-Fascist 70th Day,中国人民抗日战争暨世界反法西斯战争胜利70周年纪念日",
|
|
}
|
|
}
|
|
|
|
|
|
interface DayDetails {
|
|
interface DayDetails {
|
|
@@ -27,11 +27,39 @@ enum DayType {
|
|
InLieu = 3,
|
|
InLieu = 3,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** 国务院规定的天数,1999-2025的变化 */
|
|
|
|
+const holidayDays: Record<number, Partial<Record<Holiday, number>>> = {
|
|
|
|
+ // 1999 元旦 1 天、春节、劳动节、国庆节放假 3天
|
|
|
|
+ 1999: {
|
|
|
|
+ [Holiday.NY]: 1,
|
|
|
|
+ [Holiday.S]: 3,
|
|
|
|
+ [Holiday.L]: 3,
|
|
|
|
+ [Holiday.N]: 3,
|
|
|
|
+ },
|
|
|
|
+ // 2008 劳动节改为 1 天,增加清明、端午、中秋各 1 天
|
|
|
|
+ 2008: {
|
|
|
|
+ [Holiday.T]: 1,
|
|
|
|
+ [Holiday.L]: 1,
|
|
|
|
+ [Holiday.D]: 1,
|
|
|
|
+ [Holiday.M]: 1,
|
|
|
|
+ },
|
|
|
|
+ // 2014 春节剔除除夕,改为初一、二、三,依旧 3 天
|
|
|
|
+ // 2015 增加 中国人民抗日战争暨世界反法西斯战争胜利70周年纪念日 1 天
|
|
|
|
+ 2015: {
|
|
|
|
+ [Holiday.A]: 1,
|
|
|
|
+ },
|
|
|
|
+ // 2025 春节和劳动节 各增加 1 天
|
|
|
|
+ 2025: {
|
|
|
|
+ [Holiday.S]: 4,
|
|
|
|
+ [Holiday.L]: 2,
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+
|
|
class Arrangement {
|
|
class Arrangement {
|
|
private dayDetails: DayDetails = {};
|
|
private dayDetails: DayDetails = {};
|
|
- public holidays: Record<string, Holiday> = {};
|
|
|
|
- public workdays: Record<string, Holiday> = {};
|
|
|
|
- public inLieuDays: Record<string, Holiday> = {};
|
|
|
|
|
|
+ public holidays: Record<string, string> = {};
|
|
|
|
+ public workdays: Record<string, string> = {};
|
|
|
|
+ public inLieuDays: Record<string, string> = {};
|
|
|
|
|
|
/** year at */
|
|
/** year at */
|
|
y(year: number) {
|
|
y(year: number) {
|
|
@@ -39,6 +67,22 @@ class Arrangement {
|
|
return this;
|
|
return this;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /** 查询某年 节假日天数 */
|
|
|
|
+ getHolidayDays(year: number, holiday: Holiday): number {
|
|
|
|
+ let lastDefinedDays = 0;
|
|
|
|
+
|
|
|
|
+ // 遍历规则,查找适用于该年份的节日天数
|
|
|
|
+ for (const [ruleYear, holidays] of Object.entries(holidayDays)) {
|
|
|
|
+ const ruleYearNum = parseInt(ruleYear);
|
|
|
|
+ if (ruleYearNum > year) break;
|
|
|
|
+ if (holidays[holiday] !== undefined) {
|
|
|
|
+ lastDefinedDays = holidays[holiday];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return lastDefinedDays;
|
|
|
|
+ }
|
|
|
|
+
|
|
mark(holiday: Holiday) {
|
|
mark(holiday: Holiday) {
|
|
this.dayDetails.holiday = holiday;
|
|
this.dayDetails.holiday = holiday;
|
|
return this;
|
|
return this;
|
|
@@ -51,22 +95,28 @@ class Arrangement {
|
|
if (!this.dayDetails.holiday) {
|
|
if (!this.dayDetails.holiday) {
|
|
throw new Error("should set holiday before saving holiday");
|
|
throw new Error("should set holiday before saving holiday");
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ this.dayDetails.month = month;
|
|
|
|
+ this.dayDetails.day = day;
|
|
this.dayDetails.dayType = dayType;
|
|
this.dayDetails.dayType = dayType;
|
|
- const date = dayjs(`${this.dayDetails.year}-${month}-${day}`);
|
|
|
|
|
|
+
|
|
|
|
+ const date = dayjs(`${this.dayDetails.year}-${month}-${day}`).format("YYYY-MM-DD");
|
|
|
|
+ const holidayDays = this.getHolidayDays(this.dayDetails.year, this.dayDetails.holiday);
|
|
|
|
+ const holidayDescription = `${this.dayDetails.holiday},${holidayDays}`
|
|
|
|
+
|
|
if (dayType === DayType.Holiday) {
|
|
if (dayType === DayType.Holiday) {
|
|
- this.holidays[date.format("YYYY-MM-DD")] = this.dayDetails.holiday;
|
|
|
|
|
|
+ this.holidays[date] = holidayDescription;
|
|
} else if (dayType === DayType.Workday) {
|
|
} else if (dayType === DayType.Workday) {
|
|
- this.workdays[date.format("YYYY-MM-DD")] = this.dayDetails.holiday;
|
|
|
|
|
|
+ this.workdays[date] = holidayDescription;
|
|
} else if (dayType === DayType.InLieu) {
|
|
} else if (dayType === DayType.InLieu) {
|
|
- this.inLieuDays[date.format("YYYY-MM-DD")] = this.dayDetails.holiday;
|
|
|
|
|
|
+ this.inLieuDays[date] = holidayDescription;
|
|
}
|
|
}
|
|
- this.dayDetails.month = month;
|
|
|
|
- this.dayDetails.day = day;
|
|
|
|
return this;
|
|
return this;
|
|
}
|
|
}
|
|
|
|
|
|
to(month: number, day: number) {
|
|
to(month: number, day: number) {
|
|
if (
|
|
if (
|
|
|
|
+ !this.dayDetails.holiday ||
|
|
!this.dayDetails.year ||
|
|
!this.dayDetails.year ||
|
|
!this.dayDetails.month ||
|
|
!this.dayDetails.month ||
|
|
!this.dayDetails.day
|
|
!this.dayDetails.day
|
|
@@ -80,18 +130,19 @@ class Arrangement {
|
|
if (endDate.isBefore(startDate) || endDate.isSame(startDate)) {
|
|
if (endDate.isBefore(startDate) || endDate.isSame(startDate)) {
|
|
throw new Error("end date should be after start date");
|
|
throw new Error("end date should be after start date");
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ const holidayDays = this.getHolidayDays(this.dayDetails.year, this.dayDetails.holiday);
|
|
|
|
+ const holidayDescription = `${this.dayDetails.holiday},${holidayDays}`
|
|
|
|
+
|
|
const diffDays = endDate.diff(startDate, "day");
|
|
const diffDays = endDate.diff(startDate, "day");
|
|
for (let i = 1; i <= diffDays; i++) {
|
|
for (let i = 1; i <= diffDays; i++) {
|
|
- const theDate = startDate.add(i, "day");
|
|
|
|
|
|
+ const theDate = startDate.add(i, "day").format("YYYY-MM-DD");
|
|
if (this.dayDetails.dayType === DayType.Holiday) {
|
|
if (this.dayDetails.dayType === DayType.Holiday) {
|
|
- this.holidays[theDate.format("YYYY-MM-DD")] = this.dayDetails
|
|
|
|
- .holiday as Holiday;
|
|
|
|
|
|
+ this.holidays[theDate] = holidayDescription;
|
|
} else if (this.dayDetails.dayType === DayType.Workday) {
|
|
} else if (this.dayDetails.dayType === DayType.Workday) {
|
|
- this.workdays[theDate.format("YYYY-MM-DD")] = this.dayDetails
|
|
|
|
- .holiday as Holiday;
|
|
|
|
|
|
+ this.workdays[theDate] = holidayDescription;
|
|
} else if (this.dayDetails.dayType === DayType.InLieu) {
|
|
} else if (this.dayDetails.dayType === DayType.InLieu) {
|
|
- this.inLieuDays[theDate.format("YYYY-MM-DD")] = this.dayDetails
|
|
|
|
- .holiday as Holiday;
|
|
|
|
|
|
+ this.inLieuDays[theDate] = holidayDescription;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
return this;
|
|
@@ -122,7 +173,7 @@ class Arrangement {
|
|
t() {
|
|
t() {
|
|
return this.mark(Holiday.T);
|
|
return this.mark(Holiday.T);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/** Labour Day 五一 */
|
|
/** Labour Day 五一 */
|
|
l() {
|
|
l() {
|
|
return this.mark(Holiday.L);
|
|
return this.mark(Holiday.L);
|