### Install holiday-calendar Source: https://github.com/cg-zhou/holiday-calendar/blob/main/README.md Install the package using npm. ```bash npm install holiday-calendar ``` -------------------------------- ### Database DataLoader Example Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Configure a dataLoader to retrieve holiday data directly from a database. This example demonstrates querying a database based on resource path components. ```javascript const HolidayCalendar = require('holiday-calendar'); const calendar = new HolidayCalendar({ dataLoader: async (resourcePath) => { // 从数据库查询 const [region, file] = resourcePath.split('/'); const year = parseInt(file.split('.')[0]); if (resourcePath === 'index.json') { return await db.query('SELECT * FROM regions'); } return await db.query( 'SELECT * FROM holidays WHERE region = ? AND year = ?', [region, year] ); } }); const dates = await calendar.getDates('CN', 2025); ``` -------------------------------- ### Index File Structure Example Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/data-formats.md The index.json file contains an array of regions, each with its code, start year, and end year for available data. ```json { "regions": [ { "name": "CN", "startYear": 2000, "endYear": 2026 }, { "name": "JP", "startYear": 2000, "endYear": 2026 } ] } ``` -------------------------------- ### Using jsDelivr CDN Configuration Example Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Initialize HolidayCalendar with a baseUrl pointing to the jsDelivr CDN. This is an alternative to the default CDN. ```javascript const HolidayCalendar = require('holiday-calendar'); const calendar = new HolidayCalendar({ baseUrl: 'https://gcore.jsdelivr.net/gh/cg-zhou/holiday-calendar@main/data' }); const dates = await calendar.getDates('CN', 2025); ``` -------------------------------- ### Custom API Service DataLoader Example Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Implement a custom dataLoader to fetch holiday data from a custom API service. This example shows how to include authentication tokens in the request headers. ```javascript const HolidayCalendar = require('holiday-calendar'); const calendar = new HolidayCalendar({ dataLoader: async (resourcePath) => { const token = process.env.API_TOKEN; const response = await fetch( `https://api.example.com/holidays/${resourcePath}`, { headers: { 'Authorization': `Bearer ${token}` } } ); if (!response.ok) { throw new Error(`API 错误: ${response.status}`); } return response.json(); } }); const dates = await calendar.getDates('CN', 2025); ``` -------------------------------- ### Access JSON Data Structures Source: https://github.com/cg-zhou/holiday-calendar/blob/main/README.md Examples of the index file structure and the specific date entry format used in the library. ```json { "regions": [ { "name": "CN", "startYear": 2002, "endYear": 2026 }, { "name": "JP", "startYear": 2000, "endYear": 2026 } ] } ``` ```json { "year": 2026, "region": "CN", "dates": [ { "date": "2026-01-01", "name": "元旦", "name_cn": "元旦", "name_en": "New Year's Day", "type": "public_holiday" }, { "date": "2026-01-04", "name": "元旦补班", "name_cn": "元旦补班", "name_en": "New Year's Day Workday", "type": "transfer_workday" } ] } ``` -------------------------------- ### Instantiate HolidayCalendar with Default Options Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/api-reference/HolidayCalendar.md Create a new HolidayCalendar instance using default configurations. No specific setup is required beyond importing the class. ```javascript const HolidayCalendar = require('holiday-calendar'); // Use default configuration const calendar = new HolidayCalendar(); ``` -------------------------------- ### Node.js Environment Variable Example Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Demonstrates how to use environment variables within a custom dataLoader in Node.js. This allows for dynamic configuration of API endpoints or other settings. ```javascript const HolidayCalendar = require('holiday-calendar'); const calendar = new HolidayCalendar({ dataLoader: async (resourcePath) => { const apiUrl = process.env.HOLIDAY_API_URL || 'https://api.example.com'; const response = await fetch(`${apiUrl}/${resourcePath}`); return response.json(); } }); ``` -------------------------------- ### Node.js Local File DataLoader Example Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Configure a custom dataLoader to read holiday data from local files in a Node.js environment. This requires specifying the path to the data directory. ```javascript const fs = require('fs'); const path = require('path'); const HolidayCalendar = require('holiday-calendar'); const calendar = new HolidayCalendar({ dataLoader: async (resourcePath) => { const filePath = path.join(__dirname, 'holiday-data', resourcePath); const content = fs.readFileSync(filePath, 'utf8'); return JSON.parse(content); } }); const dates = await calendar.getDates('CN', 2025); ``` -------------------------------- ### DataLoader with Data Transformation Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Create a dataLoader that transforms the fetched holiday data before it's used, for example, by converting dates to timestamps. ```javascript const transformingDataLoader = async (resourcePath) => { const response = await fetch(`https://unpkg.com/holiday-calendar/data/${resourcePath}`); const data = await response.json(); // Example: Convert all dates to timestamps if (data.dates) { data.dates = data.dates.map(d => ({ ...d, timestamp: new Date(d.date).getTime() })); } return data; }; const calendar = new HolidayCalendar({ dataLoader: transformingDataLoader }); ``` -------------------------------- ### Browser CDN Usage Example Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Include the Holiday Calendar library via a CDN script tag in an HTML file. The library is automatically configured for browser usage. ```html Holiday Calendar ``` -------------------------------- ### DataLoader with IndexedDB Persistence (Browser) Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Utilize browser's IndexedDB for persistent caching of holiday data. This example outlines the logic for checking cache, fetching if needed, and storing the data. ```javascript const indexedDBLoader = async (resourcePath) => { const db = await openDatabase(); // Check IndexedDB const cached = await getFromIndexedDB(db, resourcePath); if (cached) { return cached; } // Fetch from CDN const response = await fetch(`https://unpkg.com/holiday-calendar/data/${resourcePath}`); const data = await response.json(); // Save to IndexedDB await saveToIndexedDB(db, resourcePath, data); return data; }; const calendar = new HolidayCalendar({ dataLoader: indexedDBLoader }); ``` -------------------------------- ### Annual Data File Structure Example Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/data-formats.md Annual data files (e.g., CN/2025.json) contain the year, region, and a list of dates with their associated holiday information. ```json { "year": 2025, "region": "CN", "dates": [ { "date": "2025-01-01", "name": "元旦", "name_cn": "元旦", "name_en": "New Year's Day", "type": "public_holiday" }, { "date": "2025-01-26", "name": "春节补班", "name_cn": "春节补班", "name_en": "Spring Festival Workday", "type": "transfer_workday" }, { "date": "2025-01-28", "name": "春节", "name_cn": "春节", "name_en": "Chinese New Year", "type": "public_holiday" } ] } ``` -------------------------------- ### Plan Vacation with Holidays Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/examples-and-recipes.md Calculates vacation details including start and end dates, total days, holidays, and workdays within the vacation period. It requires the region, start date, and desired vacation days as input. ```javascript async function planVacation(region, startDate, vacationDays) { let dayCount = 0; let current = new Date(startDate); const holidays = []; const workdays = []; while (dayCount < vacationDays) { const dateStr = current.toISOString().split('T')[0]; if (await calendar.isHoliday(region, dateStr)) { holidays.push(dateStr); } else { workdays.push(dateStr); } dayCount++; current.setDate(current.getDate() + 1); } return { startDate, endDate: current.toISOString().split('T')[0], totalDays: vacationDays, holidays: holidays.length, workdays: workdays.length, calendarDays: holidays.concat(workdays) }; } // 使用 const plan = await planVacation('CN', '2025-02-01', 10); console.log(`假期计划`); console.log(` 开始: ${plan.startDate}`); console.log(` 结束: ${plan.endDate}`); console.log(` 共计: ${plan.totalDays} 天`); console.log(` 假期: ${plan.holidays} 天`); console.log(` 工作日: ${plan.workdays} 天`); ``` -------------------------------- ### Generate a workday calendar for a month Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/overview.md An example function to generate a calendar for a specific month and year, indicating for each day whether it is a workday and providing holiday information if available. This can be used for leave application planning. ```javascript async function generateWorkdayCalendar(region, year, month) { const dates = await calendar.getDates(region, year, { startDate: `${year}-${String(month).padStart(2, '0')}-01`, endDate: `${year}-${String(month + 1).padStart(2, '0')}-00` }); const calendar = []; for (let day = 1; day <= 31; day++) { const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`; const isValid = new Date(dateStr).getMonth() + 1 === month; if (!isValid) break; const info = dates.find(d => d.date === dateStr); const isWorkday = await calendar.isWorkday(region, dateStr); calendar.push({ date: dateStr, day, isWorkday, info: info || null }); } return calendar; } ``` -------------------------------- ### Browser Custom Server DataLoader Example Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Configure Holiday Calendar in a browser to load data from a custom API endpoint. This uses the fetch API to make requests to a local or remote server. ```javascript const calendar = new HolidayCalendar({ dataLoader: async (resourcePath) => { // 从本地 API 服务器加载 const response = await fetch(`/api/holidays/${resourcePath}`); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.json(); } }); calendar.getDates('CN', 2025).then(dates => { console.log('节假日数据:', dates); }); ``` -------------------------------- ### Basic Usage of Holiday Calendar Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/overview.md Demonstrates how to initialize the HolidayCalendar, retrieve index information, load data for a specific year and region, query date details, get lists of holidays, and check if a date is a workday or holiday. ```javascript // Node.js const HolidayCalendar = require('holiday-calendar'); // 浏览器 // // window.HolidayCalendar 将可用 const calendar = new HolidayCalendar(); // 获取支持的地区信息 const index = await calendar.getIndex(); // 获取某年的全部数据 const data = await calendar.load('CN', 2025); // 查询特定日期 const dateInfo = await calendar.getDateInfo('CN', '2025-01-01'); // 获取指定年份的所有节假日 const holidays = await calendar.getDates('CN', 2025, { type: 'public_holiday' }); // 判断是否为工作日 const isWorkday = await calendar.isWorkday('CN', '2025-01-15'); // 判断是否为假期 const isHoliday = await calendar.isHoliday('CN', '2025-01-19'); ``` -------------------------------- ### Get Holiday Index Information Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/api-reference/HolidayCalendar.md Retrieve the holiday index, which lists all supported regions and their data coverage years. Useful for checking data availability. ```javascript const calendar = new HolidayCalendar(); const index = await calendar.getIndex(); console.log('Supported regions:', index.regions); // Output: Supported regions: [ // { name: 'CN', startYear: 2000, endYear: 2026 }, // { name: 'JP', startYear: 2000, endYear: 2026 } // ] // Check if data for China is available for a specific year const cnRegion = index.regions.find(r => r.name === 'CN'); if (2025 >= cnRegion.startYear && 2025 <= cnRegion.endYear) { console.log('China data available for 2025'); } ``` -------------------------------- ### Check if a day is a workday Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/overview.md Example demonstrating how to check if a specific date is a workday using the `isWorkday` method. This is useful for planning work schedules or leave applications. ```javascript const date = '2025-01-15'; const isWorkday = await calendar.isWorkday('CN', date); if (isWorkday) { console.log(`${date} 是工作日,需要工作`); } else { console.log(`${date} 不是工作日,可以休息`); } ``` -------------------------------- ### Display Holidays for a Specific Region and Year Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/examples-and-recipes.md This example demonstrates how to load and display public holidays for a selected region and year using the HolidayCalendar library. It includes HTML for controls (region select, year input, load button) and a div to display the holiday list. ```javascript // HTML + CSS + JavaScript 完整示例 const html = `
`; const calendar = new HolidayCalendar(); document.getElementById('loadBtn').addEventListener('click', async () => { const region = document.getElementById('regionSelect').value; const year = parseInt(document.getElementById('yearInput').value); try { const dates = await calendar.getDates(region, year, { type: 'public_holiday' }); let html = `

${year} 年 ${region} 的法定节假日

'; document.getElementById('holidayList').innerHTML = html; } catch (error) { document.getElementById('holidayList').innerHTML = `

加载失败: ${error.message}

`; } }); ``` -------------------------------- ### Count workdays in a month Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/overview.md An example function to count the number of workdays within a specific month and year for a given region. It considers both regular workdays and transfer workdays. ```javascript async function countWorkdays(region, year, month) { const startDate = `${year}-${String(month).padStart(2, '0')}-01`; const endDate = `${year}-${String(month + 1).padStart(2, '0')}-00`; const dates = await calendar.getDates(region, year, { startDate, endDate }); let count = 0; for (const d of dates) { if (d.type === 'transfer_workday') { count++; // 调休工作日也算工作日 } } // 再加上该月所有的周一至周五(除去法定假日) // ... 详细逻辑 return count; } ``` -------------------------------- ### Parallel Loading with Promise.all Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/advanced-usage.md Demonstrates how to load multiple holiday resources in parallel using Promise.all. This is useful for fetching data for multiple years or regions simultaneously. ```javascript const HolidayCalendar = require('holiday-calendar'); const calendar = new HolidayCalendar(); // 使用 Promise.all() 并行加载多个资源 async function loadMultipleYears(region, startYear, endYear) { const promises = []; for (let year = startYear; year <= endYear; year++) { promises.push(calendar.load(region, year)); } return Promise.all(promises); } ``` -------------------------------- ### RegionInfo Data Structure Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/overview.md Represents the structure for information about a supported region, including its code, start year, and end year for available data. ```json { "name": string, // 地区代码 ('CN', 'JP') "startYear": number, // 数据起始年份 "endYear": number // 数据结束年份 } ``` -------------------------------- ### Include via Browser Script Source: https://github.com/cg-zhou/holiday-calendar/blob/main/README.md Include the library in browser environments using CDN links. ```html ``` -------------------------------- ### Initialize HolidayCalendar with Options Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md The HolidayCalendar constructor accepts an optional configuration object. All fields within this object are optional. ```javascript new HolidayCalendar(options = {}) ``` -------------------------------- ### Using a Local Server for Base URL Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Set the baseUrl to point to holiday data deployed on your own server. Ensure the server is accessible and serves data in the expected format. ```javascript const calendar = new HolidayCalendar({ baseUrl: 'https://my-server.example.com/api/holidays' }); ``` -------------------------------- ### Configure Holiday Calendar with Alternative CDN Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/README.md If the default CDN (unpkg) is inaccessible, specify an alternative CDN URL for the data files when initializing the calendar. ```javascript const calendar = new HolidayCalendar({ baseUrl: 'https://gcore.jsdelivr.net/gh/cg-zhou/holiday-calendar@main/data' }); ``` -------------------------------- ### Calculate Workdays Between Two Dates Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/examples-and-recipes.md Calculates the number of workdays between a start date and an end date in a specified region. It iterates through each day and checks if it's a workday. ```javascript async function countWorkdaysBetween(region, startDate, endDate) { let workdayCount = 0; const current = new Date(startDate); const end = new Date(endDate); while (current <= end) { const dateStr = current.toISOString().split('T')[0]; if (await calendar.isWorkday(region, dateStr)) { workdayCount++; } current.setDate(current.getDate() + 1); } return workdayCount; } // 使用 const workdays = await countWorkdaysBetween('CN', '2025-01-01', '2025-01-31'); console.log(`2025年1月有 ${workdays} 个工作日`); ``` -------------------------------- ### Batched Loading with Concurrency Limit Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/advanced-usage.md Shows how to load holiday data in batches with a specified concurrency limit. This prevents overwhelming the server or network by controlling the number of simultaneous requests. ```javascript // 批量加载,并发请求数量受限 async function loadWithConcurrency(region, years, concurrency = 3) { const results = []; for (let i = 0; i < years.length; i += concurrency) { const batch = years.slice(i, i + concurrency); const batchResults = await Promise.all( batch.map(year => calendar.load(region, year)) ); results.push(...batchResults); } return results; } // 使用示例 const cnData = await loadWithConcurrency('CN', [2023, 2024, 2025], 2); ``` -------------------------------- ### Find Next Public Holiday Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/overview.md Finds the next public holiday for a given region starting from a specific date. If no holiday is found in the current year, it queries the following year. ```javascript async function findNextHoliday(region, fromDate) { const year = parseInt(fromDate.slice(0, 4)); const dates = await calendar.getDates(region, year, { type: 'public_holiday', startDate: fromDate }); if (dates.length > 0) { return dates[0]; } // 如果当年没有,查询下一年 const nextYearDates = await calendar.getDates(region, year + 1, { type: 'public_holiday' }); return nextYearDates[0] || null; } ``` -------------------------------- ### Read Local Holiday Data in Node.js Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/data-formats.md Demonstrates how to read local holiday data files (JSON format) in a Node.js environment using the 'fs' and 'path' modules. Ensure the data path is correctly configured. ```javascript const fs = require('fs'); const path = require('path'); const dataPath = path.join(__dirname, 'node_modules/holiday-calendar/data'); const cnData = JSON.parse( fs.readFileSync(path.join(dataPath, 'CN/2025.json'), 'utf-8') ); ``` -------------------------------- ### Use Holiday Calendar in Node.js Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/README.md Import the library using require() for Node.js environments. Instantiate the calendar object to begin using its features. ```javascript const HolidayCalendar = require('holiday-calendar'); const calendar = new HolidayCalendar(); ``` -------------------------------- ### Get Detailed Date Information Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/overview.md Retrieves detailed information about a specific date, including its name and type (e.g., public holiday). This method is useful for displaying specific event details. ```javascript const info = await calendar.getDateInfo('CN', '2025-01-01'); if (info) { console.log(info.name_cn); // 元旦 console.log(info.type); // public_holiday } ``` -------------------------------- ### Custom Server DataLoader Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md Implement a dataLoader to fetch holiday data from a custom API server. ```javascript const customDataLoader = async (resourcePath) => { const response = await fetch(`https://api.example.com/holidays/${resourcePath}`); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.json(); }; const calendar = new HolidayCalendar({ dataLoader: customDataLoader }); ``` -------------------------------- ### Calculate Required Workdays for Leave Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/examples-and-recipes.md Calculates the number of workdays needed for a leave period between a start and end date in a specified region. This is similar to calculating workdays between two dates but framed for leave calculation. ```javascript async function calculateLeaveWorkdays(region, startDate, endDate) { let workdayCount = 0; const current = new Date(startDate); const end = new Date(endDate); while (current <= end) { const dateStr = current.toISOString().split('T')[0]; if (await calendar.isWorkday(region, dateStr)) { workdayCount++; } current.setDate(current.getDate() + 1); } return workdayCount; } // 使用 const leaveWorkdays = await calculateLeaveWorkdays('CN', '2025-02-01', '2025-02-10'); console.log(`需要请假 ${leaveWorkdays} 个工作日`); ``` -------------------------------- ### Get Filtered Date Lists for a Region and Year Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/api-reference/HolidayCalendar.md Retrieve a list of dates for a specific region and year, with support for filtering by type (public holiday or transfer workday) and date range. Useful for specific queries. ```javascript const calendar = new HolidayCalendar(); // Get all entries for China in 2025 const allDates = await calendar.getDates('CN', 2025); console.log('Total', allDates.length, 'records'); // Get only public holidays const holidays = await calendar.getDates('CN', 2025, { type: 'public_holiday' }); console.log('Public holidays:', holidays.length); holidays.forEach(h => { console.log(`${h.date}: ${h.name_cn}`); }); // Get only transfer workdays const workdays = await calendar.getDates('CN', 2025, { type: 'transfer_workday' }); console.log('Transfer workdays:', workdays); // Get all entries in January const january = await calendar.getDates('CN', 2025, { startDate: '2025-01-01', endDate: '2025-01-31' }); console.log('January entries:', january); // Combined filter: public holidays in May const mayHolidays = await calendar.getDates('CN', 2025, { type: 'public_holiday', startDate: '2025-05-01', endDate: '2025-05-31' }); console.log('May public holidays:', mayHolidays); ``` -------------------------------- ### Use Holiday Calendar in Browser via CDN Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/README.md Include the library via a CDN link in your HTML to make it available as a global variable in the browser. Instantiate the calendar object. ```html ``` -------------------------------- ### Calculate Actual End Date After Adding Workdays Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/examples-and-recipes.md Calculates the actual end date after adding a specified number of workdays to a start date in a given region. It skips weekends and holidays to find the correct end date. ```javascript async function addWorkdays(region, startDate, workdaysToAdd) { let workdayCount = 0; let current = new Date(startDate); while (workdayCount < workdaysToAdd) { const dateStr = current.toISOString().split('T')[0]; if (await calendar.isWorkday(region, dateStr)) { workdayCount++; } if (workdayCount < workdaysToAdd) { current.setDate(current.getDate() + 1); } } return current.toISOString().split('T')[0]; } // 使用:从 2025-01-01 起 10 个工作日后的日期 const endDate = await addWorkdays('CN', '2025-01-01', 10); console.log(`10 个工作日后: ${endDate}`); ``` -------------------------------- ### Function to get date description with validation Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/errors.md This function retrieves and formats the description of a date, including validation for the date format. It handles cases where a date might not have a special designation, defaulting to 'normal workday' or 'normal weekend'. ```javascript async function getDateDescription(region, dateStr) { try { // 验证日期格式 if (!/^ {4}- {2}- {2}$/.test(dateStr)) { throw new Error(`日期格式错误: ${dateStr},应为 YYYY-MM-DD`); } const info = await calendar.getDateInfo(region, dateStr); if (info) { return `${dateStr} 是 ${info.name_cn}(${info.type})`; } else { // 判断是否为普通周末 const dayOfWeek = new Date(dateStr).getDay(); if (dayOfWeek === 0 || dayOfWeek === 6) { return `${dateStr} 是普通周末`; } else { return `${dateStr} 是普通工作日`; } } } catch (error) { console.error('查询失败:', error.message); return null; } } const desc = await getDateDescription('CN', '2025-01-01'); console.log(desc); ``` -------------------------------- ### Implement Caching for Holiday Queries Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/advanced-usage.md This snippet demonstrates how to create an optimized calendar class that caches query results to improve performance. It uses a Map for caching and implements a Least Recently Used (LRU) eviction policy when the cache size exceeds a defined limit. Use this when making repeated calls with the same parameters. ```javascript class OptimizedCalendar { constructor() { this.calendar = new HolidayCalendar(); this.queryCache = new Map(); this.maxCacheSize = 100; } async getDates(region, year, options = {}) { // 生成缓存键 const cacheKey = this._getCacheKey(region, year, options); if (this.queryCache.has(cacheKey)) { console.log(`[缓存命中] ${cacheKey}`); return this.queryCache.get(cacheKey); } // 执行查询 const result = await this.calendar.getDates(region, year, options); // 保存到缓存 this.queryCache.set(cacheKey, result); // 限制缓存大小(FIFO) if (this.queryCache.size > this.maxCacheSize) { const firstKey = this.queryCache.keys().next().value; this.queryCache.delete(firstKey); } return result; } _getCacheKey(region, year, options) { const optionsStr = JSON.stringify(options); return `${region}:${year}:${optionsStr}`; } clearCache() { this.queryCache.clear(); } } // 使用 const cal = new OptimizedCalendar(); const dates1 = await cal.getDates('CN', 2025, { type: 'public_holiday' }); const dates2 = await cal.getDates('CN', 2025, { type: 'public_holiday' }); // 使用缓存 ``` -------------------------------- ### Custom Data Loader for Holiday Calendar Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/data-formats.md Shows how to implement a custom data loader for the HolidayCalendar to fetch holiday data from any source, such as a database or a custom server API. This allows for flexible data retrieval strategies. ```javascript const calendar = new HolidayCalendar({ dataLoader: async (path) => { // 可以从数据库、本地服务器等加载 const response = await fetch(`https://my-server.com/holidays/${path}`); return response.json(); } }); ``` -------------------------------- ### Safely Get Index with Error Handling Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/errors.md Provides a robust function to fetch the calendar index, including error handling for network issues, missing data sources (404), and invalid JSON. It returns null on failure and logs specific user-friendly messages. ```javascript async function safeGetIndex() { try { return await calendar.getIndex(); } catch (error) { console.error('无法获取索引:', error.message); if (error.message.includes('404')) { console.log('提示:数据源可能已移动,请检查配置'); } else if (error.message.includes('fetch')) { console.log('提示:网络连接失败,请检查网络'); } return null; } } const index = await safeGetIndex(); if (!index) { console.log('使用离线备用数据'); // 使用备用数据 } ``` -------------------------------- ### Express Server Integration Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/advanced-usage.md Sets up an Express.js server to provide API endpoints for fetching holiday data, including index, specific year data, and workday checks. Requires 'express' and 'holiday-calendar' packages. ```javascript const express = require('express'); const HolidayCalendar = require('holiday-calendar'); const app = express(); const calendar = new HolidayCalendar(); // 中间件:错误处理 app.use((err, req, res, next) => { console.error('错误:', err); res.status(500).json({ error: err.message }); }); // API: 获取索引 app.get('/api/holidays/index', async (req, res, next) => { try { const index = await calendar.getIndex(); res.json(index); } catch (error) { next(error); } }); // API: 获取特定年份数据 app.get('/api/holidays/:region/:year', async (req, res, next) => { try { const { region, year } = req.params; const data = await calendar.load(region, parseInt(year)); res.json(data); } catch (error) { next(error); } }); // API: 判断日期是否为工作日 app.get('/api/is-workday/:region/:date', async (req, res, next) => { try { const { region, date } = req.params; const isWorkday = await calendar.isWorkday(region, date); res.json({ date, region, isWorkday }); } catch (error) { next(error); } }); app.listen(3000, () => { console.log('Holiday Calendar API 运行在 http://localhost:3000'); }); ``` -------------------------------- ### Handling Data Loading Errors Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/errors.md Demonstrates how to catch and handle 'Failed to load data' errors, which can occur due to network issues, HTTP errors, JSON parsing failures, missing resources, or custom data loader exceptions. It shows specific checks for different error causes. ```javascript const calendar = new HolidayCalendar(); // 场景 1: 网络连接失败 try { const dates = await calendar.getDates('CN', 2025); } catch (error) { if (error.message.includes('Failed to load data')) { console.error('数据加载失败:', error.message); // 可以提示用户检查网络连接 } } // 场景 2: 获取不存在的地区 try { const dates = await calendar.getDates('XX', 2025); // XX 不是有效地区代码 } catch (error) { if (error.message.includes('Failed to load data for XX/2025.json')) { console.error('地区 XX 不存在或数据不可用'); } } // 场景 3: 获取数据范围外的年份 try { const index = await calendar.getIndex(); const cnRegion = index.regions.find(r => r.name === 'CN'); // 检查年份是否在支持范围内 if (1999 < cnRegion.startYear) { console.log('1999 年数据不可用,CN 数据从', cnRegion.startYear, '开始'); } const dates = await calendar.getDates('CN', 1999); } catch (error) { console.error('加载失败:', error.message); } ``` ```javascript const calendar2 = new HolidayCalendar({ dataLoader: async (path) => { throw new Error('自定义错误:数据库连接失败'); } }); try { const dates = await calendar2.getDates('CN', 2025); } catch (error) { // error.message 会是: // "Failed to load data for CN/2025.json: 自定义错误:数据库连接失败" console.error(error.message); } ``` -------------------------------- ### HolidayCalendar Constructor Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/api-reference/HolidayCalendar.md Initializes a new HolidayCalendar instance. It accepts an optional options object for customizing data loading and base URL. ```APIDOC ## HolidayCalendar(options) ### Description Creates a new HolidayCalendar instance. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **options** (Object) - Optional - Configuration object. * **options.dataLoader** (Function) - Optional - Custom data loading function. Accepts a resource path string and returns a Promise. * **options.baseUrl** (string) - Optional - CDN base URL for the default data loader. Defaults to 'https://unpkg.com/holiday-calendar/data'. ### Response HolidayCalendar instance ### Request Example ```javascript const HolidayCalendar = require('holiday-calendar'); // Using default configuration const calendar = new HolidayCalendar(); // Using a custom data loader const calendar = new HolidayCalendar({ dataLoader: async (path) => { const response = await fetch(`https://my-server.com/holidays/${path}`); return response.json(); } }); ``` ``` -------------------------------- ### 性能优化模式 - 并行加载 Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/README.md 展示如何使用 Promise.all 来并行加载多年数据,以提高数据加载的效率。 ```javascript // 并行加载多年数据 const data = await Promise.all([ calendar.load('CN', 2024), calendar.load('CN', 2025), calendar.load('CN', 2026) ]); ``` -------------------------------- ### Default DataLoader Implementation Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/configuration.md This is the default asynchronous function used to load holiday data. It constructs a URL using the provided path and the configured baseUrl, then fetches the JSON data. ```javascript async defaultDataLoader(path) { const url = `${this.baseUrl}/${path}`; try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); } catch (error) { throw new Error(`Failed to load data for ${path}: ${error.message}`); } } ``` -------------------------------- ### Implement Application-Level Caching for Holiday Data Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/data-formats.md Shows a basic implementation of application-level caching using a JavaScript Map to store and retrieve holiday data. This pattern helps avoid redundant data fetching and improves performance, especially for frequently accessed data. ```javascript // 应用层缓存 const cache = new Map(); async function getCachedDates(region, year) { const key = `${region}-${year}`; if (!cache.has(key)) { cache.set(key, await calendar.getDates(region, year)); } return cache.get(key); } ``` -------------------------------- ### Handle Lunar Calendar Holiday Variations Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/data-formats.md Demonstrates how to dynamically retrieve and filter holidays like the Spring Festival, emphasizing the importance of not hardcoding dates due to their variation each year. This ensures accurate holiday calculations across different years. ```javascript // 不要硬编码春节日期,每年都会不同 const cnDates2025 = await calendar.getDates('CN', 2025); const springFestival2025 = cnDates2025.filter(d => d.name_cn.includes('春节') ); const cnDates2026 = await calendar.getDates('CN', 2026); const springFestival2026 = cnDates2026.filter(d => d.name_cn.includes('春节') ); // 这两年的春节日期会不同 ``` -------------------------------- ### Correct Date String Format (ISO 8601) Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/data-formats.md Illustrates the correct ISO 8601 format for date strings ('YYYY-MM-DD') and highlights common incorrect formats that should be avoided. Using the correct format ensures consistency and avoids parsing errors. ```javascript // 正确 const dateStr = '2025-01-15'; // ISO 8601 // 错误 const dateStr = '2025/01/15'; // 斜杠分隔 const dateStr = '01/15/2025'; // 美国格式 const dateStr = '15-01-2025'; // 欧洲格式 ``` -------------------------------- ### Performance Analysis for Holiday Calendar Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/advanced-usage.md A wrapper class for performance analysis of Holiday Calendar operations. It tracks call counts, total execution time, and individual call durations for methods like getDates. ```javascript class PerformanceCalendar { constructor() { this.calendar = new HolidayCalendar(); this.metrics = { callCount: 0, totalTime: 0, calls: [] }; } async getDates(region, year, options = {}) { const startTime = performance.now(); try { const result = await this.calendar.getDates(region, year, options); const duration = performance.now() - startTime; this.metrics.callCount++; this.metrics.totalTime += duration; this.metrics.calls.push({ method: 'getDates', region, year, duration: `${duration.toFixed(2)}ms`, success: true }); return result; } catch (error) { const duration = performance.now() - startTime; this.metrics.calls.push({ method: 'getDates', region, year, duration: `${duration.toFixed(2)}ms`, success: false, error: error.message }); throw error; } } getMetrics() { return { ...this.metrics, averageTime: this.metrics.callCount > 0 ? `${(this.metrics.totalTime / this.metrics.callCount).toFixed(2)}ms` : '0ms' }; } } // 使用 const cal = new PerformanceCalendar(); await cal.getDates('CN', 2025); await cal.getDates('CN', 2024); await cal.getDates('JP', 2025); console.log(cal.getMetrics()); // 输出: // { // callCount: 3, // totalTime: 150.50, // averageTime: '50.17ms', // calls: [...] // } ``` -------------------------------- ### Initialize HolidayCalendar with AMD/RequireJS Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/overview.md Initializes the HolidayCalendar instance using AMD/RequireJS module loading. This is suitable for environments that support these module systems. ```javascript require(['holiday-calendar'], function(HolidayCalendar) { const calendar = new HolidayCalendar(); }); ``` -------------------------------- ### Instantiate HolidayCalendar with Custom DataLoader Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/api-reference/HolidayCalendar.md Create a new HolidayCalendar instance with a custom data loader function. This allows for fetching holiday data from a custom source instead of the default CDN. ```javascript const HolidayCalendar = require('holiday-calendar'); // Use custom data loader const calendar = new HolidayCalendar({ dataLoader: async (path) => { const response = await fetch(`https://my-server.com/holidays/${path}`); return response.json(); } }); ``` -------------------------------- ### Generate Monthly Work Calendar Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/examples-and-recipes.md Creates a detailed calendar for a specific month and year in a given region. It includes the date, day of the week, and status (workday, holiday, transfer, weekend) for each day. ```javascript async function generateMonthCalendar(region, month, year) { const monthStr = String(month).padStart(2, '0'); const data = await calendar.load(region, year); const calendar = []; const lastDay = new Date(year, month, 0).getDate(); for (let day = 1; day <= lastDay; day++) { const dayStr = String(day).padStart(2, '0'); const dateStr = `${year}-${monthStr}-${dayStr}`; const dateInfo = data.dates.find(d => d.date === dateStr); const dayOfWeek = new Date(dateStr).getDay(); const dayName = ['日', '一', '二', '三', '四', '五', '六'][dayOfWeek]; let status = 'workday'; let displayName = '工作日'; if (dateInfo?.type === 'public_holiday') { status = 'holiday'; displayName = dateInfo.name_cn; } else if (dateInfo?.type === 'transfer_workday') { status = 'transfer'; displayName = dateInfo.name_cn; } else if (dayOfWeek === 0 || dayOfWeek === 6) { status = 'weekend'; displayName = '周末'; } calendar.push({ date: dateStr, day, dayOfWeek: dayName, status, displayName }); } return calendar; } // 使用 const cal = await generateMonthCalendar('CN', 1, 2025); cal.forEach(entry => { console.log(`${entry.date} (周${entry.dayOfWeek}): ${entry.displayName}`); }); ``` -------------------------------- ### Implement Error Recovery and Fallback Mechanism Source: https://github.com/cg-zhou/holiday-calendar/blob/main/_autodocs/advanced-usage.md This function provides a safe way to fetch dates, attempting an online fetch first and falling back to a basic, local generation if the online fetch fails. It includes specific logic to handle 'Failed to load' errors by returning only weekend/workday information. Use this to ensure availability of basic data even during network issues. ```javascript async function safeGetDates(region, year, options = {}) { try { // 尝试从网络加载 return await calendar.getDates(region, year, options); } catch (error) { console.error('在线加载失败:', error.message); // 降级到备用方案 if (error.message.includes('Failed to load')) { console.log('使用降级方案:只返回周末/工作日划分'); // 返回基础信息(不包含具体假日) return generateBasicDates(year, options); } throw error; } } function generateBasicDates(year, options = {}) { const dates = []; const startDate = new Date(year, 0, 1); const endDate = new Date(year, 11, 31); for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) { const dateStr = d.toISOString().split('T')[0]; const dayOfWeek = d.getDay(); const isWeekend = dayOfWeek === 0 || dayOfWeek === 6; const type = options.type; if (!type || (type === 'public_holiday' && isWeekend)) { dates.push({ date: dateStr, name: isWeekend ? '周末' : '工作日', name_cn: isWeekend ? '周末' : '工作日', name_en: isWeekend ? 'Weekend' : 'Workday', type: isWeekend ? 'public_holiday' : 'transfer_workday' }); } } return dates; } ```