diff --git a/.gitignore b/.gitignore index 262dccf..775c7d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /dist /holiday_jp.egg-info +/venv diff --git a/README.md b/README.md index a17571b..0bbd3c4 100644 --- a/README.md +++ b/README.md @@ -2,66 +2,116 @@ [![PyPI downloads](https://img.shields.io/pypi/dm/holiday-jp.svg)](https://pypi.org/project/holiday-jp/) [![GitHub release](https://img.shields.io/github/release/holiday-jp/holiday_jp-python.svg)](https://github.com/holiday-jp/holiday_jp-python/releases) -# holiday_jp-python +# holiday_jp-python リポジトリ -Japanese holiday for Python 3+ -using dataset from https://github.com/holiday-jp/holiday_jp +## 概要 -## install +`holiday_jp-python` リポジトリは、**Python言語**向けの日本の祝日データを提供するライブラリです。このライブラリを使用することで、簡単に日本の祝日情報を取得し、カレンダーアプリケーションや日程管理ツールなどで利用することができます。[holiday-jp](https://github.com/holiday-jp/holiday_jp) データセットを使用。 -> pip3 install holiday-jp +## インストール -### If you want to contribute -Build on linux with python 3.x +`pip` を使用して、簡単に `holiday_jp` ライブラリをインストールできます。 -#### Clone the project or download the source -> git clone https://github.com/holiday-jp/holiday_jp-python - -#### test -> python3 -m unittest holiday_jp.test +```bash +pip install holiday-jp +``` -OR +## 使用方法 -> make test +```python +from holiday_jp import HolidayJp -Build command: -> python3 setup.py sdist +# 特定の年の祝日を取得 +holidays_2024 = HolidayJp.year_holidays(year=2024) +print([one_holiday.date_obj for one_holiday in holidays_2024]) -OR +>> [datetime.date(2024, 1, 1), datetime.date(2024, 1, 8), datetime.date(2024, 2, 11), datetime.date(2024, 2, 12), datetime.date(2024, 2, 23), datetime.date(2024, 3, 20), datetime.date(2024, 4, 29), datetime.date(2024, 5, 3), datetime.date(2024, 5, 4), datetime.date(2024, 5, 5),... -> make build +# 休日の情報を文字列として取得するためのフォーマットを指定する。 +def format_holiday_as_string(holiday): + return f"{holiday.date_obj.strftime('%Y年%m月%d日')}({holiday.week})「{holiday.name}」" -It will build the package and be available in the dist/ directory +print([format_holiday_as_string(one_holiday) for one_holiday in holidays_2024]) -### alternative install +>> ['2024年01月01日(月)「元日」', '2024年01月08日(月)「成人の日」', '2024年02月11日(日)「建国記念の日」', '2024年02月12日(月)「建国記念の日 振替休日」', '2024年02月23日(金)「天皇誕生日」', '2024年03月20日(水)「春分の日」', '2024年04月29日(月)「昭和の日」', '2024年05月03日(金)「憲法記念日」',... +``` -download the release and install this way: -pip3 install holiday_jp-xxx.tar.gz +## サポートされている機能 -## Usage +- 特定の月の祝日一覧を取得: ```python from holiday_jp import HolidayJp -# with string date YYYY-MM-DD -if HolidayJp('1990-01-01').is_holiday: - print('True') -import datetime +# 特定の月の祝日一覧を取得 +holidays_may_2024 = HolidayJp.month_holidays(year=2024, month=5) +print([one_holiday.date_obj for one_holiday in holidays_may_2024]) + +>> [datetime.date(2024, 5, 3), datetime.date(2024, 5, 4), datetime.date(2024, 5, 5), datetime.date(2024, 5, 6)] +``` + +- 特定の日が振替休日かどうかを確認: + +```python from holiday_jp import HolidayJp -# or date object -if HolidayJp(datetime.date.today()).is_holiday: - print('False') -else: - print('True') - -# Between return holidays between 2 dates in text -holidays = HolidayJp.between('2009-01-01', '2009-01-31') -new_year_day = holidays[0] -self.assertEqual(datetime.date(year=2009, month=1, day=1), new_year_day.date_obj) -self.assertEqual('元日', new_year_day.name) - -# Or date object -holidays = HolidayJp.between(datetime.date(year=2008, month=12, day=23), datetime.date(year=2009, month=1, day=12)) + +# 特定の日が振替休日かどうかを確認 +is_substitute_holiday = holiday.is_substitute_holiday(date='2024-05-06') +print(is_substitute_holiday) + +>> True +``` + +- 今日が祝日かどうかを確認: + +```python +from datetime import date + +# 今日が祝日かどうかを確認 +today_is_holiday = holiday.is_holiday(date=date.today()) +print(today_is_holiday) + +>> False ``` -For more usage check the unit test holiday_jp/test.py +これらの例を使用することで、`holiday_jp` ライブラリを柔軟かつ効果的に利用することができます。ライブラリのドキュメントも参照して、さらに詳細な情報を得ることができます。 + +## 貢献 + +バグ報告や新機能の提案は、GitHubのイシュートラッカーを使用してください。また、プルリクエストも歓迎しています。詳細については、CONTRIBUTING.md ファイルを参照してください。 + +## ライセンス + +このプロジェクトは MIT License ライセンスの下で公開されています。詳細については、[LICENSE](https://github.com/holiday-jp/holiday_jp-python/blob/master/LICENSE) ファイルを参照してください。 + + +## 代替 + +`holiday_jp` と [jpholiday](https://github.com/Lalcs/jpholiday) の比較 + + +1. データの正確性とアップデート + + holiday_jp-python: 日本の祝日データは、holiday-jp から抽出され、更新が頻繁に行われています。GitHub リポジトリは、最新のデータと連携しています。 holiday_jp-python は、holiday-jp/holiday_jp リポジトリのメンテナンスおよびコミュニティによってサポートされています。 + + jpholiday: jpholiday は、祝日API からデータを取得しています。ライブラリのメンテナンスとデータのアップデートは、APIの提供者に依存しています。 + +2. インターフェースと使用方法 + + holiday_jp-python: holiday_jp ライブラリは、シンプルで直感的なAPIを提供し、特定の年や月の祝日情報を取得する際に柔軟性があります。 + + jpholiday: jpholiday も使いやすいライブラリであり、jpholidayモジュールから祝日情報を取得することができます。ただし、一部の機能やオプションが異なる場合があります。 + +3. カスタマイズオプション + + holiday_jp-python: holiday_jp は、特定の日が振替休日かどうかや国民の休日かどうかを確認するための専用の関数を提供しており、柔軟なオプションを利用できます。 + + jpholiday: jpholiday も同様の機能を提供していますが、それぞれのライブラリで提供されているオプションには若干の違いがあります。 + +## まとめ + +どちらのライブラリも、日本の祝日情報を取得するために便利で使いやすいものであり、プロジェクトの要件や好みによって選択できます。holiday_jp-python は、holiday-jp/holiday_jp リポジトリの共通データセットをベースにしており、コミュニティによってメンテナンスされています。両方のドキュメントを参照し、使用例を確認した上で、プロジェクトに最適なものを選択することをお勧めします。 + + + +ありがとうございます。楽しんで使っていただけることを願っています! diff --git a/holiday_jp/holiday_jp.py b/holiday_jp/holiday_jp.py index c7594bf..17fd5e5 100644 --- a/holiday_jp/holiday_jp.py +++ b/holiday_jp/holiday_jp.py @@ -6,29 +6,43 @@ class HolidayJp(object): """Holiday in Japan.""" - date_obj = '' # the date object + date_obj = None # the date object week = '' # the week day in jp ex: 木 week_en = '' # the week day in en ex: Thursday name = '' # the name of the holiday in jp ex: 元日 name_en = '' # the name of the holiday in en ex: New Year's Day - is_holiday = False # if the day is a holiday day + is_holiday = False # if the day is a national holiday + is_substitute_holiday = False # if the day is a substitute holiday is_business_day = False # if the day is from [monday, friday] - # defaul business day can be overwritten depends on context - BUSINESS_DAY = ['月', '火', '水', '木', '金'] + # default business days Monday is 0 and Sunday is 6 + BUSINESS_DAY = [i for i in range(0, 5)] HOLIDAY_DATASET = HolidayDataset.HOLIDAYS DATASET_FORMAT = '%Y-%m-%d' DATE_FORMAT = '%Y-%m-%d' - def __init__(self, date): - """init the date and fill the property. - - date: string with the following format yyyy-mm-dd (default, overwrite DATE_FORMAT for other format) - or date object + def __init__(self, date) -> None: + """Initialize a HolidayJp instance. + + Parameters: + date (str or datetime.date): The date to initialize the instance for. + If a string, must be in the format defined in the DATE_FORMAT constante (default 'YYYY-MM-DD'). + + Sets the following instance attributes based on the given date: + - date_obj: The parsed date object. + - is_holiday: Whether the date is a national holiday. + - week: The weekday in Japanese. + - week_en: The weekday in English. + - name: The holiday name in Japanese (if a holiday). + - name_en: The holiday name in English (if a holiday). + - is_business_day: Whether the date is a business day. + - is_substitute_holiday: Whether the date is a substitute holiday. """ self.date_obj = self._format_date(date) + if self.date_obj.weekday() in self.BUSINESS_DAY: + self.is_business_day = True date_str = self.date_obj.strftime(self.DATE_FORMAT) if self.HOLIDAY_DATASET.get(date_str): @@ -38,18 +52,25 @@ def __init__(self, date): self.week_en = self.HOLIDAY_DATASET[date_str]['week_en'] self.name = self.HOLIDAY_DATASET[date_str]['name'] self.name_en = self.HOLIDAY_DATASET[date_str]['name_en'] - if self.week in self.BUSINESS_DAY: - self.is_business_day = True - else: - # Monday is 0 and Sunday is 6. - if self.date_obj.weekday() < 5: - self.is_business_day = True + self.is_substitute_holiday = self._check_substitute() @classmethod - def _format_date(cls, date): - """Format the date to date object.""" + def _format_date(cls, date) -> datetime.date: + """Format a date string or date object to a date object. + + Parameters: + date (str or datetime.date): The date to format. + If a string, must match the DATE_FORMAT class constant. + + Returns: + datetime.date: The formatted date object. + + Raises: + Exception: If the date string does not match the expected format. + """ import unicodedata - date_obj = None + date_obj = date + # if date is string support the following format otherwise must be a date or datetime object if isinstance(date, str): # normalize @@ -61,17 +82,28 @@ def _format_date(cls, date): date_obj = datetime.datetime.strptime(date, cls.DATE_FORMAT).date() except Exception as e: raise e - else: - date_obj = date return date_obj @classmethod - def between(cls, start, last): - """Return a tuple of HolidayJp objects between 2 dates. + def between(cls, start, last) -> list: + """Returns a list of HolidayJp objects between the given start and end dates. - start, last: string with the following format yyyy-mm-dd - or date object + The start and end dates can be strings in the format 'yyyy-mm-dd' or + datetime.date objects. + + Iterates day-by-day from start to end date and creates a HolidayJp object + for each date that exists in the holiday dataset. + + Parameters: + start: The start date, either as string or datetime.date + end: The end date, either as string or datetime.date + + Returns: + A list of HolidayJp objects between the start and end dates inclusive. + + Raises: + ValueError if end date is before start date. """ start = cls._format_date(start) last = cls._format_date(last) @@ -97,14 +129,46 @@ def between(cls, start, last): return result @classmethod - def year_holidays(cls, year): - """Return a list of HolidayJp for a given year.""" + def year_holidays(cls, year) -> list: + """Returns a list of HolidayJp objects for the given year. + + Iterates day-by-day from Jan 1 to Dec 31 of the given year, and creates a + HolidayJp object for each date that exists in the holiday dataset. + + Parameters: + year (int): The year to get holidays for + + Returns: + list: A list of HolidayJp objects representing the holidays in the given year. + """ return cls.between('%s-01-01' % year, '%s-12-31' % year) @classmethod - def month_holidays(cls, year, month): - """Return a list of HolidayJp for a given month year.""" + def month_holidays(cls, year, month) -> list: + """Returns a list of HolidayJp objects for the given month and year. + + Iterates day-by-day from the 1st to the last day of the given month and year, + and creates a HolidayJp object for each date that exists in the holiday dataset. + + Parameters: + year (int): The year to get holidays for + month (int): The month to get holidays for, 1-12 + + Returns: + list: A list of HolidayJp objects representing the holidays in the given month and year. + """ import calendar # get the last day of the month last_day = calendar.monthrange(year, month) return cls.between('%s-%s-01' % (year, month), '%s-%s-%s' % (year, month, last_day[1])) + + def _check_substitute(self) -> bool: + """Check if the given date is a substitute holiday in Japan. + + A substitute holiday is when a national holiday falls on a Sunday, + so the following Monday is also a holiday. + + Returns: + bool: True if the date is a substitute holiday, False otherwise. + """ + return self.is_holiday and '振替休日' in self.name \ No newline at end of file diff --git a/holiday_jp/test.py b/holiday_jp/test.py index 2319e49..698d2b1 100644 --- a/holiday_jp/test.py +++ b/holiday_jp/test.py @@ -120,3 +120,11 @@ def test_month_holidays(self): gw_holiday = HolidayJp.month_holidays(2020, 5) # only 4 days for golden week need to take day off! self.assertEqual(len(gw_holiday), 4) + + def test_check_substitute_true(self): + holiday = HolidayJp('2023-01-02') + self.assertTrue(holiday._check_substitute()) + + def test_check_substitute_false(self): + random_date = datetime.date(2023, 2, 15) + self.assertFalse(HolidayJp(random_date)._check_substitute()) diff --git a/setup.py b/setup.py index 917c148..234424f 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='holiday_jp', - version='22.10.31', + version='24.01.20', url='https://github.com/LUXEYS/holiday_jp-python', license='MIT', author='Luxeys',