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:
- List calendars with
calendar_names. - Add and remove calendars with
add_calendarandremove_calendar. - Get a calendar with
calendar. - Get or set the default calendar with
calendar_nameandset_calendar. The default calendar is the one thatcalendarreturns when you don't pass a name.
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:
- In query strings, write a date-time literal, which Deephaven converts to an
Instant, or use Deephaven's built-in conversion functions. The examples below use literals. - In Python code, use the conversion functions in the
deephaven.timemodule.
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.