Elasticsearch Date Histogram Aggregation - calendar_interval and fixed_interval - Syntax, Example, and Tips

The Elasticsearch date histogram aggregation is a multi-bucket aggregation that groups documents into time intervals based on a date or date_nanos field. Each bucket spans a calendar unit (month, day, hour) or a fixed duration (90 seconds, 12 hours), with a document count and any sub-aggregations you nest inside. It is the foundation for time-series dashboards, log analytics, and anything that aggregates over time.

Syntax

GET /metrics/_search
{
  "size": 0,
  "aggs": {
    "by_hour": {
      "date_histogram": {
        "field": "@timestamp",
        "fixed_interval": "1h",
        "time_zone": "UTC",
        "format": "yyyy-MM-dd'T'HH:mm:ss",
        "min_doc_count": 0
      }
    }
  }
}

The older interval parameter was deprecated in 7.2 and removed in 8.0. Use calendar_interval for calendar-aware units, fixed_interval for absolute durations.

Parameters

Parameter Default Description
field required date or date_nanos field.
calendar_interval - One of minute, hour, day, week, month, quarter, year. Multiples not supported.
fixed_interval - Any duration: 30s, 5m, 2h, 7d, 15d. Multiples allowed.
time_zone UTC Bucket boundaries respect this zone, including DST shifts.
format - Date format for the bucket key string.
min_doc_count 0 Buckets with fewer docs are dropped. Set to 0 to keep empty buckets across the range.
extended_bounds - Force histogram to span a wider range than the data, filling empties.
hard_bounds - Restrict buckets to a range, ignoring docs outside.
missing - Substitute date for documents missing the field.
offset 0 Shift bucket boundaries (e.g. +6h to start days at 06:00).

You must specify exactly one of calendar_interval or fixed_interval.

Examples

Daily counts respecting Europe/Berlin time zone (DST aware):

"date_histogram": {
  "field": "@timestamp",
  "calendar_interval": "day",
  "time_zone": "Europe/Berlin"
}

5-minute buckets with a sum sub-aggregation:

"aggs": {
  "by_5m": {
    "date_histogram": { "field": "@timestamp", "fixed_interval": "5m" },
    "aggs": {
      "bytes_sent": { "sum": { "field": "bytes" } }
    }
  }
}

Force a continuous time series across a window even when buckets are empty:

"date_histogram": {
  "field": "@timestamp",
  "fixed_interval": "1h",
  "min_doc_count": 0,
  "extended_bounds": { "min": "2024-01-01", "max": "2024-01-08" }
}

Performance Notes

Date histograms over multi-month windows on high-ingest indices can produce hundreds of thousands of buckets when combined with sub-aggregations. The search.max_buckets setting (default 65,536) caps total buckets across the whole response - exceeding it raises too_many_buckets_exception.

calendar_interval: month produces irregular bucket sizes (28-31 days). fixed_interval: 30d produces uniform 30-day buckets but does not align to calendar months and drifts across year boundaries. Pick the one matching the question you are answering.

Date histograms over indices with millions of buckets per query are a common driver of slow searches in production. Pulse monitors slow query patterns, heap pressure, and aggregation buckets on Elasticsearch and OpenSearch clusters, flagging dashboards that produce expensive time-series queries.

Common Mistakes

  1. Using the removed interval parameter on Elasticsearch 8.x - the request is rejected.
  2. Using fixed_interval: 1M (1 megabyte? 1 minute?). M is not a valid fixed unit. Use calendar_interval: month instead.
  3. Forgetting min_doc_count: 0 plus extended_bounds when rendering a chart - missing intervals show as gaps.
  4. Setting time_zone only on the aggregation but storing local times in the index without a zone offset. Index times in UTC.
  5. Building hourly histograms over years of data, exceeding search.max_buckets.

Frequently Asked Questions

Q: What is the difference between calendar_interval and fixed_interval?
A: calendar_interval honors calendar rules - months are 28-31 days, weeks follow ISO definitions, hours respect DST. fixed_interval is a constant duration regardless of calendar. Use calendar for "monthly revenue", fixed for "every 90 seconds".

Q: Is the interval parameter still supported?
A: No. The date histogram interval parameter was deprecated in Elasticsearch 7.2 and removed in 8.0. Queries using it fail. Migrate to calendar_interval or fixed_interval.

Q: How does daylight saving time affect the buckets?
A: With calendar_interval: day and a non-UTC time_zone, the spring-forward day is 23 hours and the fall-back day is 25 hours. Bucket boundaries shift to keep midnight local. fixed_interval: 24h always produces 24-hour buckets and ignores DST.

Q: How do I include empty buckets in the response?
A: Set min_doc_count: 0 and provide extended_bounds (range to fill) or hard_bounds (range to restrict). Without extended_bounds, only buckets between the first and last matching document are emitted.

Q: Can I aggregate over date_nanos fields?
A: Yes. The date histogram supports both date (millisecond) and date_nanos (nanosecond) fields. Use fixed_interval with nanosecond-resolution durations like 100ms only against date_nanos.

Q: What happens when calendar_interval is set with a multiplier like 2d?
A: Rejected. calendar_interval accepts only single units (day, month, etc). Use fixed_interval: 2d for multiples.

Q: How do I avoid too_many_buckets_exception?
A: Reduce the time range, use a coarser interval, or switch to the auto date histogram aggregation which targets a fixed bucket count.

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.