This page provides more details about the various CQL time types, and the Java types they are mapped to in the driver.
| CQL | Java | |
java.time.Instant | No time zone. Use
Instant.atZone or register TypeCodecs.ZONED_TIMESTAMP_SYSTEM, TypeCodecs.ZONED_TIMESTAMP_UTC or TypeCodecs.zonedTimestampAt() |
duration | CqlDuration | Custom driver type; can’t be accurately represented by any of the
java.time types. |
time map directly to
These are simple, time-zone-free representations of date-only (
yyyy-mm-dd) and time-only
timestamp is the date-and-time representation, stored as a number of milliseconds since
the epoch (01/01/1970 UTC).
timestamp does not store a time zone. This is not always obvious because clients generally do
use one for display. For instance, the following CQLSH snippet is from a machine in Pacific time:
cqlsh> CREATE TABLE test(t timestamp PRIMARY KEY); cqlsh> INSERT INTO test (t) VALUES (dateof(now())); cqlsh> SELECT * FROM test; t --------------------------------- 2018-11-07 08:50:52.433000-0800
It looks like the timestamp has a zone (
-0800), but it is actually the client’s. If you force
CQLSH to a different zone and observe the same data, it will be displayed differently:
$ TZ=UTC cqlsh cqlsh> SELECT * FROM test; t --------------------------------- 2018-11-07 16:50:52.433000+0000
Internally, Cassandra only stores the raw number of milliseconds. You can observe that with a cast:
cqlsh> SELECT cast(t as bigint) FROM test; cast(t as bigint) ------------------- 1541609452433
By default, the driver maps
java.time.Instant. This Java type is the closest to the
internal representation; in particular, it does not have a time zone. On the downside, this means
you can’t directly extract calendar fields (year, month, etc.). You need to call
atZone to perform
Row row = session.execute("SELECT t FROM test").one(); Instant instant = row.getInstant("t"); ZonedDateTime dateTime = instant.atZone(ZoneId.of("America/Los_Angeles")); System.out.println(dateTime.getYear());
Conversely, you can convert a
ZonedDateTime back to an
If you want to automate those
toInstant conversions, the driver comes with an optional
ZonedDateTime codec, that must be registered explicitly with the session:
CqlSession session = CqlSession.builder() .addTypeCodecs(TypeCodecs.ZONED_TIMESTAMP_UTC) .build(); Row row = session.execute("SELECT t FROM test").one(); ZonedDateTime dateTime = row.get("t", GenericType.ZONED_DATE_TIME);
There are various constants and methods to obtain a codec instance for a particular zone:
TypeCodecs.ZONED_TIMESTAMP_SYSTEM: system default;
Which zone you choose is application-dependent. The driver doesn’t map to
ZonedDateTime by default
because it would have to make an arbitrary choice; we want you to think about time zones explicitly
before you decide to use that type.
As already stated,
timestamp is stored as a number of milliseconds. If you try to write an
ZonedDateTime with higher precision through the driver, the sub-millisecond part will
CqlSession session = CqlSession.builder() .addTypeCodecs(TypeCodecs.ZONED_TIMESTAMP_UTC) .build(); ZonedDateTime valueOnClient = ZonedDateTime.parse("2018-11-07T16:50:52.433395762Z"); // sub-millisecond digits ^^^^^^ session.execute( SimpleStatement.newInstance("INSERT INTO test (t) VALUES (?)", valueOnClient)); ZonedDateTime valueInDb = session.execute("SELECT * FROM test").one().get(0, GenericType.ZONED_DATE_TIME); System.out.println(valueInDb); // Prints "2018-11-07T16:50:52.433Z"
duration represents a period in months, days and nanoseconds. The driver maps it to a
custom type: CqlDuration.
We deliberately avoided
java.time.Period, because it does not contain a nanoseconds part as
CqlDuration does; and we also avoided
java.time.Duration, because it represents an absolute
time-based amount, regardless of the calendar, whereas
CqlDuration manipulates conceptual days and
months instead. Thus a
CqlDuration of “2 months” represents a different amount of time depending
on the date to which it is applied (because months have a different number of days, and because
daylight savings rules might also apply, etc).
java.time.temporal.TemporalAmount, so it interoperates nicely with the
JDK’s built-in temporal types:
ZonedDateTime dateTime = ZonedDateTime.parse("2018-10-04T00:00-07:00[America/Los_Angeles]"); System.out.println(dateTime.minus(CqlDuration.from("1h15s15ns"))); // prints "2018-10-03T22:59:44.999999985-07:00[America/Los_Angeles]"