diff --git a/CHANGES.txt b/CHANGES.txt index b3fe6996e4..f9a61a4237 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0.13 + * Fix CQL tojson timestamp output on negative timestamp values before Gregorian calendar reform in 1582 (CASSANDRA-19566) * Fix few types issues and implement types compatibility tests (CASSANDRA-19479) * Optionally avoid hint transfer during decommission (CASSANDRA-19525) * Change logging to TRACE when failing to get peer certificate (CASSANDRA-19508) diff --git a/src/java/org/apache/cassandra/db/marshal/DateType.java b/src/java/org/apache/cassandra/db/marshal/DateType.java index 473cedf407..372dac4f2c 100644 --- a/src/java/org/apache/cassandra/db/marshal/DateType.java +++ b/src/java/org/apache/cassandra/db/marshal/DateType.java @@ -80,7 +80,7 @@ public class DateType extends AbstractType @Override public String toJSONString(ByteBuffer buffer, ProtocolVersion protocolVersion) { - return '"' + TimestampSerializer.getJsonDateFormatter().format(TimestampSerializer.instance.deserialize(buffer)) + '"'; + return '"' + TimestampSerializer.getJsonDateFormatter().format(TimestampSerializer.instance.deserialize(buffer).toInstant()) + '"'; } @Override diff --git a/src/java/org/apache/cassandra/db/marshal/TimestampType.java b/src/java/org/apache/cassandra/db/marshal/TimestampType.java index 0dac6b0394..f876adbb8f 100644 --- a/src/java/org/apache/cassandra/db/marshal/TimestampType.java +++ b/src/java/org/apache/cassandra/db/marshal/TimestampType.java @@ -102,7 +102,7 @@ public class TimestampType extends TemporalType private String toString(Date date) { - return date != null ? TimestampSerializer.getJsonDateFormatter().format(date) : ""; + return date != null ? TimestampSerializer.getJsonDateFormatter().format(date.toInstant()) : ""; } @Override diff --git a/src/java/org/apache/cassandra/serializers/TimestampSerializer.java b/src/java/org/apache/cassandra/serializers/TimestampSerializer.java index 21cac667e4..e21af5ab52 100644 --- a/src/java/org/apache/cassandra/serializers/TimestampSerializer.java +++ b/src/java/org/apache/cassandra/serializers/TimestampSerializer.java @@ -22,7 +22,7 @@ import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; import java.nio.ByteBuffer; -import java.text.SimpleDateFormat; +import java.text.Format; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -32,7 +32,6 @@ import java.time.temporal.ChronoField; import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.TimeZone; import java.util.regex.Pattern; @@ -103,23 +102,29 @@ public class TimestampSerializer extends TypeSerializer private static final Pattern timestampPattern = Pattern.compile("^-?\\d+$"); - private static final FastThreadLocal FORMATTER_UTC = new FastThreadLocal() + private static final FastThreadLocal FORMATTER_UTC = new FastThreadLocal() { - protected SimpleDateFormat initialValue() + protected java.text.Format initialValue() { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"); - sdf.setTimeZone(TimeZone.getTimeZone("UTC")); - return sdf; + return new DateTimeFormatterBuilder() + .appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX") + .parseDefaulting(ChronoField.NANO_OF_DAY, 0) + .toFormatter() + .withZone(ZoneId.of("UTC")) + .toFormat(); } }; - private static final FastThreadLocal FORMATTER_TO_JSON = new FastThreadLocal() + private static final FastThreadLocal FORMATTER_TO_JSON = new FastThreadLocal() { - protected SimpleDateFormat initialValue() + protected java.text.Format initialValue() { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSX"); - sdf.setTimeZone(TimeZone.getTimeZone("UTC")); - return sdf; + return new DateTimeFormatterBuilder() + .appendPattern("yyyy-MM-dd HH:mm:ss.SSSX") + .parseDefaulting(ChronoField.NANO_OF_DAY, 0) + .toFormatter() + .withZone(ZoneId.of("UTC")) + .toFormat(); } }; @@ -169,7 +174,7 @@ public class TimestampSerializer extends TypeSerializer throw new MarshalException(String.format("Unable to parse a date/time from '%s'", source)); } - public static SimpleDateFormat getJsonDateFormatter() + public static Format getJsonDateFormatter() { return FORMATTER_TO_JSON.get(); } @@ -187,7 +192,7 @@ public class TimestampSerializer extends TypeSerializer public String toStringUTC(Date value) { - return value == null ? "" : FORMATTER_UTC.get().format(value); + return value == null ? "" : FORMATTER_UTC.get().format(value.toInstant()); } public Class getType() @@ -204,6 +209,6 @@ public class TimestampSerializer extends TypeSerializer { return buffer == null || !buffer.hasRemaining() ? "null" - : FORMATTER_UTC.get().format(deserialize(buffer)); + : FORMATTER_UTC.get().format(deserialize(buffer).toInstant()); } }