Temporal values and time zones
Wiki / Spatial and temporal values
On this page
Temporal: DateTime
A timezone-aware instant combines a UTC moment with a presentation offset
and, optionally, a named IANA zone. Offset zones and names such as
Europe/London are both supported by the vendored transition table.
Construct, parse and re-zone
RETURN datetime('2024-06-27T15:30:45+05:00'); // parse ISO-8601 with offset
RETURN datetime('2024-06-27T15:30:45Z'); // Z = UTC
RETURN datetime('2024-06-27T15:30:45'); // no offset ⇒ UTC
RETURN datetime(); // the current instant (UTC)
// from civil components (only `year` is required; the rest default low):
RETURN datetime({year: 2024, month: 6, day: 27, hour: 15, minute: 30,
second: 45, timezone: '+05:00'});
// from an instant:
RETURN datetime({epochSeconds: 1719502245, timezone: '+05:00'});
RETURN datetime({epochMillis: 1719502245000});
// RE-ZONE: keep the same instant, change the presentation offset:
WITH datetime('2024-06-27T15:30:45Z') AS utc
RETURN datetime({datetime: utc, timezone: '+05:00'}); // 2024-06-27T20:30:45+05:00
// NAMED IANA zones (with DST), as a [Zone] suffix or a `timezone` name:
RETURN datetime('2021-07-15T12:00:00[Europe/London]'); // 2021-07-15T12:00:00+01:00[Europe/London] (BST)
RETURN datetime('2021-01-15T12:00:00[Europe/London]'); // ...+00:00[Europe/London] (GMT)
RETURN datetime({year: 2021, month: 7, day: 15, hour: 12, timezone: 'Europe/London'});
Named zones. A trailing [Region/City] (or a timezone: 'Region/City') selects
a named IANA zone; the offset (and DST) is resolved from a vendored transition
table. .timezone then returns the zone name (.offset is still
the offset string), and toString renders …+01:00[Europe/London]. Calendar
arithmetic re-resolves the offset across a DST boundary:
// add 6 months to a winter London time → lands in BST (+01:00), keeping 12:00 local:
RETURN (datetime('2021-01-15T12:00:00[Europe/London]') + duration({months: 6})).offset; // +01:00
Offset zones (Z, ±HH:MM) and named zones are both supported; an unknown zone
name yields null. The table covers 1900–2100; TIME stays offset-only.
Fields and conversions
WITH datetime('2024-06-27T15:30:45.250+05:00') AS dt
RETURN dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.nanosecond,
dt.epochSeconds, dt.epochMillis, dt.offsetSeconds, dt.offset, dt.timezone,
toString(dt); // ISO-8601 string
Ordering & equality
- Ordering is by the underlying instant.
- Equality (
=) requires the same instant, offset and named-zone identity — so a UTC value and a+05:00value of the same moment are equal instants but distinct values in GDB. A named zone and an offset-only zone can therefore compare unequal even when their resolved offsets match.
RETURN datetime('2024-06-27T15:30:45Z') = datetime('2024-06-27T20:30:45+05:00'); // false (same instant, different offset)
RETURN datetime('2024-06-27T15:30:45Z') < datetime('2024-06-27T16:00:00Z'); // true
DateTime is persisted and sent over Bolt (legacy DateTime struct on 4.4).
The other temporal types
Alongside the zoned DateTime, GDB has the full Cypher temporal family: DATE, TIME (zoned), LOCALTIME,
LOCALDATETIME, and DURATION. Each parses ISO-8601, renders via
toString, exposes component accessors, is persisted, and is sent over Bolt as the
matching temporal structure. Native drivers map it to runtime values or precision-preserving wrappers.
Construct
RETURN date('2024-06-27'), date({year: 2024, month: 6, day: 27}), date(); // date() = today (UTC)
RETURN localtime('15:30:45'), time('15:30:45+05:00');
RETURN localdatetime('2024-06-27T15:30:45');
RETURN duration('P1Y2M3DT4H5M6S'), duration({days: 10, hours: 2, minutes: 30});
date() also truncates: give it a DATETIME or
LOCALDATETIME value — or a full ISO datetime string — and it returns the
civil date the value shows in its own timezone.
RETURN date(datetime('2026-08-18T22:59:59.999Z')); // 2026-08-18
RETURN date(localdatetime('2026-08-18T07:00:00')); // 2026-08-18
RETURN date('2026-08-18T22:59:59.999Z'); // 2026-08-18 (string form)
Accessors
RETURN date('2024-06-27').year, date('2024-06-27').month, date('2024-06-27').day;
RETURN time('15:30:45+05:00').hour, time('15:30:45+05:00').offsetSeconds;
RETURN duration('P1Y2M3DT4H5M6S').months, // 14 (years folded into months)
duration('P1Y2M3DT4H5M6S').days, // 3
duration('P1Y2M3DT4H5M6S').seconds; // 14706
Arithmetic
Add/subtract a duration to/from a date/datetime, combine durations, scale a duration, or measure the gap between two temporals. Month arithmetic is calendar-aware (day clamped to the target month length).
RETURN date('2024-01-31') + duration('P1M'); // 2024-02-29 (leap-year clamp)
RETURN localdatetime('2024-06-27T23:30') + duration('PT1H'); // 2024-06-28T00:30:00
RETURN duration('P1D') + duration('P2D'); // P3D
RETURN duration('PT1H') * 3; // PT3H
RETURN duration.between(date('2024-06-01'), date('2024-06-10')); // PT777600S (9 days)
Ordering is by the underlying instant/value; durations have no full total order in
Cypher, so GDB orders them lexically by (months, days, seconds, nanos) for a
deterministic ORDER BY. DATETIME supports both offset and named IANA zones
(see Temporal values and time zones); TIME is offset-only.
Truncation and duration aliases
date.truncate(unit, value), datetime.truncate(unit, value) and
localdatetime.truncate(unit, value) truncate to supported unit boundaries.
An optional component-override map is accepted but ignored. The
duration.inSeconds, duration.inDays and duration.inMonths names currently
call the same implementation as duration.between; they do not implement
separate unit-specific semantics.
RETURN date.truncate('month', date('2026-09-15')) AS firstDay;