import requests import os import json class HolidayAPI: def __init__(self, base_url, cache_dir="cache"): """ Initialize the HolidayAPI class. :param base_url: The base URL for the API endpoint. :param cache_dir: Directory to store cached data. """ self.base_url = base_url self.cached_holidays = {} self.cache_dir = cache_dir if not os.path.exists(self.cache_dir): os.makedirs(self.cache_dir) def _get_cache_path(self, page, size): """ Generate the cache file path for a given page and size. :param page: The page number. :param size: The size of the page. :return: Path to the cache file. """ return os.path.join(self.cache_dir, f"holidays_page{page}_size{size}.json") def get_holidays(self, page=0, size=10): """ Fetch holiday data from the API or cache. :param page: The page number to fetch. :param size: The number of records per page. :return: A list of holiday data dictionaries. """ cache_path = self._get_cache_path(page, size) if os.path.exists(cache_path): with open(cache_path, "r", encoding="utf-8") as cache_file: return json.load(cache_file) url = f"{self.base_url}?page={page}&size={size}" headers = { 'accept': 'application/json' } response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() with open(cache_path, "w", encoding="utf-8") as cache_file: json.dump(data, cache_file, ensure_ascii=False, indent=4) return data else: response.raise_for_status() def get_holidays_by_year(self, year): """ Fetch holiday data for a specific year. If the data is already cached, it returns from the cache. :param year: The year for which to fetch holidays. :return: A list of holiday data dictionaries for the given year. """ if year in self.cached_holidays: return self.cached_holidays[year] all_holidays = [] page = 0 while True: data = self.get_holidays(page=page, size=100) if not data: break all_holidays.extend(data) page += 1 filtered_holidays = [ holiday for holiday in all_holidays if holiday.get("year") == str(year) and holiday.get("date")[4:] != "0903" ] self.cached_holidays[year] = filtered_holidays return filtered_holidays def is_holiday(self, date): """ Check if a specific date is a holiday. :param date: The date to check in YYYYMMDD format. :return: True if the date is a holiday, False otherwise. """ year = date[:4] if year not in self.cached_holidays: self.get_holidays_by_year(year) for holiday in self.cached_holidays[year]: if holiday.get("date") == date and holiday.get("isholiday") == "是": return True return False class Holiday: def __init__(self, date, year, name, isholiday, holidaycategory, description): """ Represent a single holiday entry. :param date: The date of the holiday in YYYYMMDD format. :param year: The year of the holiday. :param name: The name of the holiday (if any). :param isholiday: Whether it is a holiday ('是' or '否'). :param holidaycategory: The category of the holiday. :param description: The description of the holiday. """ self.date = date self.year = year self.name = name self.isholiday = isholiday self.holidaycategory = holidaycategory self.description = description def __repr__(self): return f"Holiday(date={self.date}, year={self.year}, name={self.name}, " \ f"isholiday={self.isholiday}, holidaycategory={self.holidaycategory}, " \ f"description={self.description})" # Example usage if __name__ == "__main__": api = HolidayAPI("https://data.ntpc.gov.tw/api/datasets/308dcd75-6434-45bc-a95f-584da4fed251/json") holidays_2025 = api.get_holidays_by_year(2025) holidays = [] for entry in holidays_2025: holiday = Holiday( date=entry.get("date"), year=entry.get("year"), name=entry.get("name"), isholiday=entry.get("isholiday"), holidaycategory=entry.get("holidaycategory"), description=entry.get("description") ) holidays.append(holiday) for holiday in holidays: print(holiday) # Check if a specific date is a holiday specific_date = "20250102" print(f"Is {specific_date} a holiday? {api.is_holiday(specific_date)}")