Creating and loading calendars

There are two main ways to work with calendars:

  1. construct a Calendar(...) directly from holidays and nonworking weekdays

  2. load a calendar with Calendar.load(...)

Use the constructor when your application already owns the holiday data. Use load when you want packaged calendars or a JSON file.

Calendars that come with the package

The package ships with these calendar names:

  • ANBIMA

  • B3

  • Actual

[1]:
from bizdays import Calendar, list_calendars

{name: Calendar.load(name=name).name for name in ["ANBIMA", "B3", "Actual"]}
[1]:
{'ANBIMA': 'ANBIMA', 'B3': 'B3', 'Actual': 'Actual'}
[2]:
list_calendars()
[2]:
{'packaged': ['ANBIMA', 'B3', 'Actual'],
 'pandas_market_calendars': {'available': True,
  'prefix': 'PMC/',
  'calendars': ['ASX',
   'BMF',
   'B3',
   'BSE',
   'NSE',
   'XNSE',
   'CFE',
   'CBOE_Futures',
   'CBOE_Equity_Options',
   'CBOE_Index_Options',
   'CME_Equity',
   'CBOT_Equity',
   'CME_Agriculture',
   'CBOT_Agriculture',
   'COMEX_Agriculture',
   'NYMEX_Agriculture',
   'CME_Rate',
   'CBOT_Rate',
   'CME_InterestRate',
   'CBOT_InterestRate',
   'CME_Bond',
   'CBOT_Bond',
   'CMEGlobex_Livestock',
   'CMEGlobex_Live_Cattle',
   'CMEGlobex_Feeder_Cattle',
   'CMEGlobex_Lean_Hog',
   'CMEGlobex_Port_Cutout',
   'CMEGlobex_Grains',
   'CMEGlobex_Oilseeds',
   'CME Globex Cryptocurrencies',
   'CME Globex Crypto',
   'CMEGlobex_EnergyAndMetals',
   'CMEGlobex_Energy',
   'CMEGlobex_CrudeAndRefined',
   'CMEGlobex_NYHarbor',
   'CMEGlobex_HO',
   'HO',
   'CMEGlobex_Crude',
   'CMEGlobex_CL',
   'CL',
   'CMEGlobex_Gas',
   'CMEGlobex_RB',
   'RB',
   'CMEGlobex_MicroCrude',
   'CMEGlobex_MCL',
   'MCL',
   'CMEGlobex_NatGas',
   'CMEGlobex_NG',
   'NG',
   'CMEGlobex_Dutch_NatGas',
   'CMEGlobex_TTF',
   'TTF',
   'CMEGlobex_LastDay_NatGas',
   'CMEGlobex_NN',
   'NN',
   'CMEGlobex_CarbonOffset',
   'CMEGlobex_CGO',
   'CGO',
   'C-GEO',
   'CMEGlobex_NGO',
   'NGO',
   'CMEGlobex_GEO',
   'GEO',
   'CMEGlobex_Metals',
   'CMEGlobex_PreciousMetals',
   'CMEGlobex_Gold',
   'CMEGlobex_GC',
   'GC',
   'CMEGlobex_Silver',
   'CMEGlobex_SI',
   'SI',
   'CMEGlobex_Platinum',
   'CMEGlobex_PL',
   'PL',
   'CMEGlobex_BaseMetals',
   'CMEGlobex_Copper',
   'CMEGlobex_HG',
   'HG',
   'CMEGlobex_Aluminum',
   'CMEGlobex_ALI',
   'ALI',
   'CMEGlobex_QC',
   'QC',
   'CMEGlobex_FerrousMetals',
   'CMEGlobex_HRC',
   'HRC',
   'CMEGlobex_BUS',
   'BUS',
   'CMEGlobex_TIO',
   'TIO',
   'CME Globex Equity',
   'CMEGlobex_FX',
   'CME_FX',
   'CME_Currency',
   'CME Globex Fixed Income',
   'CME Globex Interest Rate Products',
   'EUREX',
   'EUREX_Bond',
   'HKEX',
   'ICE',
   'ICEUS',
   'NYFE',
   'NYSE',
   'stock',
   'NASDAQ',
   'BATS',
   'DJIA',
   'DOW',
   'IEX',
   'Investors_Exchange',
   'JPX',
   'XJPX',
   'LSE',
   'OSE',
   'SIFMAUS',
   'SIFMA_US',
   'Capital_Markets_US',
   'Financial_Markets_US',
   'Bond_Markets_US',
   'SIFMAUK',
   'SIFMA_UK',
   'Capital_Markets_UK',
   'Financial_Markets_UK',
   'Bond_Markets_UK',
   'SIFMAJP',
   'SIFMA_JP',
   'Capital_Markets_JP',
   'Financial_Markets_JP',
   'Bond_Markets_JP',
   'SIX',
   'SSE',
   'TASE',
   'TSX',
   'TSXV',
   'AIXK',
   'ASEX',
   'BVMF',
   'XCYS',
   'CMES',
   'IEPA',
   'XAMS',
   'XASX',
   'XBEL',
   'XBDA',
   'XBKK',
   'XBOG',
   'XBOM',
   'XBRU',
   'XBSE',
   'XBUD',
   'XBUE',
   'XBRA',
   'XCBF',
   'XCSE',
   'XDUB',
   'XDUS',
   'XEEE',
   'XFRA',
   'XETR',
   'XHAM',
   'XHEL',
   'XHKG',
   'XICE',
   'XIDX',
   'XIST',
   'XJSE',
   'XKAR',
   'XKLS',
   'XKRX',
   'XLIM',
   'XLIS',
   'XLIT',
   'XLJU',
   'XLON',
   'XLUX',
   'XMAD',
   'XMEX',
   'XMIL',
   'XMOS',
   'XNYS',
   'XNZE',
   'XOSL',
   'XPAR',
   'XPHS',
   'XPRA',
   'XRIS',
   'XSAU',
   'XSES',
   'XSGO',
   'XSHG',
   'XSTO',
   'XSWX',
   'XTAE',
   'XTAI',
   'XTAL',
   'XTKS',
   'XTSE',
   'XWAR',
   'XWBO',
   'XZAG',
   'us_futures',
   '24/7',
   '24/5']},
 'exchange_calendars': {'available': True,
  'prefix': 'XCAL/',
  'calendars': ['24/5',
   '24/7',
   'AIXK',
   'ARCX',
   'ASEX',
   'ASX',
   'BATS',
   'BMF',
   'BSE',
   'BVB',
   'BVMF',
   'CBOT',
   'CFE',
   'CME',
   'CMES',
   'COMEX',
   'FWB',
   'HKEX',
   'ICE',
   'ICEUS',
   'IEPA',
   'JKT',
   'JPX',
   'LSE',
   'LUXSE',
   'NASDAQ',
   'NYFE',
   'NYMEX',
   'NYSE',
   'OOTC',
   'OSE',
   'SIX',
   'SSE',
   'TASE',
   'TSX',
   'XAMS',
   'XASE',
   'XASX',
   'XBDA',
   'XBEL',
   'XBKK',
   'XBOG',
   'XBOM',
   'XBRA',
   'XBRU',
   'XBSE',
   'XBUD',
   'XBUE',
   'XCBF',
   'XCSE',
   'XCYS',
   'XDUB',
   'XDUS',
   'XEEE',
   'XETR',
   'XFRA',
   'XHAM',
   'XHEL',
   'XHKG',
   'XICE',
   'XIDX',
   'XIST',
   'XJSE',
   'XKAR',
   'XKLS',
   'XKRX',
   'XLIM',
   'XLIS',
   'XLIT',
   'XLJU',
   'XLON',
   'XLUX',
   'XMAD',
   'XMEX',
   'XMIL',
   'XMOS',
   'XNAS',
   'XNYS',
   'XNZE',
   'XOSL',
   'XPAR',
   'XPHS',
   'XPRA',
   'XRIS',
   'XSAU',
   'XSES',
   'XSGO',
   'XSHG',
   'XSTO',
   'XSWX',
   'XTAE',
   'XTAI',
   'XTAL',
   'XTKS',
   'XTSE',
   'XTSX',
   'XWAR',
   'XWBO',
   'XZAG',
   'us_futures']},
 'workalendar': {'available': True,
  'prefix': 'WORK/',
  'calendars': ['AT',
   'BY',
   'BE',
   'BG',
   'KY',
   'HR',
   'CY',
   'CZ',
   'DK',
   'EE',
   'FI',
   'FR',
   'GE',
   'GR',
   'GG',
   'HU',
   'IS',
   'IE',
   'IT',
   'LV',
   'LT',
   'LU',
   'MT',
   'MC',
   'NL',
   'NO',
   'PL',
   'PT',
   'RO',
   'RU',
   'RS',
   'SK',
   'SI',
   'SE',
   'CH',
   'UA',
   'GB',
   'GB-NIR',
   'TR',
   'DE',
   'DE-BW',
   'DE-BY',
   'DE-BE',
   'DE-BB',
   'DE-HB',
   'DE-HH',
   'DE-HE',
   'DE-MV',
   'DE-NI',
   'DE-NW',
   'DE-RP',
   'DE-SL',
   'DE-SN',
   'DE-ST',
   'DE-SH',
   'DE-TH',
   'ES',
   'ES-AN',
   'ES-AR',
   'ES-CT',
   'ES-CL',
   'ES-CM',
   'ES-CN',
   'ES-EX',
   'ES-GA',
   'ES-IB',
   'ES-RI',
   'ES-MD',
   'ES-MC',
   'ES-NA',
   'ES-AS',
   'ES-PV',
   'ES-CB',
   'ES-VC',
   'CH-AG',
   'CH-AI',
   'CH-AR',
   'CH-BE',
   'CH-BL',
   'CH-BS',
   'CH-FR',
   'CH-GE',
   'CH-GL',
   'CH-GR',
   'CH-JU',
   'CH-LU',
   'CH-NE',
   'CH-NW',
   'CH-OW',
   'CH-SG',
   'CH-SH',
   'CH-SO',
   'CH-SZ',
   'CH-TG',
   'CH-TI',
   'CH-UR',
   'CH-VD',
   'CH-VS',
   'CH-ZG',
   'CH-ZH',
   'US',
   'US-AL',
   'US-AK',
   'US-AZ',
   'US-AR',
   'US-CA',
   'US-CO',
   'US-CT',
   'US-DE',
   'US-DC',
   'US-FL',
   'US-GA',
   'US-HI',
   'US-ID',
   'US-IL',
   'US-IN',
   'US-IA',
   'US-KS',
   'US-KY',
   'US-LA',
   'US-ME',
   'US-MD',
   'US-MA',
   'US-MI',
   'US-MN',
   'US-MS',
   'US-MO',
   'US-MT',
   'US-NE',
   'US-NV',
   'US-NH',
   'US-NJ',
   'US-NM',
   'US-NY',
   'US-NC',
   'US-ND',
   'US-OH',
   'US-OK',
   'US-OR',
   'US-PA',
   'US-RI',
   'US-SC',
   'US-SD',
   'US-TN',
   'US-TX',
   'US-UT',
   'US-VT',
   'US-VA',
   'US-WA',
   'US-WV',
   'US-WI',
   'US-WY',
   'US-AS',
   'US-GU',
   'BR',
   'BR-AC',
   'BR-AL',
   'BR-AP',
   'BR-AM',
   'BR-BA',
   'BR-CE',
   'BR-DF',
   'BR-ES',
   'BR-GO',
   'BR-MA',
   'BR-MG',
   'BR-MT',
   'BR-MS',
   'BR-PA',
   'BR-PB',
   'BR-PE',
   'BR-PI',
   'BR-PR',
   'BR-RJ',
   'BR-RN',
   'BR-RS',
   'BR-RO',
   'BR-RR',
   'BR-SC',
   'BR-SP',
   'BR-SE',
   'BR-TO',
   'CA',
   'CA-ON',
   'CA-QC',
   'CA-BC',
   'CA-AB',
   'CA-SK',
   'CA-MB',
   'CA-NB',
   'CA-NS',
   'CA-PE',
   'CA-NL',
   'CA-YT',
   'CA-NT',
   'CA-NU',
   'BB',
   'CL',
   'CO',
   'MX',
   'PA',
   'PY',
   'AR',
   'SV',
   'DZ',
   'BJ',
   'CI',
   'KE',
   'MG',
   'ST',
   'ZA',
   'AO',
   'MZ',
   'NG',
   'TN',
   'CN',
   'HK',
   'JP',
   'MY',
   'QA',
   'SG',
   'KR',
   'TW',
   'IL',
   'PH',
   'KZ',
   'AU',
   'AU-ACT',
   'AU-NSW',
   'AU-NT',
   'AU-QLD',
   'AU-SA',
   'AU-TAS',
   'AU-VIC',
   'AU-WA',
   'MH',
   'NZ']}}

list_calendars() is the programmatic discovery helper for calendar sources.

It returns a dictionary with:

  • packaged: the curated calendars shipped with bizdays

  • pandas_market_calendars: metadata about the optional PMC integration

  • exchange_calendars: metadata about the optional exchange calendar integration

  • workalendar: metadata about the optional workalendar integration

Each integration entry contains:

  • available: whether the optional dependency is installed

  • prefix: the prefix used with Calendar.load(name="<prefix><calendar>")

  • calendars: the discovered calendar names when available, otherwise an empty list

[3]:
info = list_calendars()
{
    "packaged": info["packaged"],
    "pmc_available": info["pandas_market_calendars"]["available"],
    "pmc_prefix": info["pandas_market_calendars"]["prefix"],
    "xcal_available": info["exchange_calendars"]["available"],
    "xcal_prefix": info["exchange_calendars"]["prefix"],
    "work_available": info["workalendar"]["available"],
    "work_prefix": info["workalendar"]["prefix"],
}
[3]:
{'packaged': ['ANBIMA', 'B3', 'Actual'],
 'pmc_available': True,
 'pmc_prefix': 'PMC/',
 'xcal_available': True,
 'xcal_prefix': 'XCAL/',
 'work_available': True,
 'work_prefix': 'WORK/'}

Actual is the simplest packaged calendar: it has no holidays and no nonworking weekdays, so every day is a business day.

[4]:
actual = Calendar.load(name="Actual")
actual.isbizday(["2024-01-01", "2024-01-06", "2024-01-07"])
[4]:
masked_array(data=[True, True, True],
             mask=[False, False, False],
       fill_value=False)

Creating a calendar from scratch with Calendar(...)

The constructor accepts:

  • holidays: ISO date strings or date-like objects

  • weekdays: names of nonworking weekdays

  • startdate and enddate: optional calendar bounds

  • name: a display name

  • financial: whether to use financial counting rules

[5]:
custom = Calendar(
    holidays=["2024-01-01", "2024-04-21", "2024-12-25"],
    weekdays=["Saturday", "Sunday"],
    startdate="2024-01-01",
    enddate="2024-12-31",
    name="Example",
    financial=True,
)
custom
[5]:
Calendar: Example
Start: 2024-01-01
End: 2024-12-31
Weekdays: Saturday, Sunday
Holidays: 3
Financial: True
[6]:
{
    "name": custom.name,
    "weekdays": custom.weekdays,
    "startdate": str(custom.startdate),
    "enddate": str(custom.enddate),
    "holidays": [str(day) for day in custom.holidays],
}
[6]:
{'name': 'Example',
 'weekdays': ('Saturday', 'Sunday'),
 'startdate': '2024-01-01',
 'enddate': '2024-12-31',
 'holidays': ['2024-01-01', '2024-04-21', '2024-12-25']}

If you omit startdate and enddate, they are inferred from the holiday range. If you construct a calendar without holidays, a broad default range is used.

[7]:
weekends_only = Calendar(
    weekdays=["Saturday", "Sunday"],
    name="WeekendsOnly",
)
{
    "startdate": str(weekends_only.startdate),
    "enddate": str(weekends_only.enddate),
    "isbizday": weekends_only.isbizday(["2024-01-05", "2024-01-06", "2024-01-07"]),
}
[7]:
{'startdate': '1970-01-01',
 'enddate': '2071-01-01',
 'isbizday': masked_array(data=[True, False, False],
              mask=[False, False, False],
        fill_value=False)}

JSON calendar layout

Calendar.load(filename=...) expects a JSON object with this layout:

  • name: string

  • weekdays: list of strings

  • holidays: list of ISO date strings

  • financial: boolean

  • start.date and end.date: optional ISO date strings (YYYY-MM-DD) that set startdate and enddate; a bad value raises ValueError

  • adjust.from and adjust.to: optional; only the defaults "following" and "preceding" are accepted, and other values raise ValueError

[8]:
payload = {
    "name": "CustomJson",
    "weekdays": ["saturday", "sunday"],
    "holidays": ["2024-01-01", "2024-04-21", "2024-12-25"],
    "financial": True,
    "adjust.from": "following",
    "adjust.to": "preceding",
}
payload
[8]:
{'name': 'CustomJson',
 'weekdays': ['saturday', 'sunday'],
 'holidays': ['2024-01-01', '2024-04-21', '2024-12-25'],
 'financial': True,
 'adjust.from': 'following',
 'adjust.to': 'preceding'}
[9]:
import json
import tempfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmpdir:
    filename = Path(tmpdir) / "custom-calendar.json"
    filename.write_text(json.dumps(payload), encoding="utf-8")
    json_calendar = Calendar.load(filename=str(filename))

json_calendar
[9]:
Calendar: CustomJson
Start: 2024-01-01
End: 2024-12-25
Weekdays: Saturday, Sunday
Holidays: 3
Financial: True

Optional calendar provider integrations

If you install the optional bizdays[pmc] extra, Calendar.load(name="PMC/<calendar>") can load calendars from pandas_market_calendars.

If you install the optional bizdays[xcal] extra, Calendar.load(name="XCAL/<calendar>") can load calendars from exchange_calendars.

If you install the optional bizdays[work] extra, Calendar.load(name="WORK/<code>") can load calendars from workalendar.

These are not packaged calendars; they come from optional integrations.

[10]:
{
    "pmc": Calendar.load(name="PMC/B3").name,
    "xcal": Calendar.load(name="XCAL/XNYS").name,
    "work": Calendar.load(name="WORK/FR").name,
}
[10]:
{'pmc': 'PMC/B3', 'xcal': 'XCAL/XNYS', 'work': 'WORK/FR'}