Time and Calendars
This chapter covers working with time and calendars in Deephaven queries. Since Deephaven specializes in real-time operations, understanding how to work with time is crucial to building effective analyses.
Critical concepts covered in this chapter include:
- Time data types
- Time constants
- Create temporal data
- Time arithmetic and filtering
- Time zones
- Business calendars
- Aggregate by time
- Put it all together
Time data types
Deephaven natively supports the following java.time types:
Instant: A specific point in time.ZonedDateTime: A specific point in time with time zone information.LocalDate: A date without time zone information.LocalTime: A time of day without date or time zone information.Duration: A length of time, such as 5 minutes or 1 hour.Period: A date-based amount of time, such as 2 months.ZoneId: A time zone, such asAmerica/New_York.
This chapter works mostly with Instant, plus ZonedDateTime, LocalDate, and Duration. See Work with time for details on all of them.
Time constants
Deephaven offers built-in constants for common time periods, defined in DateTimeUtils. Each constant is a number of nanoseconds:
Create temporal data
You can create temporal data with built-in query string methods. For instance, now returns the current time as an Instant, and adding a time constant to an Instant gives a sequence of later Instants:
Time arithmetic and filtering
Time arithmetic in tables uses built-in methods, either called directly or through the + and - operators. See DateTimeUtils for the available constants and methods.
In a query string, a date-time value goes in single quotes and ends with its time zone, such as '2025-06-01T09:30Z' or '2025-06-01T09:30 ET'. The Z suffix means UTC, and ET means US Eastern Time; Time zones covers time zone names. A duration also goes in single quotes, such as 'PT1H' for one hour. A string goes in backticks, such as `A`. Query strings covers literals in full.
epochMillis converts a timestamp to milliseconds since 1970-01-01 UTC. upperBin and lowerBin round a timestamp up or down to a multiple of an interval. The Aggregations over time buckets section uses lowerBin to group rows into 15-minute buckets.
plus, minus, upperBin, and lowerBin all accept a length of time in either of these forms:
- A time constant expression, such as
15 * MINUTE, which is a count of nanoseconds. - An ISO 8601 duration string, such as
'PT15M', which is aDuration.
plus and minus also accept a date-based Period, such as 'P1D'.
Filtering temporal data with where isn't much different from filtering numeric data:
Time zones
Time zones are a critical part of temporal data. The same instant can have a different local date and time in different time zones. For example, if it's 6 PM in Los Angeles during daylight saving time, it's 9 AM the next day in Shanghai. Methods that extract a date or time component, such as secondOfDay, dayOfYear, and hourOfDay, take a time zone because their result depends on it.
Pass a time zone in single quotes, in either of these forms:
- A full name, such as
'Asia/Shanghai'. - A short alias, such as
'PT'for Pacific Time (America/Los_Angeles) or'ET'for Eastern Time (America/New_York).
The alias 'PT' is unrelated to the PT prefix of duration strings such as 'PT1H'.
The final true argument to secondOfDay and hourOfDay sets asLocalTime. With asLocalTime set to true, they measure from local midnight by the wall clock, so a 9:30 AM local timestamp gives the same result on every day, including days when daylight saving time starts or ends.
The previous operations use Instant values. An Instant contains no time zone information, so each method call needs a time zone argument such as 'PT' or 'Asia/Shanghai'. Instead, you can bake the time zone into the data by converting to a ZonedDateTime with toZonedDateTime:
Business calendars
Business calendars help you work with trading days, business hours, and holidays.
Built-in calendars
Deephaven includes three built-in calendars: UTC and the example calendars USNYSE_EXAMPLE and USBANK_EXAMPLE. calendar_names lists the available calendars, and calendar gets one by name:
Note
The USNYSE_EXAMPLE and USBANK_EXAMPLE calendars are examples. For any production system, use a custom calendar. See Work with calendars to create one.
Filter and count with a calendar
You can use a calendar to:
- Filter data to business days with
isBusinessDay. - Filter data to business hours with
isBusinessTime. - Count business days with
numberBusinessDates.
The following examples use a table of synthetic trades. It has one trade every 30 seconds around the clock for five days, starting on Monday, July 14, 2025. The data therefore includes nights and a Saturday morning:
A query string can use a Python variable by name and call its methods, so nyse_cal.isBusinessDay(Timestamp) calls the calendar's isBusinessDay method for each row. Query strings covers this in full.
The following example filters the trades to business days and to business hours, then counts business days. numberBusinessDates counts the business dates between two times, including both ends. BizDaysFromStart is 1 for Monday's trades and rises to 5 for Friday's trades. Saturday isn't a business day, so Saturday's trades also get 5:
Aggregate by time
Grouping rows by date or by fixed intervals of time, then aggregating each group, is the core of most time-series analysis.
Daily summaries
Combine time operations with aggregations for powerful analysis. To summarize data by day, convert each timestamp to a date with toLocalDate, then aggregate with agg_by. For example, the following query uses the trading_data table from Filter and count with a calendar to calculate the number of trades, the total size, and the average price for each ticker on each day:
Aggregations over time buckets
Time buckets group data into fixed intervals so you can analyze trends across them. The following query uses lowerBin to place each trade into a 15-minute bucket, then calculates the average trade price and size for each ticker in each bucket:
Put it all together
Here's a practical example that brings these time concepts together. It combines the business-hours filter from Filter and count with a calendar with the daily summary from Daily summaries, a combination common in financial data analysis. It reuses the nyse_cal calendar and differs from those examples in two ways:
- Its data starts on January 1, an NYSE holiday, so the calendar filter removes that whole day.
- Its query uses
minuteOfDayto get each trade's minute of the day, then flags trades in the first hour after the open.
Next steps
Time handling is crucial for real-time data processing. The concepts covered here form the foundation for more advanced time-series analysis. To go further, see: