Skip to content

Holiday Calendar (Java)

Build Quality Gate Status License: LGPL v2.1

A Java library for defining and calculating holiday calendars. Provides an extensible foundation for generating the calendars used to determine when holidays occur and when they are observed worldwide.

Upgrading from v1.4.0 or earlier? v2.0.0 introduced the EarlyCloseHoliday API, and v2.1.0 separates national holiday calendars from equities-exchange market calendars. Skip v2.0.0 and upgrade straight to v2.1.0 or later — see MIGRATION.md for the full breaking-changes guide.

Porting to another language? See docs/PORTING_GUIDE.md for the core abstractions, design patterns, and data formats needed to build a compatible implementation in JavaScript, Python, Go, or any other language.

About

Holiday Calendar answers common needs in financial, scheduling, and business applications: "Is this date a business day?" and "When is this holiday observed this year?"

Key design goals:

  • Correct date rolling — when a holiday falls on a weekend, the library applies configurable rolling rules (e.g. following Monday, previous Friday) to compute the observed date.
  • Extensible by design — new regional calendars are added via Java's ServiceLoader mechanism; no changes to core code required.
  • Modern Java — built on Java 21, using sealed interfaces, records, and the module system (JPMS).

Supported Calendars

Each region may publish up to three distinct calendars: a National calendar (public holidays only, no early closes — with one exception, noted below), a Central Bank/Settlement calendar (currency/RTGS system holidays), and a Market/Exchange calendar (a specific exchange's trading holidays, generally including half-day early closes). Not every country has all three — see the tables below. factory.create("CODE") accepts any code from any column.

Exception: TR (Turkey's national calendar) is the one national code that includes an early-close entry (Republic Day Eve), because it is a statutory closure rather than a market-only convention. The same entry is also carried by TRY.

Western (holiday-calendar-western)

Country/Region National Central Bank/Settlement Market/Exchange (MIC) Early closes?
Australia AU AUD RBA XASX ASX ✅ (XASX)
Canada CA CAD Bank of Canada (Lynx) XTSE TSX ✅ (XTSE)
France FR XPAR Euronext Paris ✅ (XPAR)
Germany DE XETR Xetra
Switzerland CH CHF SIC/SNB XSWX SIX
United Kingdom UK GBP CHAPS XLON LSE ✅ (XLON)
United States US USD Federal Reserve XNYS NYSE ✅ (XNYS)
Eurozone (multi-country) EUR TARGET2

Germany and France have no dedicated currency-code row (no separate settlement system) — the shared Eurozone/EUR row above serves that role instead of being duplicated per country.

APAC (holiday-calendar-apac)

Country/Region National Central Bank/Settlement Market/Exchange (MIC) Early closes?
China CN CNY PBOC
Japan JP JPY BOJ
Singapore SG SGD MAS/MEPS+ XSES SGX ✅ (XSES)

Japan has no dedicated exchange (MIC) calendar — JP is documented as national-only.

MENA (holiday-calendar-mena)

No Market/Exchange (MIC) calendars exist yet in this module — each country has only a National and a Currency/Exchange code, with the currency code doubling as the de facto exchange calendar where applicable (e.g. ILS for TASE, TRY for BIST).

Country National Currency/Exchange Early closes?
UAE AE AED CBUAE/DFM/ADX
Saudi Arabia SA SAR Tadawul/SAMA
Israel IL ILS TASE/Bank of Israel ✅ (ILS only, 6 entries)
Turkey TR TRY BIST/TCMB ✅ (both TR and TRY — shared Republic Day Eve entry)
Qatar QA QAR QSE/QCB
Egypt EG EGP EGX/CBE
Kuwait KW KWD Boursa Kuwait/CBK
Bahrain BH BHD Boursa Bahrain/CBB
Morocco MA MAD CSE/BAM
Jordan JO JOD ASE/CBJ

For information on adding new calendars or maintaining existing ones, see the Contributing Guide. For per-exchange early-close times, time zones, weekend-roll behavior, and primary-source citations, see the calendar reference docs.

Installation

Holiday Calendar requires Java 21 and Maven 3.5.0 or higher.

The library is published to the GitHub Packages Maven registry. Add the repository and dependency to your pom.xml:

<repositories>
  <repository>
    <id>github</id>
    <name>GitHub holiday-calendar Apache Maven Packages</name>
    <url>https://maven.pkg.github.com/holiday-calendar/holiday-calendar-java</url>
  </repository>
</repositories>

Then add the modules you need:

<!-- Core API (required) -->
<dependency>
  <groupId>org.holiday.calendar</groupId>
  <artifactId>holiday-calendar-core</artifactId>
  <version>2.2.0-SNAPSHOT</version>
</dependency>

<!-- Western calendars: US, USD, CA, CAD, UK, GBP, CH, CHF, DE, EUR, FR, AU, AUD -->
<dependency>
  <groupId>org.holiday.calendar</groupId>
  <artifactId>holiday-calendar-western</artifactId>
  <version>2.2.0-SNAPSHOT</version>
</dependency>

<!-- APAC calendars: SG, SGD, JP, JPY, CN, CNY -->
<dependency>
  <groupId>org.holiday.calendar</groupId>
  <artifactId>holiday-calendar-apac</artifactId>
  <version>2.2.0-SNAPSHOT</version>
</dependency>

<!-- MENA calendars: AE, AED, BH, BHD, EG, EGP, IL, ILS, JO, JOD, KW, KWD, MA, MAD, QA, QAR, SA, SAR, TR, TRY -->
<dependency>
  <groupId>org.holiday.calendar</groupId>
  <artifactId>holiday-calendar-mena</artifactId>
  <version>2.2.0-SNAPSHOT</version>
</dependency>

Usage

Look up a calendar and calculate holidays for a year

import org.holiday.calendar.HolidayCalendar;
import org.holiday.calendar.HolidayCalendarFactory;
import org.holiday.calendar.HolidayDate;

HolidayCalendarFactory factory = new HolidayCalendarFactory();

// Get the US holiday calendar
HolidayCalendar usCalendar = factory.create("US");

// Calculate observed holiday dates for 2025
List<HolidayDate> holidays = usCalendar.calculate(2025);
holidays.forEach(hd ->
    System.out.printf("%s  %s%n", hd.getDate(), hd.getHoliday().getName())
);

Check if a date is a weekend

boolean isWeekend = usCalendar.isWeekendUTC(Instant.now());

Merge two calendars

HolidayCalendar ukCalendar = factory.create("UK");
HolidayCalendar combined = usCalendar.merge(ukCalendar);
List<HolidayDate> combined2025 = combined.calculate(2025);

List all available calendar codes

List<String> codes = factory.listAvailableCodes();
// ["AE", "AED", "AU", "AUD", "BH", "BHD", "CA", "CAD", "CH", "CHF", "CN", "CNY", "DE", "EUR", "FR", "GBP", "IL", "ILS", "JO", "JOD", "JP", "JPY", "KW", "KWD", "MA", "MAD", "QA", "QAR", "SA", "SAR", "SG", "SGD", "TR", "TRY", "UK", "US", "USD"]

Retrieve early close holidays

EarlyCloseHoliday entries represent partial trading days — e.g. NYSE's 1:00pm ET close the day after Thanksgiving. They are excluded from calculate() and must be retrieved separately via calculateEarlyCloses(int). Use an exchange MIC code such as XNYS — national codes no longer carry early closes (with the sole exception of TR; see Supported Calendars).

import org.holiday.calendar.EarlyCloseHoliday;

HolidayCalendar xnysCalendar = factory.create("XNYS");

for (HolidayDate hd : xnysCalendar.calculateEarlyCloses(2026)) {
    EarlyCloseHoliday earlyClose = (EarlyCloseHoliday) hd.getHoliday();
    System.out.printf("%s  %s closes at %s %s%n",
        hd.getDate(), earlyClose.getName(), earlyClose.getCloseTime(), earlyClose.getZoneId());
}

hasEarlyCloses() is a cheap, year-independent check for whether a calendar has any early-close entries at all, useful for branching without computing a specific year.

if (xnysCalendar.hasEarlyCloses()) {
    System.out.println("This calendar publishes early-close trading days.");
}

To get a single chronologically-sorted view of both full closures and early closes for a year, merge the two result lists and re-sort — HolidayDate is not Comparable, so sort with an explicit Comparator:

import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;

List<HolidayDate> allDates2026 = Stream.concat(
        xnysCalendar.calculate(2026).stream(),
        xnysCalendar.calculateEarlyCloses(2026).stream())
    .sorted(Comparator.comparing(HolidayDate::getDate))
    .toList();

Define a custom holiday calendar

Implement HolidayCalendarService, register it via ServiceLoader, and it will be discovered automatically by HolidayCalendarFactory.

public class HolidayCalendarServiceJP implements HolidayCalendarService {

    @Override
    public boolean isProvided(String code) {
        return "JP".equalsIgnoreCase(code);
    }

    @Override
    public String getCode() { return "JP"; }

    @Override
    public String getRegion() { return "Japan National Holidays"; }

    @Override
    public HolidayCalendar getHolidayCalendar() {
        return HolidayCalendar.builder()
            .code("JP")
            .name("Japan National Holidays")
            .dateRoll(DateRolls.followingMonday())
            .holiday(Holiday.builder()
                .name("New Year's Day")
                .monthDay(Month.JANUARY, 1)
                .build())
            // ... additional holidays
            .build();
    }
}

Register the service in META-INF/services/org.holiday.calendar.HolidayCalendarService and add a provides directive to module-info.java.

Contributing

Contributions are welcome! Please read the Contributing Guide before opening an issue or pull request. This project adheres to a Code of Conduct — all participants are expected to uphold it.

License

Holiday Calendar is released under the GNU Lesser General Public License, version 2.1.

About

A library for definition and calculation of holiday calendars.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

55 stars

Watchers

54 watching

Forks

Releases

Packages

Used by

Contributors

Languages