Work with calendars

This guide shows you how to create and use business calendars in Deephaven. A business calendar is a calendar that knows which days and hours are business time and which are not, such as weekends, holidays, and hours outside business hours.

This guide covers Deephaven's Python calendar API and how to use the Java BusinessCalendar object it returns in table operations. Because the calendar is a Java object, query strings can call its methods directly. Calling them directly avoids Python-Java boundary crossings and improves performance.

The Python API is minimal. It lets you:

This guide uses the functions that list, get, and add calendars. See Related documentation for the others.

Get a calendar

The code block below uses calendar_names to list the available calendars and calendar to get the USNYSE_EXAMPLE calendar.

Deephaven comes with three calendars: UTC, USNYSE_EXAMPLE, and USBANK_EXAMPLE. The output also confirms that nyse_cal is a BusinessCalendar. You don't need to be a Java developer to use it. The sections below use its methods in queries.

Warning

The calendars that come with Deephaven are examples, and Deephaven doesn't guarantee that their holidays are complete or current. Create your own calendars for production use.

Use a calendar in queries

The examples in this section call methods on nyse_cal, the calendar from Get a calendar, and use the source table created below.

Create data

Before you use a calendar in queries, create a table with some data. The following code block creates about three weeks' worth of date-time data spaced 3 minutes apart.

Input data types

Date and time arguments to BusinessCalendar methods are Java date-time types such as Instant, ZonedDateTime, and LocalDate. Many methods also accept strings. Check the Javadoc for each method's overloads. For example, isBusinessTime accepts an Instant or a ZonedDateTime, but not a string or a LocalDate.

To get these types:

Business days and business time

The following example uses numberBusinessDates and numberNonBusinessDates to calculate the number of business days and non-business days (weekends and holidays) between two timestamps. Both counts include the start and end dates.

The following code block filters source twice. The first filter uses isBusinessDay to keep rows that fall on an NYSE business day. The second uses isBusinessTime to keep rows that fall within NYSE business hours.

Plot against business time

To plot data against business time, pass the calendar to the calendar argument of a Deephaven Express plot, such as a line plot. The plot's time axis leaves out weekends, holidays, and hours outside business hours, so the plot has no gaps where the market is closed. The following code block plots all of source against NYSE business time.

The built-in plotting API supports business-time axes through the business_time and calendar arguments of axis. That API is no longer under active development.

Create a calendar

Deephaven's built-in calendar files use XML to define the properties of the calendar, which include:

  • Name
  • Time zone
  • Description
  • Valid date range
  • Default business hours and weekend days
  • Holidays and half-days

Deephaven ignores other elements, such as <language> and <country>.

To build your own calendar, create a calendar file in the format that the BusinessCalendarXMLParser Javadoc describes. The rest of this guide goes over an example of using a custom-built calendar for a hypothetical business for the year 2024. The example is based on a calendar file in Deephaven's examples repository.

The calendar file

Most business calendars have a single business period each day, such as 9am to 5pm. Some split the day around a lunch break. The test calendar below covers only 2024 and defines:

  • Two business periods: 8am to 12pm and 1pm to 5pm.
  • The 2024 holidays, two of which are half-days that are open only for the morning period.

Save the listing as /data/examples/Calendar/TestCalendar_2024.calendar in the Deephaven Docker container. The examples below load the calendar from that path.

If you have the examples repository's copy of TestCalendar_2024.calendar, replace it. That copy puts both <open>/<close> pairs in one <businessTime> element. Deephaven reads only the first pair in each element, so the copy defines only the morning period. The listing below gives each period its own <businessTime> element.

Test calendar for 2024

Add and use the new calendar

Add the calendar to the set of available calendars

Add a calendar from a running session with add_calendar, or load it when the server starts.

The following code block uses add_calendar to load /data/examples/Calendar/TestCalendar_2024.calendar, the file you saved in The calendar file.

Get an instance of the new calendar

After you add the calendar, get it by the name in its <name> element, the same way as a built-in calendar. calendar matches the name case-insensitively. calendar_names lists names in uppercase, such as TESTCALENDAR_2024.

Use the new calendar in a query

The new calendar works in queries the same way as nyse_cal in Use a calendar in queries. The following code block keeps only the rows of the source table from Create data that fall within the test calendar's business hours. Because of the lunch break, the result has no rows between 12pm and 1pm. It also has no rows on the January 1 and January 15 holidays.

Load calendars when the server starts

Instead of calling add_calendar in each session, you can load calendars when the server starts. The configuration property Calendar.userImportPath adds calendars to the built-in set when the server starts. Its value is the location of a text file that lists one calendar file location per line. Deephaven loads the text file and each calendar file as classpath resources, not filesystem paths, so:

  • The folder that holds the files must be on the server's classpath, the list of directories the Java server searches for resources. The Docker example below adds it with EXTRA_CLASSPATH.
  • Each location, including the property's value, starts with / and is relative to that folder.

Say a calendars folder next to your docker-compose.yml file contains three calendar files: MyCalendar.calendar, TestCalendar_2024.calendar, and CrazyCalendar.calendar. The same folder also contains a text file named calendar_imports.txt, which looks as follows:

To load these calendars when the server starts with Docker Compose, mount the folder, add it to the classpath with EXTRA_CLASSPATH, and set the property as a JVM argument in START_OPTS:

You can also set Calendar.userImportPath in a configuration file instead of START_OPTS. The folder must still be on the classpath.

Caution

Don't set Calendar.importPath to load your own calendars. Use Calendar.userImportPath instead. Calendar.importPath points to the list of built-in calendars, so overriding it drops UTC, USNYSE_EXAMPLE, and USBANK_EXAMPLE unless your list includes them.

The Calendar.default property sets the default calendar, and its value is UTC unless you change it. If UTC isn't loaded, requesting the default calendar fails with a "No such calendar" error. If you drop UTC, also set Calendar.default to a calendar you load.