### 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
加载失败: ${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