export type ChinaWorkdayType = 'workday' | 'weekend' | 'holiday' | 'makeup_workday'; export interface ChinaWorkdayInfo { date: string; type: ChinaWorkdayType; label: string; isWorkday: boolean; source: 'official_2026' | 'weekend_fallback'; } type OverrideInfo = { type: Extract; label: string; }; export const CHINA_HOLIDAY_SOURCE_2026 = { name: '国务院办公厅关于2026年部分节假日安排的通知', url: 'https://www.gov.cn/zhengce/zhengceku/202511/content_7047091.htm', } as const; const OFFICIAL_2026_OVERRIDES: Record = { '2026-01-01': { type: 'holiday', label: '元旦' }, '2026-01-02': { type: 'holiday', label: '元旦' }, '2026-01-03': { type: 'holiday', label: '元旦' }, '2026-01-04': { type: 'makeup_workday', label: '元旦调休上班' }, '2026-02-14': { type: 'makeup_workday', label: '春节调休上班' }, '2026-02-15': { type: 'holiday', label: '春节' }, '2026-02-16': { type: 'holiday', label: '春节' }, '2026-02-17': { type: 'holiday', label: '春节' }, '2026-02-18': { type: 'holiday', label: '春节' }, '2026-02-19': { type: 'holiday', label: '春节' }, '2026-02-20': { type: 'holiday', label: '春节' }, '2026-02-21': { type: 'holiday', label: '春节' }, '2026-02-22': { type: 'holiday', label: '春节' }, '2026-02-23': { type: 'holiday', label: '春节' }, '2026-02-28': { type: 'makeup_workday', label: '春节调休上班' }, '2026-04-04': { type: 'holiday', label: '清明节' }, '2026-04-05': { type: 'holiday', label: '清明节' }, '2026-04-06': { type: 'holiday', label: '清明节' }, '2026-05-01': { type: 'holiday', label: '劳动节' }, '2026-05-02': { type: 'holiday', label: '劳动节' }, '2026-05-03': { type: 'holiday', label: '劳动节' }, '2026-05-04': { type: 'holiday', label: '劳动节' }, '2026-05-05': { type: 'holiday', label: '劳动节' }, '2026-05-09': { type: 'makeup_workday', label: '劳动节调休上班' }, '2026-06-19': { type: 'holiday', label: '端午节' }, '2026-06-20': { type: 'holiday', label: '端午节' }, '2026-06-21': { type: 'holiday', label: '端午节' }, '2026-09-20': { type: 'makeup_workday', label: '国庆节调休上班' }, '2026-09-25': { type: 'holiday', label: '中秋节' }, '2026-09-26': { type: 'holiday', label: '中秋节' }, '2026-09-27': { type: 'holiday', label: '中秋节' }, '2026-10-01': { type: 'holiday', label: '国庆节' }, '2026-10-02': { type: 'holiday', label: '国庆节' }, '2026-10-03': { type: 'holiday', label: '国庆节' }, '2026-10-04': { type: 'holiday', label: '国庆节' }, '2026-10-05': { type: 'holiday', label: '国庆节' }, '2026-10-06': { type: 'holiday', label: '国庆节' }, '2026-10-07': { type: 'holiday', label: '国庆节' }, '2026-10-10': { type: 'makeup_workday', label: '国庆节调休上班' }, }; const DATE_KEY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})/; export function getDateKey(value: string | Date): string { if (value instanceof Date) { return formatDateKey(value); } const matched = value.match(DATE_KEY_PATTERN); if (matched) return `${matched[1]}-${matched[2]}-${matched[3]}`; const parsed = new Date(value); return Number.isNaN(parsed.getTime()) ? '' : formatDateKey(parsed); } export function getChinaWorkdayInfo(value: string | Date): ChinaWorkdayInfo { const date = getDateKey(value); const override = OFFICIAL_2026_OVERRIDES[date]; if (override) { return { date, type: override.type, label: override.label, isWorkday: override.type === 'makeup_workday', source: 'official_2026', }; } const parsed = parseDateKey(date); const weekend = parsed ? isWeekend(parsed) : false; return { date, type: weekend ? 'weekend' : 'workday', label: weekend ? '周末' : '工作日', isWorkday: !weekend, source: 'weekend_fallback', }; } export function isChinaWorkday(value: string | Date): boolean { return getChinaWorkdayInfo(value).isWorkday; } function formatDateKey(date: Date): string { const yyyy = date.getFullYear(); const mm = String(date.getMonth() + 1).padStart(2, '0'); const dd = String(date.getDate()).padStart(2, '0'); return `${yyyy}-${mm}-${dd}`; } function parseDateKey(dateKey: string): Date | null { const matched = dateKey.match(DATE_KEY_PATTERN); if (!matched) return null; const year = Number(matched[1]); const month = Number(matched[2]); const day = Number(matched[3]); if (!year || !month || !day) return null; return new Date(year, month - 1, day); } function isWeekend(date: Date): boolean { const day = date.getDay(); return day === 0 || day === 6; }