diff --git a/community/bolt/src/main/java/org/neo4j/bolt/v1/messaging/Neo4jPackV1.java b/community/bolt/src/main/java/org/neo4j/bolt/v1/messaging/Neo4jPackV1.java index 233eacd4cbf89..579d2bd1ccf29 100644 --- a/community/bolt/src/main/java/org/neo4j/bolt/v1/messaging/Neo4jPackV1.java +++ b/community/bolt/src/main/java/org/neo4j/bolt/v1/messaging/Neo4jPackV1.java @@ -20,6 +20,11 @@ package org.neo4j.bolt.v1.messaging; import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -299,37 +304,31 @@ public void writeDuration( long months, long days, long seconds, int nanos ) thr } @Override - public void writeDate( long epochDay ) throws IOException + public void writeDate( LocalDate localDate ) throws IOException { throw new BoltIOException( Status.Request.Invalid, "Date is not yet supported as a return type in Bolt" ); } @Override - public void writeLocalTime( long nanoOfDay ) throws IOException + public void writeLocalTime( LocalTime localTime ) throws IOException { throw new BoltIOException( Status.Request.Invalid, "LocalTime is not yet supported as a return type in Bolt" ); } @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws IOException + public void writeTime( OffsetTime offsetTime ) throws IOException { throw new BoltIOException( Status.Request.Invalid, "Time is not yet supported as a return type in Bolt" ); } @Override - public void writeLocalDateTime( long epochSecond, int nano ) throws IOException + public void writeLocalDateTime( LocalDateTime localDateTime ) throws IOException { throw new BoltIOException( Status.Request.Invalid, "LocalDateTime is not yet supported as a return type in Bolt" ); } @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws IOException - { - throw new BoltIOException( Status.Request.Invalid, "DateTime is not yet supported as a return type in Bolt" ); - } - - @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws IOException + public void writeDateTime( ZonedDateTime zonedDateTime ) throws IOException { throw new BoltIOException( Status.Request.Invalid, "DateTime is not yet supported as a return type in Bolt" ); } diff --git a/community/bolt/src/main/java/org/neo4j/bolt/v2/messaging/Neo4jPackV2.java b/community/bolt/src/main/java/org/neo4j/bolt/v2/messaging/Neo4jPackV2.java index 7b5ac057cd616..2708068fe96d1 100644 --- a/community/bolt/src/main/java/org/neo4j/bolt/v2/messaging/Neo4jPackV2.java +++ b/community/bolt/src/main/java/org/neo4j/bolt/v2/messaging/Neo4jPackV2.java @@ -20,8 +20,13 @@ package org.neo4j.bolt.v2.messaging; import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.Arrays; import org.neo4j.bolt.v1.messaging.Neo4jPack; @@ -36,9 +41,10 @@ import org.neo4j.values.storable.LocalDateTimeValue; import org.neo4j.values.storable.LocalTimeValue; import org.neo4j.values.storable.PointValue; -import org.neo4j.values.storable.TimeUtil; import org.neo4j.values.storable.TimeValue; +import org.neo4j.values.utils.TemporalUtil; +import static java.time.ZoneOffset.UTC; import static org.neo4j.values.storable.DateTimeValue.datetime; import static org.neo4j.values.storable.DateValue.epochDate; import static org.neo4j.values.storable.DurationValue.duration; @@ -123,51 +129,70 @@ public void writeDuration( long months, long days, long seconds, int nanos ) thr } @Override - public void writeDate( long epochDay ) throws IOException + public void writeDate( LocalDate localDate ) throws IOException { + long epochDay = localDate.toEpochDay(); + packStructHeader( 1, DATE ); pack( epochDay ); } @Override - public void writeLocalTime( long nanoOfDay ) throws IOException + public void writeLocalTime( LocalTime localTime ) throws IOException { + long nanoOfDay = localTime.toNanoOfDay(); + packStructHeader( 1, LOCAL_TIME ); pack( nanoOfDay ); } @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws IOException + public void writeTime( OffsetTime offsetTime ) throws IOException { + long nanosOfDayLocal = offsetTime.toLocalTime().toNanoOfDay(); + int offsetSeconds = offsetTime.getOffset().getTotalSeconds(); + packStructHeader( 2, TIME ); - pack( TimeUtil.nanosOfDayToLocal( nanosOfDayUTC, offsetSeconds ) ); + pack( nanosOfDayLocal ); pack( offsetSeconds ); } @Override - public void writeLocalDateTime( long epochSecond, int nano ) throws IOException + public void writeLocalDateTime( LocalDateTime localDateTime ) throws IOException { + long epochSecond = localDateTime.toEpochSecond( UTC ); + int nano = localDateTime.getNano(); + packStructHeader( 2, LOCAL_DATE_TIME ); pack( epochSecond ); pack( nano ); } @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws IOException + public void writeDateTime( ZonedDateTime zonedDateTime ) throws IOException { - packStructHeader( 3, DATE_TIME_WITH_ZONE_OFFSET ); - pack( epochSecondUTC ); - pack( nano ); - pack( offsetSeconds ); - } + long epochSecondUTC = zonedDateTime.toEpochSecond(); + int nano = zonedDateTime.getNano(); - @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws IOException - { - packStructHeader( 3, DATE_TIME_WITH_ZONE_NAME ); - pack( epochSecondUTC ); - pack( nano ); - pack( zoneId ); + ZoneId zone = zonedDateTime.getZone(); + if ( zone instanceof ZoneOffset ) + { + int offsetSeconds = ((ZoneOffset) zone).getTotalSeconds(); + + packStructHeader( 3, DATE_TIME_WITH_ZONE_OFFSET ); + pack( epochSecondUTC ); + pack( nano ); + pack( offsetSeconds ); + } + else + { + String zoneId = zone.getId(); + + packStructHeader( 3, DATE_TIME_WITH_ZONE_NAME ); + pack( epochSecondUTC ); + pack( nano ); + pack( zoneId ); + } } } @@ -247,7 +272,7 @@ private TimeValue unpackTime() throws IOException { long nanosOfDayLocal = unpackLong(); int offsetSeconds = unpackInteger(); - return time( TimeUtil.nanosOfDayToUTC( nanosOfDayLocal, offsetSeconds ), ZoneOffset.ofTotalSeconds( offsetSeconds ) ); + return time( TemporalUtil.nanosOfDayToUTC( nanosOfDayLocal, offsetSeconds ), ZoneOffset.ofTotalSeconds( offsetSeconds ) ); } private LocalDateTimeValue unpackLocalDateTime() throws IOException diff --git a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/ParameterConverter.java b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/ParameterConverter.java index f82f65eadea66..4155ef69d5e4d 100644 --- a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/ParameterConverter.java +++ b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/ParameterConverter.java @@ -20,13 +20,10 @@ package org.neo4j.cypher.internal.codegen; import java.lang.reflect.Array; -import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.OffsetTime; -import java.time.ZoneId; -import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayDeque; import java.util.ArrayList; @@ -47,13 +44,11 @@ import org.neo4j.values.storable.DurationValue; import org.neo4j.values.storable.TextArray; import org.neo4j.values.storable.TextValue; -import org.neo4j.values.storable.TimeUtil; import org.neo4j.values.storable.Values; import org.neo4j.values.virtual.MapValue; import org.neo4j.values.virtual.NodeValue; import org.neo4j.values.virtual.RelationshipValue; -import static java.time.ZoneOffset.UTC; import static org.neo4j.helpers.collection.Iterators.iteratorsEqual; /** @@ -365,41 +360,33 @@ public void writeDuration( long months, long days, long seconds, int nanos ) } @Override - public void writeDate( long epochDay ) + public void writeDate( LocalDate localDate ) { - writeValue( LocalDate.ofEpochDay( epochDay ) ); + writeValue( localDate ); } @Override - public void writeLocalTime( long nanoOfDay ) + public void writeLocalTime( LocalTime localTime ) { - writeValue( LocalTime.ofNanoOfDay( nanoOfDay ) ); + writeValue( localTime ); } @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) + public void writeTime( OffsetTime offsetTime ) { - writeValue( OffsetTime.of( - LocalTime.ofNanoOfDay( TimeUtil.nanosOfDayToLocal( nanosOfDayUTC, offsetSeconds ) ), - ZoneOffset.ofTotalSeconds( offsetSeconds ) ) ); + writeValue( offsetTime ); } @Override - public void writeLocalDateTime( long epochSecond, int nano ) + public void writeLocalDateTime( LocalDateTime localDateTime ) { - writeValue( LocalDateTime.ofInstant( Instant.ofEpochSecond( epochSecond, nano ), UTC ) ); + writeValue( localDateTime ); } @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) + public void writeDateTime( ZonedDateTime zonedDateTime ) { - writeValue( ZonedDateTime.ofInstant( Instant.ofEpochSecond( epochSecondUTC, nano ), ZoneOffset.ofTotalSeconds( offsetSeconds ) ) ); - } - - @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) - { - writeValue( ZonedDateTime.ofInstant( Instant.ofEpochSecond( epochSecondUTC, nano ), ZoneId.of( zoneId ) ) ); + writeValue( zonedDateTime ); } private interface Writer diff --git a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/CastSupport.scala b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/CastSupport.scala index 52d265d78b828..0cee1792bb9a1 100644 --- a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/CastSupport.scala +++ b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/CastSupport.scala @@ -241,23 +241,20 @@ object CastSupport { override def writeDuration(months: Long, days: Long, seconds: Long, nanos: Int): Unit = write(DurationValue.duration(months, days, seconds, nanos)) - override def writeDate(epochDay: Long): Unit = - write(DateValue.epochDate(epochDay).asObject()) + override def writeDate(localDate: LocalDate): Unit = + write(localDate) - override def writeLocalTime(nanoOfDay: Long): Unit = - write(LocalTimeValue.localTime(nanoOfDay).asObject()) + override def writeLocalTime(localTime: LocalTime): Unit = + write(localTime) - override def writeTime(nanosOfDayUTC: Long, offsetSeconds: Int): Unit = - write(TimeValue.time(nanosOfDayUTC, ZoneOffset.ofTotalSeconds(offsetSeconds)).asObject()) + override def writeTime(offsetTime: OffsetTime): Unit = + write(offsetTime) - override def writeLocalDateTime(epochSecond: Long, nano: Int): Unit = - write(LocalDateTimeValue.localDateTime(epochSecond,nano).asObject()) + override def writeLocalDateTime(localDateTime: LocalDateTime): Unit = + write(localDateTime) - override def writeDateTime(epochSecondUTC: Long, nano: Int, offsetSeconds: Int): Unit = - write(DateTimeValue.datetime(epochSecondUTC, nano, ZoneOffset.ofTotalSeconds(offsetSeconds)).asObject()) - - override def writeDateTime(epochSecondUTC: Long, nano: Int, zoneId: String): Unit = - write(DateTimeValue.datetime(epochSecondUTC, nano, ZoneId.of(zoneId)).asObject()) + override def writeDateTime(zonedDateTime: ZonedDateTime): Unit = + write(zonedDateTime) } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/index/ArrayEncoder.java b/community/kernel/src/main/java/org/neo4j/kernel/api/index/ArrayEncoder.java index 5e5593025e379..1ec9e47eba1dd 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/index/ArrayEncoder.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/index/ArrayEncoder.java @@ -19,8 +19,11 @@ */ package org.neo4j.kernel.api.index; -import java.time.ZoneId; -import java.time.ZoneOffset; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; import java.util.Base64; import org.neo4j.string.UTF8; @@ -166,44 +169,37 @@ public void writeDuration( long months, long days, long seconds, int nanos ) thr } @Override - public void writeDate( long epochDay ) throws RuntimeException + public void writeDate( LocalDate localDate ) throws RuntimeException { - builder.append( DateValue.epochDate( epochDay ).prettyPrint() ); + builder.append( DateValue.date( localDate ).prettyPrint() ); builder.append( '|' ); } @Override - public void writeLocalTime( long nanoOfDay ) throws RuntimeException + public void writeLocalTime( LocalTime localTime ) throws RuntimeException { - builder.append( LocalTimeValue.localTime( nanoOfDay ).prettyPrint() ); + builder.append( LocalTimeValue.localTime( localTime ).prettyPrint() ); builder.append( '|' ); } @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws RuntimeException + public void writeTime( OffsetTime offsetTime ) throws RuntimeException { - builder.append( TimeValue.time( nanosOfDayUTC, ZoneOffset.ofTotalSeconds( offsetSeconds ) ).prettyPrint() ); + builder.append( TimeValue.time( offsetTime ).prettyPrint() ); builder.append( '|' ); } @Override - public void writeLocalDateTime( long epochSecond, int nano ) throws RuntimeException + public void writeLocalDateTime( LocalDateTime localDateTime ) throws RuntimeException { - builder.append( LocalDateTimeValue.localDateTime( epochSecond, nano ).prettyPrint() ); + builder.append( LocalDateTimeValue.localDateTime( localDateTime ).prettyPrint() ); builder.append( '|' ); } @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws RuntimeException + public void writeDateTime( ZonedDateTime zonedDateTime ) throws RuntimeException { - builder.append( DateTimeValue.datetime( epochSecondUTC, nano, ZoneOffset.ofTotalSeconds( offsetSeconds ) ).prettyPrint() ); - builder.append( '|' ); - } - - @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws RuntimeException - { - builder.append( DateTimeValue.datetime( epochSecondUTC, nano, ZoneId.of( zoneId ) ).prettyPrint() ); + builder.append( DateTimeValue.datetime( zonedDateTime ).prettyPrint() ); builder.append( '|' ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaKey.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaKey.java index dd5604d0d7d59..1d83b1c77a77f 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaKey.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaKey.java @@ -20,15 +20,15 @@ package org.neo4j.kernel.impl.index.schema; import org.neo4j.index.internal.gbptree.GBPTree; +import org.neo4j.kernel.impl.store.TemporalValueWriterAdapter; import org.neo4j.values.storable.Value; -import org.neo4j.values.storable.ValueWriter; /** * Includes value and entity id (to be able to handle non-unique values). * This is the abstraction of what NativeSchemaIndex with friends need from a schema key. * Note that it says nothing about how keys are compared, serialized, read, written, etc. That is the job of Layout. */ -abstract class NativeSchemaKey> extends ValueWriter.Adapter +abstract class NativeSchemaKey> extends TemporalValueWriterAdapter { private static final boolean DEFAULT_COMPARE_ID = true; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/PropertyStore.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/PropertyStore.java index 64256e586c33d..f3d10372e9bc3 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/PropertyStore.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/PropertyStore.java @@ -53,7 +53,6 @@ import org.neo4j.values.storable.ArrayValue; import org.neo4j.values.storable.CoordinateReferenceSystem; import org.neo4j.values.storable.Value; -import org.neo4j.values.storable.ValueWriter; import static org.neo4j.kernel.impl.store.DynamicArrayStore.getRightArray; import static org.neo4j.kernel.impl.store.NoStoreHeaderFormat.NO_STORE_HEADER_FORMAT; @@ -411,7 +410,7 @@ private static ByteBuffer grow( ByteBuffer buffer, int required ) return ByteBuffer.allocate( capacity ).order( ByteOrder.LITTLE_ENDIAN ).put( buffer ); } - private static class PropertyBlockValueWriter implements ValueWriter + private static class PropertyBlockValueWriter extends TemporalValueWriterAdapter { private final PropertyBlock block; private final int keyId; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/TemporalValueWriterAdapter.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/TemporalValueWriterAdapter.java new file mode 100644 index 0000000000000..a073ec66c3280 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/TemporalValueWriterAdapter.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2002-2018 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.store; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import org.neo4j.values.storable.ValueWriter; +import org.neo4j.values.utils.TemporalUtil; + +import static java.time.ZoneOffset.UTC; + +/** + * A {@link ValueWriter} that defines format for all temporal types, except duration. + * Subclasses will not be able to override methods like {@link #writeDate(LocalDate)}. They should instead override {@link #writeDate(long)} that + * defines how {@link LocalDate} is serialized. + *

+ * Primary purpose of this class is to share serialization format between property store writer and schema indexes. + * + * @param the error type. + */ +public abstract class TemporalValueWriterAdapter extends ValueWriter.Adapter +{ + @Override + public final void writeDate( LocalDate localDate ) throws E + { + writeDate( localDate.toEpochDay() ); + } + + @Override + public final void writeLocalTime( LocalTime localTime ) throws E + { + writeLocalTime( localTime.toNanoOfDay() ); + } + + @Override + public final void writeTime( OffsetTime offsetTime ) throws E + { + long nanosOfDayUTC = TemporalUtil.getNanosOfDayUTC( offsetTime ); + int offsetSeconds = offsetTime.getOffset().getTotalSeconds(); + writeTime( nanosOfDayUTC, offsetSeconds ); + } + + @Override + public final void writeLocalDateTime( LocalDateTime localDateTime ) throws E + { + long epochSecond = localDateTime.toEpochSecond( UTC ); + int nano = localDateTime.getNano(); + writeLocalDateTime( epochSecond, nano ); + } + + @Override + public final void writeDateTime( ZonedDateTime zonedDateTime ) throws E + { + long epochSecondUTC = zonedDateTime.toEpochSecond(); + int nano = zonedDateTime.getNano(); + + ZoneId zone = zonedDateTime.getZone(); + if ( zone instanceof ZoneOffset ) + { + int offsetSeconds = ((ZoneOffset) zone).getTotalSeconds(); + writeDateTime( epochSecondUTC, nano, offsetSeconds ); + } + else + { + String zoneId = zone.getId(); + writeDateTime( epochSecondUTC, nano, zoneId ); + } + } + + /** + * Write date value obtained from {@link LocalDate} in {@link #writeDate(LocalDate)}. + * + * @param epochDay the epoch day. + */ + protected void writeDate( long epochDay ) throws E + { + } + + /** + * Write local time value obtained from {@link LocalTime} in {@link #writeLocalTime(LocalTime)}. + * + * @param nanoOfDay the nanosecond of the day. + */ + protected void writeLocalTime( long nanoOfDay ) throws E + { + } + + /** + * Write time value obtained from {@link OffsetTime} in {@link #writeTime(OffsetTime)}. + * + * @param nanosOfDayUTC nanoseconds of day in UTC. will be between -18h and +42h + * @param offsetSeconds time zone offset in seconds + */ + protected void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws E + { + } + + /** + * Write local date-time value obtained from {@link LocalDateTime} in {@link #writeLocalDateTime(LocalDateTime)}. + * + * @param epochSecond the epoch second in UTC. + * @param nano the nanosecond. + */ + protected void writeLocalDateTime( long epochSecond, int nano ) throws E + { + } + + /** + * Write zoned date-time value obtained from {@link ZonedDateTime} in {@link #writeDateTime(ZonedDateTime)}. + * + * @param epochSecondUTC the epoch second in UTC (no offset). + * @param nano the nanosecond. + * @param offsetSeconds the offset in seconds. + */ + protected void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws E + { + } + + /** + * Write zoned date-time value obtained from {@link ZonedDateTime} in {@link #writeDateTime(ZonedDateTime)}. + * + * @param epochSecondUTC the epoch second in UTC (no offset). + * @param nano the nanosecond. + * @param zoneId the timezone id. + */ + protected void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws E + { + } +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/BaseToObjectValueWriter.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/BaseToObjectValueWriter.java index bc7ea26b0be60..1eae6f80c56a7 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/BaseToObjectValueWriter.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/BaseToObjectValueWriter.java @@ -20,13 +20,10 @@ package org.neo4j.kernel.impl.util; import java.lang.reflect.Array; -import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.OffsetTime; -import java.time.ZoneId; -import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayDeque; import java.util.ArrayList; @@ -54,7 +51,6 @@ import org.neo4j.values.virtual.NodeValue; import org.neo4j.values.virtual.RelationshipValue; -import static java.time.ZoneOffset.UTC; import static org.neo4j.helpers.collection.Iterators.iteratorsEqual; /** @@ -417,40 +413,33 @@ public void writeDuration( long months, long days, long seconds, int nanos ) } @Override - public void writeDate( long epochDay ) throws RuntimeException + public void writeDate( LocalDate localDate ) throws RuntimeException { - writeValue( LocalDate.ofEpochDay( epochDay ) ); + writeValue( localDate ); } @Override - public void writeLocalTime( long nanoOfDay ) throws RuntimeException + public void writeLocalTime( LocalTime localTime ) throws RuntimeException { - writeValue( LocalTime.ofNanoOfDay( nanoOfDay ) ); + writeValue( localTime ); } @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws RuntimeException + public void writeTime( OffsetTime offsetTime ) throws RuntimeException { - writeValue( OffsetTime.ofInstant( Instant.ofEpochSecond( 0, nanosOfDayUTC ), - ZoneOffset.ofTotalSeconds( offsetSeconds ) ) ); + writeValue( offsetTime ); } @Override - public void writeLocalDateTime( long epochSecond, int nano ) throws RuntimeException + public void writeLocalDateTime( LocalDateTime localDateTime ) throws RuntimeException { - writeValue( LocalDateTime.ofInstant( Instant.ofEpochSecond(epochSecond, nano), UTC ) ); + writeValue( localDateTime ); } @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws RuntimeException + public void writeDateTime( ZonedDateTime zonedDateTime ) throws RuntimeException { - writeValue( ZonedDateTime.ofInstant( Instant.ofEpochSecond(epochSecondUTC, nano), ZoneOffset.ofTotalSeconds( offsetSeconds ) ) ); - } - - @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws RuntimeException - { - writeValue( ZonedDateTime.ofInstant( Instant.ofEpochSecond(epochSecondUTC, nano), ZoneId.of( zoneId ) ) ); + writeValue( zonedDateTime ); } private interface Writer diff --git a/community/values/src/main/java/org/neo4j/values/storable/DateTimeValue.java b/community/values/src/main/java/org/neo4j/values/storable/DateTimeValue.java index a6f63a84a952f..6134e58566a05 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/DateTimeValue.java +++ b/community/values/src/main/java/org/neo4j/values/storable/DateTimeValue.java @@ -459,17 +459,7 @@ public boolean equals( Value other ) @Override public void writeTo( ValueWriter writer ) throws E { - Instant instant = value.toInstant(); - ZoneId zone = value.getZone(); - if ( zone instanceof ZoneOffset ) - { - ZoneOffset offset = (ZoneOffset) zone; - writer.writeDateTime( instant.getEpochSecond(), instant.getNano(), offset.getTotalSeconds() ); - } - else - { - writer.writeDateTime( instant.getEpochSecond(), instant.getNano(), zone.getId() ); - } + writer.writeDateTime( value ); } @Override diff --git a/community/values/src/main/java/org/neo4j/values/storable/DateValue.java b/community/values/src/main/java/org/neo4j/values/storable/DateValue.java index 4da6016eaf41d..caeefc74c5103 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/DateValue.java +++ b/community/values/src/main/java/org/neo4j/values/storable/DateValue.java @@ -260,7 +260,7 @@ public boolean equals( Value other ) @Override public void writeTo( ValueWriter writer ) throws E { - writer.writeDate( value.toEpochDay() ); + writer.writeDate( value ); } @Override diff --git a/community/values/src/main/java/org/neo4j/values/storable/DurationValue.java b/community/values/src/main/java/org/neo4j/values/storable/DurationValue.java index 60ff6e1a5eee4..318be0fb0a57c 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/DurationValue.java +++ b/community/values/src/main/java/org/neo4j/values/storable/DurationValue.java @@ -55,10 +55,10 @@ import static java.util.regex.Pattern.CASE_INSENSITIVE; import static org.neo4j.values.storable.NumberType.NO_NUMBER; import static org.neo4j.values.storable.NumberValue.safeCastFloatingPoint; -import static org.neo4j.values.storable.TimeUtil.AVG_DAYS_PER_MONTH; -import static org.neo4j.values.storable.TimeUtil.AVG_SECONDS_PER_MONTH; -import static org.neo4j.values.storable.TimeUtil.NANOS_PER_SECOND; -import static org.neo4j.values.storable.TimeUtil.SECONDS_PER_DAY; +import static org.neo4j.values.utils.TemporalUtil.AVG_DAYS_PER_MONTH; +import static org.neo4j.values.utils.TemporalUtil.AVG_SECONDS_PER_MONTH; +import static org.neo4j.values.utils.TemporalUtil.NANOS_PER_SECOND; +import static org.neo4j.values.utils.TemporalUtil.SECONDS_PER_DAY; /** * We use our own implementation because neither {@link java.time.Duration} nor {@link java.time.Period} fits our needs. diff --git a/community/values/src/main/java/org/neo4j/values/storable/LocalDateTimeValue.java b/community/values/src/main/java/org/neo4j/values/storable/LocalDateTimeValue.java index 34b7fffe3d986..df18e05de07f7 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/LocalDateTimeValue.java +++ b/community/values/src/main/java/org/neo4j/values/storable/LocalDateTimeValue.java @@ -347,7 +347,7 @@ public boolean equals( Value other ) @Override public void writeTo( ValueWriter writer ) throws E { - writer.writeLocalDateTime( value.toEpochSecond( UTC ), value.getNano() ); + writer.writeLocalDateTime( value ); } @Override diff --git a/community/values/src/main/java/org/neo4j/values/storable/LocalTimeValue.java b/community/values/src/main/java/org/neo4j/values/storable/LocalTimeValue.java index 73fb52dea1f6f..d696045d262fe 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/LocalTimeValue.java +++ b/community/values/src/main/java/org/neo4j/values/storable/LocalTimeValue.java @@ -28,7 +28,6 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoField; import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; import java.util.Map; @@ -255,7 +254,7 @@ public boolean equals( Value other ) @Override public void writeTo( ValueWriter writer ) throws E { - writer.writeLocalTime( value.getLong( ChronoField.NANO_OF_DAY ) ); + writer.writeLocalTime( value ); } @Override diff --git a/community/values/src/main/java/org/neo4j/values/storable/TimeValue.java b/community/values/src/main/java/org/neo4j/values/storable/TimeValue.java index 5f944ca678fe7..e8bbb570d2535 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/TimeValue.java +++ b/community/values/src/main/java/org/neo4j/values/storable/TimeValue.java @@ -28,7 +28,6 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoField; import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; import java.util.HashMap; @@ -40,6 +39,7 @@ import org.neo4j.values.AnyValue; import org.neo4j.values.StructureBuilder; import org.neo4j.values.ValueMapper; +import org.neo4j.values.utils.TemporalUtil; import org.neo4j.values.virtual.MapValue; import org.neo4j.values.virtual.VirtualValues; @@ -49,7 +49,6 @@ import static org.neo4j.values.storable.DateTimeValue.parseZoneName; import static org.neo4j.values.storable.LocalTimeValue.optInt; import static org.neo4j.values.storable.LocalTimeValue.parseTime; -import static org.neo4j.values.storable.TimeUtil.NANOS_PER_SECOND; public final class TimeValue extends TemporalValue { @@ -260,15 +259,8 @@ protected TimeValue selectTime( private TimeValue( OffsetTime value ) { // truncate the offset to whole minutes - this.value = TimeUtil.truncateOffsetToMinutes( value ); - this.nanosOfDayUTC = getNanosOfDayUTC( this.value ); - } - - private static long getNanosOfDayUTC( OffsetTime value ) - { - long secondsOfDayLocal = value.getLong( ChronoField.SECOND_OF_DAY ); - long secondsOffset = value.getOffset().getTotalSeconds(); - return ( secondsOfDayLocal - secondsOffset ) * NANOS_PER_SECOND + value.getNano(); + this.value = TemporalUtil.truncateOffsetToMinutes( value ); + this.nanosOfDayUTC = TemporalUtil.getNanosOfDayUTC( this.value ); } @Override @@ -340,8 +332,7 @@ public boolean equals( Value other ) @Override public void writeTo( ValueWriter writer ) throws E { - int zoneOffsetSeconds = value.getOffset().getTotalSeconds(); - writer.writeTime( nanosOfDayUTC, zoneOffsetSeconds ); + writer.writeTime( value ); } @Override diff --git a/community/values/src/main/java/org/neo4j/values/storable/ValueWriter.java b/community/values/src/main/java/org/neo4j/values/storable/ValueWriter.java index f9d7798d3b114..345320b59b664 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/ValueWriter.java +++ b/community/values/src/main/java/org/neo4j/values/storable/ValueWriter.java @@ -20,6 +20,11 @@ package org.neo4j.values.storable; import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; /** * Writer of values. @@ -85,23 +90,15 @@ default void writeUTF8( byte[] bytes, int offset, int length ) throws E void writeDuration( long months, long days, long seconds, int nanos ) throws E; - void writeDate( long epochDay ) throws E; + void writeDate( LocalDate localDate ) throws E; - void writeLocalTime( long nanoOfDay ) throws E; + void writeLocalTime( LocalTime localTime ) throws E; - /** - * Write time value - * - * @param nanosOfDayUTC nanoseconds of day in UTC. will be between -18h and +42h - * @param offsetSeconds time zone offset in seconds - */ - void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws E; + void writeTime( OffsetTime offsetTime ) throws E; - void writeLocalDateTime( long epochSecond, int nano ) throws E; + void writeLocalDateTime( LocalDateTime localDateTime ) throws E; - void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws E; - - void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws E; + void writeDateTime( ZonedDateTime zonedDateTime ) throws E; class Adapter implements ValueWriter { @@ -181,32 +178,27 @@ public void writeDuration( long months, long days, long seconds, int nanos ) } @Override - public void writeDate( long epochDay ) throws E - { // no-op - } - - @Override - public void writeLocalTime( long nanoOfDay ) throws E + public void writeDate( LocalDate localDate ) throws E { // no-op } @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws E + public void writeLocalTime( LocalTime localTime ) throws E { // no-op } @Override - public void writeLocalDateTime( long epochSecond, int nano ) throws E + public void writeTime( OffsetTime offsetTime ) throws E { // no-op } @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws E + public void writeLocalDateTime( LocalDateTime localDateTime ) throws E { // no-op } @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws E + public void writeDateTime( ZonedDateTime zonedDateTime ) throws E { // no-op } } diff --git a/community/values/src/main/java/org/neo4j/values/utils/PrettyPrinter.java b/community/values/src/main/java/org/neo4j/values/utils/PrettyPrinter.java index 580aaef83b6d4..86da7175707f2 100644 --- a/community/values/src/main/java/org/neo4j/values/utils/PrettyPrinter.java +++ b/community/values/src/main/java/org/neo4j/values/utils/PrettyPrinter.java @@ -19,17 +19,22 @@ */ package org.neo4j.values.utils; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Deque; import org.neo4j.values.AnyValueWriter; +import org.neo4j.values.storable.CoordinateReferenceSystem; import org.neo4j.values.storable.TextArray; import org.neo4j.values.storable.TextValue; -import org.neo4j.values.storable.CoordinateReferenceSystem; -import org.neo4j.values.virtual.RelationshipValue; import org.neo4j.values.virtual.MapValue; import org.neo4j.values.virtual.NodeValue; +import org.neo4j.values.virtual.RelationshipValue; import static java.lang.String.format; @@ -179,63 +184,43 @@ public void writeDuration( long months, long days, long seconds, int nanos ) thr } @Override - public void writeDate( long epochDay ) throws RuntimeException + public void writeDate( LocalDate localDate ) throws RuntimeException { - append( "{date: {epochDay: " ); - append( Long.toString( epochDay ) ); - append( "}}" ); + append( "{date: " ); + append( quote( localDate.toString() ) ); + append( "}" ); } @Override - public void writeLocalTime( long nanoOfDay ) throws RuntimeException + public void writeLocalTime( LocalTime localTime ) throws RuntimeException { - append( "{localTime: {nanosOfDay: " ); - append( Long.toString( nanoOfDay ) ); - append( "}}" ); + append( "{localTime: " ); + append( quote( localTime.toString() ) ); + append( "}" ); } @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws RuntimeException + public void writeTime( OffsetTime offsetTime ) throws RuntimeException { - append( "{time: {nanosOfDayUTC: " ); - append( Long.toString( nanosOfDayUTC ) ); - append( ", offsetSeconds: " ); - append( Long.toString( offsetSeconds ) ); - append( "}}" ); + append( "{time: " ); + append( quote( offsetTime.toString() ) ); + append( "}" ); } @Override - public void writeLocalDateTime( long epochSecond, int nano ) throws RuntimeException + public void writeLocalDateTime( LocalDateTime localDateTime ) throws RuntimeException { - append( "{localDateTime: {epochDay: " ); - append( Long.toString( epochSecond ) ); - append( ", nanosOfDay: " ); - append( Long.toString( nano ) ); - append( "}}" ); - } - - @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws RuntimeException - { - append( "{datetime: {epochDay: " ); - append( Long.toString( epochSecondUTC ) ); - append( ", nanosOfDay: " ); - append( Long.toString( nano ) ); - append( ", offsetSeconds: " ); - append( Long.toString( offsetSeconds ) ); - append( "}}" ); + append( "{localDateTime: " ); + append( quote( localDateTime.toString() ) ); + append( "}" ); } @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws RuntimeException - { - append( "{datetime: {epochDay: " ); - append( Long.toString( epochSecondUTC ) ); - append( ", nanosOfDay: " ); - append( Long.toString( nano ) ); - append( ", timezone: \"" ); - append( zoneId ); - append( "\"}}" ); + public void writeDateTime( ZonedDateTime zonedDateTime ) throws RuntimeException + { + append( "{datetime: " ); + append( quote( zonedDateTime.toString() ) ); + append( "}" ); } @Override diff --git a/community/values/src/main/java/org/neo4j/values/storable/TimeUtil.java b/community/values/src/main/java/org/neo4j/values/utils/TemporalUtil.java similarity index 72% rename from community/values/src/main/java/org/neo4j/values/storable/TimeUtil.java rename to community/values/src/main/java/org/neo4j/values/utils/TemporalUtil.java index 5e14888dfbdd8..dc5c3b283ad92 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/TimeUtil.java +++ b/community/values/src/main/java/org/neo4j/values/utils/TemporalUtil.java @@ -17,40 +17,25 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.neo4j.values.storable; +package org.neo4j.values.utils; import java.time.OffsetTime; import java.time.ZoneOffset; import static java.time.temporal.ChronoUnit.DAYS; -@SuppressWarnings( "WeakerAccess" ) -public class TimeUtil +public final class TemporalUtil { public static final long NANOS_PER_SECOND = 1_000_000_000L; public static final long SECONDS_PER_DAY = DAYS.getDuration().getSeconds(); - public static final long NANOS_PER_DAY = NANOS_PER_SECOND * SECONDS_PER_DAY; /** 30.4375 days = 30 days, 10 hours, 30 minutes */ public static final double AVG_DAYS_PER_MONTH = 365.2425 / 12; public static final long AVG_SECONDS_PER_MONTH = 2_629_746; - private TimeUtil() + private TemporalUtil() { } - public static long asValidTime( long nanosPerDay ) - { - if ( nanosPerDay < 0 ) - { - return nanosPerDay + NANOS_PER_DAY; - } - if ( nanosPerDay >= NANOS_PER_DAY ) - { - return nanosPerDay - NANOS_PER_DAY; - } - return nanosPerDay; - } - public static OffsetTime truncateOffsetToMinutes( OffsetTime value ) { int offsetMinutes = value.getOffset().getTotalSeconds() / 60; @@ -58,13 +43,15 @@ public static OffsetTime truncateOffsetToMinutes( OffsetTime value ) return value.withOffsetSameInstant( truncatedOffset ); } - public static long nanosOfDayToLocal( long nanosOfDayUTC, int offsetSeconds ) + public static long nanosOfDayToUTC( long nanosOfDayLocal, int offsetSeconds ) { - return nanosOfDayUTC + offsetSeconds * NANOS_PER_SECOND; + return nanosOfDayLocal - offsetSeconds * NANOS_PER_SECOND; } - public static long nanosOfDayToUTC( long nanosOfDayLocal, int offsetSeconds ) + public static long getNanosOfDayUTC( OffsetTime value ) { - return nanosOfDayLocal - offsetSeconds * NANOS_PER_SECOND; + long secondsOfDayLocal = value.toLocalTime().toSecondOfDay(); + long secondsOffset = value.getOffset().getTotalSeconds(); + return (secondsOfDayLocal - secondsOffset) * NANOS_PER_SECOND + value.getNano(); } } diff --git a/community/values/src/test/java/org/neo4j/values/storable/BufferValueWriter.java b/community/values/src/test/java/org/neo4j/values/storable/BufferValueWriter.java index cdc6d9c816858..944557d2e3fbc 100644 --- a/community/values/src/test/java/org/neo4j/values/storable/BufferValueWriter.java +++ b/community/values/src/test/java/org/neo4j/values/storable/BufferValueWriter.java @@ -21,8 +21,11 @@ import org.hamcrest.Matchers; -import java.time.ZoneId; -import java.time.ZoneOffset; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -184,39 +187,33 @@ public void writeDuration( long months, long days, long seconds, int nanos ) } @Override - public void writeDate( long epochDay ) throws RuntimeException + public void writeDate( LocalDate localDate ) throws RuntimeException { - buffer.add( DateValue.epochDate( epochDay ) ); + buffer.add( DateValue.date( localDate ) ); } @Override - public void writeLocalTime( long nanoOfDay ) throws RuntimeException + public void writeLocalTime( LocalTime localTime ) throws RuntimeException { - buffer.add( LocalTimeValue.localTime( nanoOfDay ) ); + buffer.add( LocalTimeValue.localTime( localTime ) ); } @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws RuntimeException + public void writeTime( OffsetTime offsetTime ) throws RuntimeException { - buffer.add( TimeValue.time( nanosOfDayUTC, ZoneOffset.ofTotalSeconds( offsetSeconds ) ) ); + buffer.add( TimeValue.time( offsetTime ) ); } @Override - public void writeLocalDateTime( long epochSecond, int nano ) throws RuntimeException + public void writeLocalDateTime( LocalDateTime localDateTime ) throws RuntimeException { - buffer.add( LocalDateTimeValue.localDateTime( epochSecond, nano ) ); + buffer.add( LocalDateTimeValue.localDateTime( localDateTime ) ); } @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws RuntimeException + public void writeDateTime( ZonedDateTime zonedDateTime ) throws RuntimeException { - buffer.add( DateTimeValue.datetime( epochSecondUTC, nano, ZoneOffset.ofTotalSeconds( offsetSeconds ) ) ); - } - - @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws RuntimeException - { - buffer.add( DateTimeValue.datetime( epochSecondUTC, nano, ZoneId.of( zoneId ) ) ); + buffer.add( DateTimeValue.datetime( zonedDateTime ) ); } @SuppressWarnings( "WeakerAccess" ) diff --git a/community/values/src/test/java/org/neo4j/values/storable/DateTimeValueTest.java b/community/values/src/test/java/org/neo4j/values/storable/DateTimeValueTest.java index c63d175a44874..2570e1e19c234 100644 --- a/community/values/src/test/java/org/neo4j/values/storable/DateTimeValueTest.java +++ b/community/values/src/test/java/org/neo4j/values/storable/DateTimeValueTest.java @@ -44,7 +44,6 @@ import static org.neo4j.values.storable.DateValue.date; import static org.neo4j.values.storable.FrozenClockRule.assertEqualTemporal; import static org.neo4j.values.storable.InputMappingStructureBuilder.fromValues; -import static org.neo4j.values.storable.LocalDateTimeValue.inUTC; import static org.neo4j.values.storable.LocalDateTimeValue.localDateTime; import static org.neo4j.values.storable.LocalTimeValue.localTime; import static org.neo4j.values.storable.TimeValue.time; @@ -147,21 +146,12 @@ public void shouldWriteDateTime() } ) { List values = new ArrayList<>( 1 ); - List locals = new ArrayList<>( 1 ); ValueWriter writer = new ThrowingValueWriter.AssertOnly() { @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws RuntimeException + public void writeDateTime( ZonedDateTime zonedDateTime ) { - values.add( datetime( epochSecondUTC, nano, ZoneOffset.ofTotalSeconds( offsetSeconds ) ) ); - locals.add( localDateTime( epochSecondUTC, nano ) ); - } - - @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws RuntimeException - { - values.add( datetime( epochSecondUTC, nano, ZoneId.of( zoneId ) ) ); - locals.add( localDateTime( epochSecondUTC, nano ) ); + values.add( datetime( zonedDateTime ) ); } }; @@ -170,7 +160,6 @@ public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws // then assertEquals( singletonList( value ), values ); - assertEquals( singletonList( inUTC( value ) ), locals ); } } diff --git a/community/values/src/test/java/org/neo4j/values/storable/DateValueTest.java b/community/values/src/test/java/org/neo4j/values/storable/DateValueTest.java index 64c5cf051632d..ee33e409efd8e 100644 --- a/community/values/src/test/java/org/neo4j/values/storable/DateValueTest.java +++ b/community/values/src/test/java/org/neo4j/values/storable/DateValueTest.java @@ -34,7 +34,6 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import static org.neo4j.values.storable.DateValue.date; -import static org.neo4j.values.storable.DateValue.epochDate; import static org.neo4j.values.storable.DateValue.ordinalDate; import static org.neo4j.values.storable.DateValue.parse; import static org.neo4j.values.storable.DateValue.quarterDate; @@ -189,9 +188,9 @@ public void shouldWriteDate() ValueWriter writer = new ThrowingValueWriter.AssertOnly() { @Override - public void writeDate( long epochDay ) throws RuntimeException + public void writeDate( LocalDate localDate ) { - values.add( epochDate( epochDay ) ); + values.add( date( localDate ) ); } }; diff --git a/community/values/src/test/java/org/neo4j/values/storable/LocalDateTimeValueTest.java b/community/values/src/test/java/org/neo4j/values/storable/LocalDateTimeValueTest.java index 63d8227728df3..58f71fc06ef5f 100644 --- a/community/values/src/test/java/org/neo4j/values/storable/LocalDateTimeValueTest.java +++ b/community/values/src/test/java/org/neo4j/values/storable/LocalDateTimeValueTest.java @@ -19,11 +19,12 @@ */ package org.neo4j.values.storable; +import org.junit.Test; + +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -import org.junit.Test; - import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.neo4j.values.storable.DateValue.date; @@ -60,9 +61,9 @@ public void shouldWriteDateTime() ValueWriter writer = new ThrowingValueWriter.AssertOnly() { @Override - public void writeLocalDateTime( long epochSecond, int nano ) throws RuntimeException + public void writeLocalDateTime( LocalDateTime localDateTime ) { - values.add( localDateTime( epochSecond, nano ) ); + values.add( localDateTime( localDateTime ) ); } }; diff --git a/community/values/src/test/java/org/neo4j/values/storable/LocalTimeValueTest.java b/community/values/src/test/java/org/neo4j/values/storable/LocalTimeValueTest.java index ea7e10bf5acbf..a97a6c0103583 100644 --- a/community/values/src/test/java/org/neo4j/values/storable/LocalTimeValueTest.java +++ b/community/values/src/test/java/org/neo4j/values/storable/LocalTimeValueTest.java @@ -22,6 +22,7 @@ import org.junit.Test; import java.time.DateTimeException; +import java.time.LocalTime; import java.util.ArrayList; import java.util.List; @@ -97,9 +98,9 @@ public void shouldWriteLocalTime() ValueWriter writer = new ThrowingValueWriter.AssertOnly() { @Override - public void writeLocalTime( long nanoOfDay ) throws RuntimeException + public void writeLocalTime( LocalTime localTime ) { - values.add( localTime( nanoOfDay ) ); + values.add( localTime( localTime ) ); } }; diff --git a/community/values/src/test/java/org/neo4j/values/storable/ThrowingValueWriter.java b/community/values/src/test/java/org/neo4j/values/storable/ThrowingValueWriter.java index 9c4cc32fc82ab..4a1dceb930f6b 100644 --- a/community/values/src/test/java/org/neo4j/values/storable/ThrowingValueWriter.java +++ b/community/values/src/test/java/org/neo4j/values/storable/ThrowingValueWriter.java @@ -19,6 +19,11 @@ */ package org.neo4j.values.storable; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; import java.util.function.Supplier; public abstract class ThrowingValueWriter implements ValueWriter @@ -137,37 +142,31 @@ public void writeDuration( long months, long days, long seconds, int nanos ) thr } @Override - public void writeDate( long epochDay ) throws E + public void writeDate( LocalDate localDate ) throws E { throw exception( "writeDate" ); } @Override - public void writeLocalTime( long nanoOfDay ) throws E + public void writeLocalTime( LocalTime localTime ) throws E { throw exception( "writeLocalTime" ); } @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws E + public void writeTime( OffsetTime offsetTime ) throws E { throw exception( "writeTime" ); } @Override - public void writeLocalDateTime( long epochSecond, int nano ) throws E + public void writeLocalDateTime( LocalDateTime localDateTime ) throws E { throw exception( "writeLocalDateTime" ); } @Override - public void writeDateTime( long epochSecondUTC, int nano, int offsetSeconds ) throws E - { - throw exception( "writeDateTime" ); - } - - @Override - public void writeDateTime( long epochSecondUTC, int nano, String zoneId ) throws E + public void writeDateTime( ZonedDateTime zonedDateTime ) throws E { throw exception( "writeDateTime" ); } diff --git a/community/values/src/test/java/org/neo4j/values/storable/TimeValueTest.java b/community/values/src/test/java/org/neo4j/values/storable/TimeValueTest.java index 0449e636d8d7d..10e4caf7c7444 100644 --- a/community/values/src/test/java/org/neo4j/values/storable/TimeValueTest.java +++ b/community/values/src/test/java/org/neo4j/values/storable/TimeValueTest.java @@ -22,10 +22,12 @@ import org.junit.Test; import java.time.DateTimeException; +import java.time.OffsetTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import static java.time.ZoneOffset.UTC; @@ -34,9 +36,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertSame; -import static org.neo4j.values.storable.LocalTimeValue.inUTC; -import static org.neo4j.values.storable.LocalTimeValue.localTime; -import static org.neo4j.values.storable.TimeUtil.asValidTime; import static org.neo4j.values.storable.TimeValue.parse; import static org.neo4j.values.storable.TimeValue.time; import static org.neo4j.values.utils.AnyValueTestUtil.assertEqual; @@ -111,14 +110,12 @@ public void shouldWriteTime() } ) { List values = new ArrayList<>( 1 ); - List locals = new ArrayList<>( 1 ); ValueWriter writer = new ThrowingValueWriter.AssertOnly() { @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws RuntimeException + public void writeTime( OffsetTime offsetTime ) { - values.add( time( nanosOfDayUTC, ZoneOffset.ofTotalSeconds( offsetSeconds ) ) ); - locals.add( localTime( asValidTime( nanosOfDayUTC ) ) ); + values.add( time( offsetTime ) ); } }; @@ -127,7 +124,6 @@ public void writeTime( long nanosOfDayUTC, int offsetSeconds ) throws RuntimeExc // then assertEquals( singletonList( time ), values ); - assertEquals( singletonList( inUTC( time ) ), locals ); } } @@ -216,11 +212,10 @@ public void shouldWriteDerivedValueThatIsEqual() TimeValue value1 = time( 42, ZoneOffset.of( "-18:00" ) ); TimeValue value2 = time( value1.temporal() ); - NanoOfDayAndOffset nanoAndOffset1 = write( value1 ); - NanoOfDayAndOffset nanoAndOffset2 = write( value2 ); + OffsetTime offsetTime1 = write( value1 ); + OffsetTime offsetTime2 = write( value2 ); - assertEquals( nanoAndOffset1.nanosOfDay, nanoAndOffset2.nanosOfDay ); - assertEquals( nanoAndOffset1.offsetSeconds, nanoAndOffset2.offsetSeconds ); + assertEquals( offsetTime1, offsetTime2 ); } @Test @@ -246,19 +241,18 @@ private DateTimeException assertCannotParse( String text ) throw new AssertionError( text ); } - private static NanoOfDayAndOffset write( TimeValue value ) + private static OffsetTime write( TimeValue value ) { - NanoOfDayAndOffset result = new NanoOfDayAndOffset(); + AtomicReference result = new AtomicReference<>(); value.writeTo( new ThrowingValueWriter.AssertOnly() { @Override - public void writeTime( long nanosOfDayUTC, int offsetSeconds ) + public void writeTime( OffsetTime offsetTime ) { - result.nanosOfDay = nanosOfDayUTC; - result.offsetSeconds = offsetSeconds; + result.set( offsetTime ); } } ); - return result; + return result.get(); } private static class NanoOfDayAndOffset diff --git a/community/values/src/test/java/org/neo4j/values/utils/PrettyPrinterTest.java b/community/values/src/test/java/org/neo4j/values/utils/PrettyPrinterTest.java index 5bbbb1cde7a36..ee8f8ff0c832d 100644 --- a/community/values/src/test/java/org/neo4j/values/utils/PrettyPrinterTest.java +++ b/community/values/src/test/java/org/neo4j/values/utils/PrettyPrinterTest.java @@ -21,26 +21,40 @@ import org.junit.Test; +import java.time.ZoneOffset; import java.util.HashMap; import org.neo4j.values.AnyValue; import org.neo4j.values.storable.CoordinateReferenceSystem; +import org.neo4j.values.storable.DateTimeValue; +import org.neo4j.values.storable.DateValue; +import org.neo4j.values.storable.DurationValue; +import org.neo4j.values.storable.LocalDateTimeValue; +import org.neo4j.values.storable.LocalTimeValue; +import org.neo4j.values.storable.PointValue; import org.neo4j.values.storable.TextArray; import org.neo4j.values.storable.TextValue; +import org.neo4j.values.storable.TimeValue; import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Values; -import org.neo4j.values.storable.PointValue; -import org.neo4j.values.virtual.RelationshipReference; -import org.neo4j.values.virtual.RelationshipValue; import org.neo4j.values.virtual.ListValue; import org.neo4j.values.virtual.MapValue; import org.neo4j.values.virtual.NodeReference; import org.neo4j.values.virtual.NodeValue; import org.neo4j.values.virtual.PathValue; +import org.neo4j.values.virtual.RelationshipReference; +import org.neo4j.values.virtual.RelationshipValue; import org.neo4j.values.virtual.VirtualValues; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.neo4j.values.storable.DateTimeValue.datetime; +import static org.neo4j.values.storable.DateValue.date; +import static org.neo4j.values.storable.DurationValue.duration; +import static org.neo4j.values.storable.LocalDateTimeValue.localDateTime; +import static org.neo4j.values.storable.LocalTimeValue.localTime; +import static org.neo4j.values.storable.TimeValue.time; import static org.neo4j.values.storable.Values.byteValue; import static org.neo4j.values.storable.Values.intValue; import static org.neo4j.values.storable.Values.stringValue; @@ -312,6 +326,83 @@ public void shouldBeAbleToUseAnyQuoteMark() assertThat( printer.value(), equalTo( "__(ツ)__" ) ); } + @Test + public void shouldHandleDuration() + { + DurationValue duration = duration( 12, 45, 90, 9911 ); + PrettyPrinter printer = new PrettyPrinter(); + + duration.writeTo( printer ); + + assertEquals( "{duration: {months: 12, days: 45, seconds: 90, nanos: 9911}}", printer.value() ); + } + + @Test + public void shouldHandleDate() + { + DateValue date = date( 1991, 9, 24 ); + PrettyPrinter printer = new PrettyPrinter(); + + date.writeTo( printer ); + + assertEquals( "{date: \"1991-09-24\"}", printer.value() ); + } + + @Test + public void shouldHandleLocalTime() + { + LocalTimeValue localTime = localTime( 18, 39, 24, 111222777 ); + PrettyPrinter printer = new PrettyPrinter(); + + localTime.writeTo( printer ); + + assertEquals( "{localTime: \"18:39:24.111222777\"}", printer.value() ); + } + + @Test + public void shouldHandleTime() + { + TimeValue time = time( 11, 19, 11, 123456789, ZoneOffset.ofHoursMinutes( -9, -30 ) ); + PrettyPrinter printer = new PrettyPrinter(); + + time.writeTo( printer ); + + assertEquals( "{time: \"11:19:11.123456789-09:30\"}", printer.value() ); + } + + @Test + public void shouldHandleLocalDateTime() + { + LocalDateTimeValue localDateTime = localDateTime( 2015, 8, 8, 8, 40, 29, 999888111 ); + PrettyPrinter printer = new PrettyPrinter(); + + localDateTime.writeTo( printer ); + + assertEquals( "{localDateTime: \"2015-08-08T08:40:29.999888111\"}", printer.value() ); + } + + @Test + public void shouldHandleDateTimeWithTimeZoneId() + { + DateTimeValue datetime = datetime( 2045, 2, 7, 12, 00, 40, 999888999, "Europe/London" ); + PrettyPrinter printer = new PrettyPrinter(); + + datetime.writeTo( printer ); + + assertEquals( "{datetime: \"2045-02-07T12:00:40.999888999Z[Europe/London]\"}", printer.value() ); + } + + @Test + public void shouldHandleDateTimeWithTimeZoneOffset() + { + DateTimeValue datetime = datetime( 1988, 4, 19, 10, 12, 59, 112233445, ZoneOffset.ofHoursMinutes( 3, 15 ) ); + PrettyPrinter printer = new PrettyPrinter(); + + datetime.writeTo( printer ); + + assertEquals( "{datetime: \"1988-04-19T10:12:59.112233445+03:15\"}", printer.value() ); + } + private MapValue props( Object... keyValue ) { HashMap map = new HashMap<>( keyValue.length ); diff --git a/community/values/src/test/java/org/neo4j/values/utils/TemporalUtilTest.java b/community/values/src/test/java/org/neo4j/values/utils/TemporalUtilTest.java new file mode 100644 index 0000000000000..ab045a7c78f13 --- /dev/null +++ b/community/values/src/test/java/org/neo4j/values/utils/TemporalUtilTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2002-2018 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.values.utils; + +import org.junit.Test; + +import java.time.Duration; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZoneOffset; + +import static java.time.temporal.ChronoUnit.SECONDS; +import static org.junit.Assert.assertEquals; + +public class TemporalUtilTest +{ + @Test + public void shouldDoNothingForOffsetWithoutSeconds() + { + OffsetTime time = OffsetTime.of( 23, 30, 10, 0, ZoneOffset.ofHoursMinutes( -5, -30 ) ); + + OffsetTime truncatedTime = TemporalUtil.truncateOffsetToMinutes( time ); + + assertEquals( time, truncatedTime ); + } + + @Test + public void shouldTruncateOffsetSeconds() + { + OffsetTime time = OffsetTime.of( 14, 55, 50, 0, ZoneOffset.ofHoursMinutesSeconds( 2, 15, 45 ) ); + + OffsetTime truncatedTime = TemporalUtil.truncateOffsetToMinutes( time ); + + assertEquals( OffsetTime.of( 14, 55, 5, 0, ZoneOffset.ofHoursMinutes( 2, 15 ) ), truncatedTime ); + } + + @Test + public void shouldConvertNanosOfDayToUTCWhenOffsetIsZero() + { + int nanosOfDayLocal = 42; + + long nanosOfDayUTC = TemporalUtil.nanosOfDayToUTC( nanosOfDayLocal, 0 ); + + assertEquals( nanosOfDayLocal, nanosOfDayUTC ); + } + + @Test + public void shouldConvertNanosOfDayToUTC() + { + int nanosOfDayLocal = 42; + Duration offsetDuration = Duration.ofMinutes( 35 ); + + long nanosOfDayUTC = TemporalUtil.nanosOfDayToUTC( nanosOfDayLocal, (int) offsetDuration.getSeconds() ); + + assertEquals( nanosOfDayLocal - offsetDuration.toNanos(), nanosOfDayUTC ); + } + + @Test + public void shouldGetNanosOfDayUTC() + { + LocalTime localTime = LocalTime.of( 14, 19, 18, 123999 ); + ZoneOffset offset = ZoneOffset.ofHours( -12 ); + OffsetTime time = OffsetTime.of( localTime, offset ); + + long nanosOfDayUTC = TemporalUtil.getNanosOfDayUTC( time ); + + long expectedNanosOfDayUTC = Duration.ofSeconds( localTime.toSecondOfDay() ) + .minus( offset.getTotalSeconds(), SECONDS ) + .toNanos(); + + assertEquals( expectedNanosOfDayUTC + localTime.getNano(), nanosOfDayUTC ); + } +}