Time-based data is at the core of most analytical workloads. Event logs, application metrics, IoT telemetry, financial transactions, and user activity streams all rely on accurate date and time processing.
ClickHouse® provides a rich set of date and time data types and functions that enable efficient storage, querying, aggregation, and transformation of temporal data. Understanding how these types work is essential for building performant analytical systems.
In this article, we’ll cover:
- Date and time data types
- Time zone handling
- Date and time functions
- Aggregation by time intervals
- Common pitfalls
- Performance considerations
Understanding Date and Time Data Types
ClickHouse® offers multiple date and time types, each optimized for different use cases.
Date
The Date type stores calendar dates without a time component.
CREATE TABLE events
(
event_date Date
)
ENGINE = MergeTree
ORDER BY event_date;
Example value:
2025-08-08
Use Date when time precision is unnecessary, such as daily reports or partitioning data by day.
Date32
Date32 extends the supported date range beyond the limitations of Date.
CREATE TABLE historical_data
(
record_date Date32
)
ENGINE = MergeTree
ORDER BY record_date;
This type is useful when working with historical datasets or future planning data that falls outside the standard Date range. Supported Range: [1900-01-01, 2299-12-31]
DateTime
DateTime stores date and time values with second-level precision.
CREATE TABLE user_activity
(
event_time DateTime
)
ENGINE = MergeTree
ORDER BY event_time;
Example value:
2025-08-08 14:30:45
This is the most commonly used temporal type in ClickHouse®.
DateTime64
DateTime64 supports fractional seconds.
CREATE TABLE api_logs
(
request_time DateTime64(3)
)
ENGINE = MergeTree
ORDER BY request_time;
Example value:
2025-08-08 14:30:45.123
The precision parameter determines the number of decimal digits:
| Precision | Unit |
|---|---|
| 3 | Milliseconds |
| 6 | Microseconds |
| 9 | Nanoseconds |
Use DateTime64 when high-resolution timestamps are required.
Working with Time Zones
Time zone handling is a common source of errors in analytics systems.
ClickHouse® allows time zones to be specified directly within temporal columns.
CREATE TABLE events
(
event_time DateTime('UTC')
)
ENGINE = MergeTree
ORDER BY event_time;
You can also use DateTime64 with a time zone.
event_time DateTime64(3, 'UTC')
Converting Between Time Zones
The toTimeZone() function converts timestamps between time zones.
SELECT
event_time,
toTimeZone(event_time, 'Asia/Kolkata') AS local_time
FROM events;
Example output:
UTC Time Local Time
2025-08-08 09:00:00 2025-08-08 14:30:00
A common practice is to store timestamps in UTC and convert them only during reporting or visualization.
Parsing Date and Time Values
Real-world datasets often arrive as strings.
Parsing Dates
SELECT toDate('2025-08-08');
Result:
2025-08-08
Parsing DateTime
SELECT toDateTime('2025-08-08 14:30:45');
Result:
2025-08-08 14:30:45
Parsing DateTime64
SELECT toDateTime64(
'2025-08-08 14:30:45.123',
3
);
Result:
2025-08-08 14:30:45.123
These conversion functions are frequently used during ingestion and ETL workflows.
Extracting Components
ClickHouse® provides functions to extract individual parts of a timestamp.
Given:
SELECT toDateTime('2025-08-08 14:30:45');
You can extract:
SELECT
toYear(event_time) AS year,
toMonth(event_time) AS month,
toDayOfMonth(event_time) AS day,
toHour(event_time) AS hour,
toMinute(event_time) AS minute
FROM events;
Example output:
year 2025
month 8
day 8
hour 14
minute 30
These functions are useful for building custom aggregations and dimensions.
Date Arithmetic
Date arithmetic is commonly required for retention analysis, rolling windows, and trend reporting.
Add Time
SELECT addDays(today(), 7);
SELECT addMonths(today(), 1);
SELECT addYears(today(), 1);
Subtract Time
SELECT subtractDays(today(), 30);
SELECT subtractMonths(today(), 6);
These functions simplify date calculations without requiring manual timestamp manipulation.
Rounding Dates and Times
Analytical queries often need timestamps grouped into larger intervals.
Round to Day
SELECT toStartOfDay(event_time)
FROM events;
Round to Hour
SELECT toStartOfHour(event_time)
FROM events;
Round to Month
SELECT toStartOfMonth(event_time)
FROM events;
Example:
Original Timestamp Rounded Hour
2025-08-08 14:37:22 2025-08-08 14:00:00
These functions are heavily used in dashboards and reporting pipelines.
Time-Based Aggregation
One of the most common analytical operations is grouping records by time intervals.
Daily Aggregation
SELECT
toDate(event_time) AS day,
count(*) AS events
FROM events
GROUP BY day
ORDER BY day;
Hourly Aggregation
SELECT
toStartOfHour(event_time) AS hour,
count(*) AS events
FROM events
GROUP BY hour
ORDER BY hour;
Monthly Aggregation
SELECT
toStartOfMonth(event_time) AS month,
sum(revenue) AS total_revenue
FROM sales
GROUP BY month
ORDER BY month;
These patterns form the foundation of most time-series analytics workloads.
Calculating Time Differences
The dateDiff() function calculates differences between timestamps.
SELECT
dateDiff(
'day',
signup_date,
current_date
) AS days_since_signup
FROM users;
Other supported units include:
second
minute
hour
day
week
month
year
Example:
SELECT dateDiff(
'hour',
'2025-08-08 10:00:00',
'2025-08-08 15:00:00'
);
Result:
5
Common Pitfalls
Mixing Time Zones
Storing timestamps in different time zones can create inconsistent results.
Prefer:
Store in UTC
Convert during query or presentation
Using Strings Instead of Native Types
Avoid storing timestamps as strings.
Bad:
event_time String
Good:
event_time DateTime64(3)
Native date and time types consume less storage and enable efficient filtering and aggregation.
Incorrect Precision Selection
Using nanosecond precision when only second-level precision is required increases storage costs without adding value.
Choose the lowest precision that satisfies business requirements.
Performance Considerations
Partition by Date
Large tables should typically be partitioned using a date column.
PARTITION BY toYYYYMM(event_time)
This allows ClickHouse® to skip irrelevant partitions during query execution.
Use Native Temporal Types
Filtering on native date and time types is significantly more efficient than filtering string values.
WHERE event_time >= now() - INTERVAL 7 DAY
is preferable to:
WHERE event_time_string >= '2025-08-01'
Avoid Repeated Conversions
Repeatedly calling conversion functions inside large scans can increase CPU usage.
Instead of:
WHERE toDate(event_time) = today()
consider storing or materializing the required value when appropriate.
Exploring ClickHouse® for Your Analytics?
At Quantrail Data, we help teams run ClickHouse® reliably for real-time analytics – from Kubernetes deployments and migrations to performance tuning in production.
We see these challenges firsthand while supporting demanding analytics workloads. In one recent engagement, a customer achieved near bare-metal performance with ClickHouse® in production – a story we’ve shared here:
Success Story: Quantrail Bare-Metal ClickHouse® Deployment
If you’re evaluating ClickHouse® or trying to get more out of an existing setup, we’re happy to share practical lessons from real-world deployments.
Contact
Quantrail Data
Conclusion
Date and time processing is fundamental to analytical workloads, and ClickHouse® provides a comprehensive toolkit for handling temporal data efficiently.
Key takeaways:
- Use
DateandDate32for date-only data. - Use
DateTimefor second-level precision. - Use
DateTime64when sub-second precision is required. - Store timestamps in UTC whenever possible.
- Use built-in functions for parsing, extraction, rounding, and arithmetic.
- Partition large tables by date to improve query performance.
- Prefer native temporal types over strings.
A solid understanding of these concepts helps build faster queries, more accurate reports, and scalable time-series analytics systems on ClickHouse®.
References
https://clickhouse.com/docs/sql-reference/functions/date-time-functions
