438 lines
15 KiB
Python
438 lines
15 KiB
Python
# holidays
|
|
# --------
|
|
# A fast, efficient Python library for generating country, province and state
|
|
# specific sets of holidays on the fly. It aims to make determining whether a
|
|
# specific date is a holiday as fast and flexible as possible.
|
|
#
|
|
# Authors: Vacanza Team and individual contributors (see CONTRIBUTORS file)
|
|
# dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
|
|
# ryanss <ryanssdev@icloud.com> (c) 2014-2017
|
|
# Website: https://github.com/vacanza/holidays
|
|
# License: MIT (see LICENSE file)
|
|
|
|
__all__ = (
|
|
"country_holidays",
|
|
"CountryHoliday",
|
|
"financial_holidays",
|
|
"list_localized_countries",
|
|
"list_localized_financial",
|
|
"list_supported_countries",
|
|
"list_supported_financial",
|
|
)
|
|
|
|
import warnings
|
|
from collections.abc import Iterable
|
|
from functools import lru_cache
|
|
from typing import Optional, Union
|
|
|
|
from holidays.holiday_base import CategoryArg, HolidayBase
|
|
from holidays.registry import EntityLoader
|
|
|
|
|
|
def country_holidays(
|
|
country: str,
|
|
subdiv: Optional[str] = None,
|
|
years: Optional[Union[int, Iterable[int]]] = None,
|
|
expand: bool = True,
|
|
observed: bool = True,
|
|
prov: Optional[str] = None,
|
|
state: Optional[str] = None,
|
|
language: Optional[str] = None,
|
|
categories: Optional[CategoryArg] = None,
|
|
) -> HolidayBase:
|
|
"""
|
|
Returns a new dictionary-like `HolidayBase` object for the public
|
|
holidays of the country matching **country** and other keyword arguments.
|
|
|
|
Args:
|
|
country:
|
|
An ISO 3166-1 Alpha-2 country code.
|
|
|
|
subdiv:
|
|
The subdivision (e.g. state or province) as a ISO 3166-2 code
|
|
or its alias; not implemented for all countries (see documentation).
|
|
|
|
years:
|
|
The year(s) to pre-calculate public holidays for at instantiation.
|
|
|
|
expand:
|
|
Whether the entire year is calculated when one date from that year
|
|
is requested.
|
|
|
|
observed:
|
|
Whether to include the dates of when public holiday are observed
|
|
(e.g. a holiday falling on a Sunday being observed the following
|
|
Monday). False may not work for all countries.
|
|
|
|
prov:
|
|
*deprecated* use `subdiv` instead.
|
|
|
|
state:
|
|
*deprecated* use `subdiv` instead.
|
|
|
|
language:
|
|
Specifies the language in which holiday names are returned.
|
|
|
|
Accepts either:
|
|
|
|
* A two-letter ISO 639-1 language code (e.g., 'en' for English, 'fr' for French),
|
|
or
|
|
* A language and entity combination using an underscore (e.g., 'en_US' for U.S.
|
|
English, 'pt_BR' for Brazilian Portuguese).
|
|
|
|
!!! warning
|
|
The provided language or locale code must be supported by the holiday
|
|
entity. Unsupported values will result in names being shown in the entity's
|
|
original language.
|
|
|
|
If not explicitly set (`language=None`), the system attempts to infer the
|
|
language from the environment's locale settings. The following environment
|
|
variables are checked, in order of precedence: LANGUAGE, LC_ALL, LC_MESSAGES, LANG.
|
|
|
|
If none of these are set or they are empty, holiday names will default to the
|
|
original language of the entity's holiday implementation.
|
|
|
|
!!! warning
|
|
This fallback mechanism may yield inconsistent results across environments
|
|
(e.g., between a terminal session and a Jupyter notebook).
|
|
|
|
To ensure consistent behavior, it is recommended to set the language parameter
|
|
explicitly. If the specified language is not supported, holiday names will remain
|
|
in the original language of the entity's holiday implementation.
|
|
|
|
This behavior will be updated and formalized in v1.
|
|
|
|
categories:
|
|
Requested holiday categories.
|
|
|
|
Returns:
|
|
A `HolidayBase` object matching the **country**.
|
|
|
|
The key of the `dict`-like `HolidayBase` object is the
|
|
`date` of the holiday, and the value is the name of the holiday itself.
|
|
Dates where a key is not present are not public holidays (or, if
|
|
**observed** is False, days when a public holiday is observed).
|
|
|
|
When passing the `date` as a key, the `date` can be expressed in one of the
|
|
following types:
|
|
|
|
* `datetime.date`,
|
|
* `datetime.datetime`,
|
|
* a `str` of any format recognized by `dateutil.parser.parse()`,
|
|
* or a `float` or `int` representing a POSIX timestamp.
|
|
|
|
The key is always returned as a `datetime.date` object.
|
|
|
|
To maximize speed, the list of public holidays is built on the fly as
|
|
needed, one calendar year at a time. When the object is instantiated
|
|
without a **years** parameter, it is empty, but, unless **expand** is set
|
|
to False, as soon as a key is accessed the class will calculate that entire
|
|
year's list of holidays and set the keys with them.
|
|
|
|
If you need to list the holidays as opposed to querying individual dates,
|
|
instantiate the class with the **years** parameter.
|
|
|
|
Example usage:
|
|
|
|
>>> from holidays import country_holidays
|
|
>>> us_holidays = country_holidays('US')
|
|
# For a specific subdivision (e.g. state or province):
|
|
>>> calif_holidays = country_holidays('US', subdiv='CA')
|
|
|
|
The below will cause 2015 holidays to be calculated on the fly:
|
|
|
|
>>> from datetime import date
|
|
>>> assert date(2015, 1, 1) in us_holidays
|
|
|
|
This will be faster because 2015 holidays are already calculated:
|
|
|
|
>>> assert date(2015, 1, 2) not in us_holidays
|
|
|
|
The `HolidayBase` class also recognizes strings of many formats
|
|
and numbers representing a POSIX timestamp:
|
|
|
|
>>> assert '2014-01-01' in us_holidays
|
|
>>> assert '1/1/2014' in us_holidays
|
|
>>> assert 1388597445 in us_holidays
|
|
|
|
Show the holiday's name:
|
|
|
|
>>> us_holidays.get('2014-01-01')
|
|
"New Year's Day"
|
|
|
|
Check a range:
|
|
|
|
>>> us_holidays['2014-01-01': '2014-01-03']
|
|
[datetime.date(2014, 1, 1)]
|
|
|
|
List all 2020 holidays:
|
|
|
|
>>> us_holidays = country_holidays('US', years=2020)
|
|
>>> for day in sorted(us_holidays.items()):
|
|
... print(day)
|
|
(datetime.date(2020, 1, 1), "New Year's Day")
|
|
(datetime.date(2020, 1, 20), 'Martin Luther King Jr. Day')
|
|
(datetime.date(2020, 2, 17), "Washington's Birthday")
|
|
(datetime.date(2020, 5, 25), 'Memorial Day')
|
|
(datetime.date(2020, 7, 3), 'Independence Day (observed)')
|
|
(datetime.date(2020, 7, 4), 'Independence Day')
|
|
(datetime.date(2020, 9, 7), 'Labor Day')
|
|
(datetime.date(2020, 10, 12), 'Columbus Day')
|
|
(datetime.date(2020, 11, 11), 'Veterans Day')
|
|
(datetime.date(2020, 11, 26), 'Thanksgiving Day')
|
|
(datetime.date(2020, 12, 25), 'Christmas Day')
|
|
|
|
Some holidays are only present in parts of a country:
|
|
|
|
>>> us_pr_holidays = country_holidays('US', subdiv='PR')
|
|
>>> assert '2018-01-06' not in us_holidays
|
|
>>> assert '2018-01-06' in us_pr_holidays
|
|
|
|
Append custom holiday dates by passing one of:
|
|
|
|
* a `dict` with date/name key/value pairs (e.g.
|
|
`{'2010-07-10': 'My birthday!'}`),
|
|
* a list of dates (as a `datetime.date`, `datetime.datetime`,
|
|
`str`, `int`, or `float`); "Holiday" will be used as a description,
|
|
* or a single date item (of one of the types above); "Holiday" will be
|
|
used as a description:
|
|
|
|
```python
|
|
>>> custom_holidays = country_holidays('US', years=2015)
|
|
>>> custom_holidays.update({'2015-01-01': "New Year's Day"})
|
|
>>> custom_holidays.update(['2015-07-01', '07/04/2015'])
|
|
>>> custom_holidays.update(date(2015, 12, 25))
|
|
>>> assert date(2015, 1, 1) in custom_holidays
|
|
>>> assert date(2015, 1, 2) not in custom_holidays
|
|
>>> assert '12/25/2015' in custom_holidays
|
|
```
|
|
|
|
For more complex logic, like 4th Monday of January, you can inherit the
|
|
`HolidayBase` class and define your own `_populate` method.
|
|
See documentation for examples.
|
|
"""
|
|
import holidays
|
|
|
|
try:
|
|
return getattr(holidays, country)(
|
|
years=years,
|
|
subdiv=subdiv,
|
|
expand=expand,
|
|
observed=observed,
|
|
prov=prov,
|
|
state=state,
|
|
language=language,
|
|
categories=categories,
|
|
)
|
|
except AttributeError:
|
|
raise NotImplementedError(f"Country {country} not available")
|
|
|
|
|
|
def financial_holidays(
|
|
market: str,
|
|
subdiv: Optional[str] = None,
|
|
years: Optional[Union[int, Iterable[int]]] = None,
|
|
expand: bool = True,
|
|
observed: bool = True,
|
|
language: Optional[str] = None,
|
|
) -> HolidayBase:
|
|
"""
|
|
Returns a new dictionary-like :py:class:`HolidayBase` object for the public
|
|
holidays of the financial market matching **market** and other keyword
|
|
arguments.
|
|
|
|
Args:
|
|
market:
|
|
An ISO 3166-1 Alpha-2 market code.
|
|
|
|
subdiv:
|
|
Currently not implemented for markets (see documentation).
|
|
|
|
years:
|
|
The year(s) to pre-calculate public holidays for at instantiation.
|
|
|
|
expand:
|
|
Whether the entire year is calculated when one date from that year
|
|
is requested.
|
|
|
|
observed:
|
|
Whether to include the dates of when public holiday are observed
|
|
(e.g. a holiday falling on a Sunday being observed the following
|
|
Monday). False may not work for all countries.
|
|
|
|
language:
|
|
Specifies the language in which holiday names are returned.
|
|
|
|
Accepts either:
|
|
|
|
* A two-letter ISO 639-1 language code (e.g., 'en' for English, 'fr' for French),
|
|
or
|
|
* A language and entity combination using an underscore (e.g., 'en_US' for U.S.
|
|
English, 'pt_BR' for Brazilian Portuguese).
|
|
|
|
!!! warning
|
|
The provided language or locale code must be supported by the holiday
|
|
entity. Unsupported values will result in names being shown in the entity's
|
|
original language.
|
|
|
|
If not explicitly set (`language=None`), the system attempts to infer the
|
|
language from the environment's locale settings. The following environment
|
|
variables are checked, in order of precedence: LANGUAGE, LC_ALL, LC_MESSAGES, LANG.
|
|
|
|
If none of these are set or they are empty, holiday names will default to the
|
|
original language of the entity's holiday implementation.
|
|
|
|
!!! warning
|
|
This fallback mechanism may yield inconsistent results across environments
|
|
(e.g., between a terminal session and a Jupyter notebook).
|
|
|
|
To ensure consistent behavior, it is recommended to set the language parameter
|
|
explicitly. If the specified language is not supported, holiday names will remain
|
|
in the original language of the entity's holiday implementation.
|
|
|
|
This behavior will be updated and formalized in v1.
|
|
|
|
Returns:
|
|
A `HolidayBase` object matching the **market**.
|
|
|
|
Example usage:
|
|
|
|
>>> from holidays import financial_holidays
|
|
>>> nyse_holidays = financial_holidays('XNYS')
|
|
|
|
See [country_holidays()][holidays.utils.country_holidays] documentation for further
|
|
details and examples.
|
|
"""
|
|
import holidays
|
|
|
|
try:
|
|
return getattr(holidays, market)(
|
|
years=years, subdiv=subdiv, expand=expand, observed=observed, language=language
|
|
)
|
|
except AttributeError:
|
|
raise NotImplementedError(f"Financial market {market} not available")
|
|
|
|
|
|
def CountryHoliday( # noqa: N802
|
|
country: str,
|
|
subdiv: Optional[str] = None,
|
|
years: Optional[Union[int, Iterable[int]]] = None,
|
|
expand: bool = True,
|
|
observed: bool = True,
|
|
prov: Optional[str] = None,
|
|
state: Optional[str] = None,
|
|
) -> HolidayBase:
|
|
"""
|
|
Note:
|
|
Deprecated name for `country_holidays()`.
|
|
"""
|
|
|
|
warnings.warn(
|
|
"CountryHoliday is deprecated, use country_holidays instead.", DeprecationWarning
|
|
)
|
|
return country_holidays(country, subdiv, years, expand, observed, prov, state)
|
|
|
|
|
|
def _list_localized_entities(entity_codes: Iterable[str]) -> dict[str, list[str]]:
|
|
"""Get all localized entities and languages they support.
|
|
|
|
Args:
|
|
entity_codes:
|
|
A list of entity codes.
|
|
|
|
Returns:
|
|
A dictionary where key is an entity code and value is a list of supported
|
|
languages (either ISO 639-1 or a combination of ISO 639-1 and ISO 3166-1 codes joined
|
|
with "_").
|
|
"""
|
|
import holidays
|
|
|
|
localized_countries = {}
|
|
for entity_code in entity_codes:
|
|
languages = getattr(holidays, entity_code).supported_languages
|
|
if not languages:
|
|
continue
|
|
localized_countries[entity_code] = sorted(languages)
|
|
|
|
return localized_countries
|
|
|
|
|
|
@lru_cache
|
|
def list_localized_countries(include_aliases: bool = True) -> dict[str, list[str]]:
|
|
"""Get all localized countries and languages they support.
|
|
|
|
Args:
|
|
include_aliases:
|
|
Whether to include entity aliases (e.g. UK for GB).
|
|
|
|
Returns:
|
|
A dictionary where key is an ISO 3166-1 alpha-2 country code and value is a
|
|
list of supported languages (either ISO 639-1 or a combination of ISO 639-1
|
|
and ISO 3166-1 codes joined with "_").
|
|
"""
|
|
return _list_localized_entities(EntityLoader.get_country_codes(include_aliases))
|
|
|
|
|
|
@lru_cache
|
|
def list_localized_financial(include_aliases: bool = True) -> dict[str, list[str]]:
|
|
"""Get all localized financial markets and languages they support.
|
|
|
|
Args:
|
|
include_aliases:
|
|
Whether to include entity aliases (e.g. TAR for ECB, XNYS for NYSE).
|
|
|
|
Returns:
|
|
A dictionary where key is a market code and value is a list of supported
|
|
subdivision codes.
|
|
"""
|
|
return _list_localized_entities(EntityLoader.get_financial_codes(include_aliases))
|
|
|
|
|
|
def _list_supported_entities(entity_codes: Iterable[str]) -> dict[str, list[str]]:
|
|
"""Get all supported entities and their subdivisions.
|
|
|
|
Args:
|
|
entity_codes:
|
|
A list of entity codes.
|
|
|
|
Returns:
|
|
A dictionary where key is an entity code and value is a list of supported
|
|
subdivision codes.
|
|
"""
|
|
import holidays
|
|
|
|
return {
|
|
country_code: list(getattr(holidays, country_code).subdivisions)
|
|
for country_code in entity_codes
|
|
}
|
|
|
|
|
|
@lru_cache
|
|
def list_supported_countries(include_aliases: bool = True) -> dict[str, list[str]]:
|
|
"""Get all supported countries and their subdivisions.
|
|
|
|
Args:
|
|
include_aliases:
|
|
Whether to include entity aliases (e.g. UK for GB).
|
|
|
|
Returns:
|
|
A dictionary where key is an ISO 3166-1 alpha-2 country code and value
|
|
is a list of supported subdivision codes.
|
|
"""
|
|
return _list_supported_entities(EntityLoader.get_country_codes(include_aliases))
|
|
|
|
|
|
@lru_cache
|
|
def list_supported_financial(include_aliases: bool = True) -> dict[str, list[str]]:
|
|
"""Get all supported financial markets and their subdivisions.
|
|
|
|
Args:
|
|
include_aliases:
|
|
Whether to include entity aliases (e.g. TAR for ECB, XNYS for NYSE).
|
|
|
|
Returns:
|
|
A dictionary where key is a market code and value is a list of supported
|
|
subdivision codes.
|
|
"""
|
|
return _list_supported_entities(EntityLoader.get_financial_codes(include_aliases))
|