diff --git a/engine/time/src/main/java/io/deephaven/time/DateTimeUtils.java b/engine/time/src/main/java/io/deephaven/time/DateTimeUtils.java index 7f86e80403e..231547ee56f 100644 --- a/engine/time/src/main/java/io/deephaven/time/DateTimeUtils.java +++ b/engine/time/src/main/java/io/deephaven/time/DateTimeUtils.java @@ -982,21 +982,6 @@ public static long epochNanos(@Nullable final ZonedDateTime dateTime) { return safeComputeNanos(dateTime.toEpochSecond(), dateTime.getNano()); } - /** - * Returns nanoseconds from the Epoch for a {@link LocalDateTime} value in UTC timezone. - * - * @param localDateTime the local date time to compute the Epoch offset for - * @return nanoseconds since Epoch, or a NULL_LONG value if the local date time is null - */ - @ScriptApi - public static long epochNanosUTC(@Nullable final LocalDateTime localDateTime) { - if (localDateTime == null) { - return NULL_LONG; - } - return TimeUnit.SECONDS.toNanos(localDateTime.toEpochSecond(ZoneOffset.UTC)) - + localDateTime.toLocalTime().getNano(); - } - /** * Returns microseconds from the Epoch for an {@link Instant} value. * @@ -1415,43 +1400,6 @@ public static ZonedDateTime excelToZonedDateTime(final double excel, @Nullable f return epochMillisToZonedDateTime(excelTimeToEpochMillis(excel, timeZone), timeZone); } - /** - * Converts nanoseconds from the Epoch to a {@link LocalDateTime} in UTC timezone. - * - * @param nanos nanoseconds since Epoch - * @return {@code null} if the input is {@link QueryConstants#NULL_LONG}; otherwise the input nanoseconds from the - * Epoch converted to a {@link LocalDateTime} in UTC timezone - */ - public static @Nullable LocalDateTime epochNanosToLocalDateTimeUTC(final long nanos) { - return nanos == NULL_LONG ? null - : LocalDateTime.ofEpochSecond(nanos / 1_000_000_000L, (int) (nanos % 1_000_000_000L), ZoneOffset.UTC); - } - - /** - * Converts microseconds from the Epoch to a {@link LocalDateTime} in UTC timezone. - * - * @param micros microseconds since Epoch - * @return {@code null} if the input is {@link QueryConstants#NULL_LONG}; otherwise the input microseconds from the - * Epoch converted to a {@link LocalDateTime} in UTC timezone - */ - public static @Nullable LocalDateTime epochMicrosToLocalDateTimeUTC(final long micros) { - return micros == NULL_LONG ? null - : LocalDateTime.ofEpochSecond(micros / 1_000_000L, (int) ((micros % 1_000_000L) * MICRO), - ZoneOffset.UTC); - } - - /** - * Converts milliseconds from the Epoch to a {@link LocalDateTime} in UTC timezone. - * - * @param millis milliseconds since Epoch - * @return {@code null} if the input is {@link QueryConstants#NULL_LONG}; otherwise the input milliseconds from the - * Epoch converted to a {@link LocalDateTime} in UTC timezone - */ - public static @Nullable LocalDateTime epochMillisToLocalDateTimeUTC(final long millis) { - return millis == NULL_LONG ? null - : LocalDateTime.ofEpochSecond(millis / 1_000L, (int) ((millis % 1_000L) * MILLI), ZoneOffset.UTC); - } - // endregion // region Arithmetic diff --git a/engine/time/src/test/java/io/deephaven/time/TestDateTimeUtils.java b/engine/time/src/test/java/io/deephaven/time/TestDateTimeUtils.java index 4e3e6b3d501..c8fbfc2d78d 100644 --- a/engine/time/src/test/java/io/deephaven/time/TestDateTimeUtils.java +++ b/engine/time/src/test/java/io/deephaven/time/TestDateTimeUtils.java @@ -1391,10 +1391,6 @@ public void testEpochNanos() { TestCase.assertEquals(nanos, DateTimeUtils.epochNanos(dt3)); TestCase.assertEquals(NULL_LONG, DateTimeUtils.epochNanos((ZonedDateTime) null)); - - final LocalDateTime ldt = LocalDateTime.ofInstant(dt2, ZoneId.of("UTC")); - TestCase.assertEquals(nanos, DateTimeUtils.epochNanosUTC(ldt)); - TestCase.assertEquals(NULL_LONG, DateTimeUtils.epochNanosUTC(null)); } public void testEpochMicros() { @@ -1460,10 +1456,6 @@ public void testEpochNanosTo() { TestCase.assertEquals(dt3, DateTimeUtils.epochNanosToZonedDateTime(nanos, TZ_JP)); TestCase.assertNull(DateTimeUtils.epochNanosToZonedDateTime(NULL_LONG, TZ_JP)); TestCase.assertNull(DateTimeUtils.epochNanosToZonedDateTime(nanos, null)); - - final LocalDateTime ldt = LocalDateTime.ofInstant(dt2, ZoneId.of("UTC")); - TestCase.assertEquals(ldt, DateTimeUtils.epochNanosToLocalDateTimeUTC(nanos)); - TestCase.assertNull(DateTimeUtils.epochNanosToLocalDateTimeUTC(NULL_LONG)); } public void testEpochMicrosTo() { @@ -1479,10 +1471,6 @@ public void testEpochMicrosTo() { TestCase.assertEquals(dt3, DateTimeUtils.epochMicrosToZonedDateTime(micros, TZ_JP)); TestCase.assertNull(DateTimeUtils.epochMicrosToZonedDateTime(NULL_LONG, TZ_JP)); TestCase.assertNull(DateTimeUtils.epochMicrosToZonedDateTime(micros, null)); - - final LocalDateTime ldt = LocalDateTime.ofInstant(dt2, ZoneId.of("UTC")); - TestCase.assertEquals(ldt, DateTimeUtils.epochMicrosToLocalDateTimeUTC(micros)); - TestCase.assertNull(DateTimeUtils.epochMicrosToLocalDateTimeUTC(NULL_LONG)); } public void testEpochMillisTo() { @@ -1498,10 +1486,6 @@ public void testEpochMillisTo() { TestCase.assertEquals(dt3, DateTimeUtils.epochMillisToZonedDateTime(millis, TZ_JP)); TestCase.assertNull(DateTimeUtils.epochMillisToZonedDateTime(NULL_LONG, TZ_JP)); TestCase.assertNull(DateTimeUtils.epochMillisToZonedDateTime(millis, null)); - - final LocalDateTime ldt = LocalDateTime.ofInstant(dt2, ZoneId.of("UTC")); - TestCase.assertEquals(ldt, DateTimeUtils.epochMillisToLocalDateTimeUTC(millis)); - TestCase.assertNull(DateTimeUtils.epochMillisToLocalDateTimeUTC(NULL_LONG)); } public void testEpochSecondsTo() { diff --git a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/pagestore/topage/ToLocalDateTimePage.java b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/pagestore/topage/ToLocalDateTimePage.java index 8f906915d56..356d547c74e 100644 --- a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/pagestore/topage/ToLocalDateTimePage.java +++ b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/pagestore/topage/ToLocalDateTimePage.java @@ -5,7 +5,7 @@ import io.deephaven.chunk.ChunkType; import io.deephaven.chunk.attributes.Any; -import io.deephaven.time.DateTimeUtils; +import io.deephaven.parquet.table.util.TransferUtils; import io.deephaven.util.QueryConstants; import org.apache.parquet.schema.LogicalTypeAnnotation; import org.jetbrains.annotations.NotNull; @@ -79,21 +79,21 @@ private static LocalDateTime[] convertResultHelper(@NotNull final Object result, private static final class ToLocalDateTimePageFromMillis extends ToLocalDateTimePage { @Override public LocalDateTime[] convertResult(@NotNull final Object result) { - return convertResultHelper(result, DateTimeUtils::epochMillisToLocalDateTimeUTC); + return convertResultHelper(result, TransferUtils::epochMillisToLocalDateTimeUTC); } } private static final class ToLocalDateTimePageFromMicros extends ToLocalDateTimePage { @Override public LocalDateTime[] convertResult(@NotNull final Object result) { - return convertResultHelper(result, DateTimeUtils::epochMicrosToLocalDateTimeUTC); + return convertResultHelper(result, TransferUtils::epochMicrosToLocalDateTimeUTC); } } private static final class ToLocalDateTimePageFromNanos extends ToLocalDateTimePage { @Override public LocalDateTime[] convertResult(@NotNull final Object result) { - return convertResultHelper(result, DateTimeUtils::epochNanosToLocalDateTimeUTC); + return convertResultHelper(result, TransferUtils::epochNanosToLocalDateTimeUTC); } } diff --git a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/transfer/LocalDateTimeArrayTransfer.java b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/transfer/LocalDateTimeArrayTransfer.java index 16ed5fc6d0f..4b1e8a74da4 100644 --- a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/transfer/LocalDateTimeArrayTransfer.java +++ b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/transfer/LocalDateTimeArrayTransfer.java @@ -10,7 +10,7 @@ import io.deephaven.engine.rowset.RowSequence; import io.deephaven.engine.table.ColumnSource; -import io.deephaven.time.DateTimeUtils; +import io.deephaven.parquet.table.util.TransferUtils; import org.jetbrains.annotations.NotNull; import java.nio.LongBuffer; @@ -38,7 +38,7 @@ void resizeBuffer(final int length) { @Override void copyToBuffer(@NotNull final EncodedData data) { for (final LocalDateTime t : data.encodedValues) { - buffer.put(DateTimeUtils.epochNanosUTC(t)); + buffer.put(TransferUtils.epochNanosUTC(t)); } } } diff --git a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/transfer/LocalDateTimeTransfer.java b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/transfer/LocalDateTimeTransfer.java index 38ca4a338ea..b5e91a05a17 100644 --- a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/transfer/LocalDateTimeTransfer.java +++ b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/transfer/LocalDateTimeTransfer.java @@ -12,7 +12,7 @@ import io.deephaven.chunk.attributes.Values; import io.deephaven.engine.rowset.RowSequence; import io.deephaven.engine.table.ColumnSource; -import io.deephaven.time.DateTimeUtils; +import io.deephaven.parquet.table.util.TransferUtils; import org.jetbrains.annotations.NotNull; import java.nio.LongBuffer; @@ -31,7 +31,7 @@ final class LocalDateTimeTransfer extends GettingPrimitiveTransfer> data) { try (final CloseableIterator dataIterator = data.encodedValues.iterator()) { - dataIterator.forEachRemaining((LocalDateTime t) -> buffer.put(DateTimeUtils.epochNanosUTC(t))); + dataIterator.forEachRemaining((LocalDateTime t) -> buffer.put(TransferUtils.epochNanosUTC(t))); } } } diff --git a/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/util/TransferUtils.java b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/util/TransferUtils.java new file mode 100644 index 00000000000..ab231f07dfe --- /dev/null +++ b/extensions/parquet/table/src/main/java/io/deephaven/parquet/table/util/TransferUtils.java @@ -0,0 +1,66 @@ +package io.deephaven.parquet.table.util; + +import io.deephaven.time.DateTimeUtils; +import io.deephaven.util.QueryConstants; +import org.jetbrains.annotations.Nullable; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +/** + * Internal library with utility methods for converting data between Deephaven and Parquet. + */ +public class TransferUtils { + /** + * Returns nanoseconds from the Epoch for a {@link LocalDateTime} value in UTC timezone. + * + * @param localDateTime the local date time to compute the Epoch offset for + * @return nanoseconds since Epoch, or a NULL_LONG value if the local date time is null + */ + public static long epochNanosUTC(@Nullable final LocalDateTime localDateTime) { + if (localDateTime == null) { + return QueryConstants.NULL_LONG; + } + return DateTimeUtils.secondsToNanos(localDateTime.toEpochSecond(ZoneOffset.UTC)) + + localDateTime.toLocalTime().getNano(); + } + + /** + * Converts nanoseconds from the Epoch to a {@link LocalDateTime} in UTC timezone. + * + * @param nanos nanoseconds since Epoch + * @return {@code null} if the input is {@link QueryConstants#NULL_LONG}; otherwise the input nanoseconds from the + * Epoch converted to a {@link LocalDateTime} in UTC timezone + */ + public static @Nullable LocalDateTime epochNanosToLocalDateTimeUTC(final long nanos) { + return nanos == QueryConstants.NULL_LONG ? null + : LocalDateTime.ofEpochSecond(nanos / 1_000_000_000L, (int) (nanos % 1_000_000_000L), ZoneOffset.UTC); + } + + /** + * Converts microseconds from the Epoch to a {@link LocalDateTime} in UTC timezone. + * + * @param micros microseconds since Epoch + * @return {@code null} if the input is {@link QueryConstants#NULL_LONG}; otherwise the input microseconds from the + * Epoch converted to a {@link LocalDateTime} in UTC timezone + */ + public static @Nullable LocalDateTime epochMicrosToLocalDateTimeUTC(final long micros) { + return micros == QueryConstants.NULL_LONG ? null + : LocalDateTime.ofEpochSecond(micros / 1_000_000L, (int) ((micros % 1_000_000L) * DateTimeUtils.MICRO), + ZoneOffset.UTC); + } + + /** + * Converts milliseconds from the Epoch to a {@link LocalDateTime} in UTC timezone. + * + * @param millis milliseconds since Epoch + * @return {@code null} if the input is {@link QueryConstants#NULL_LONG}; otherwise the input milliseconds from the + * Epoch converted to a {@link LocalDateTime} in UTC timezone + */ + public static @Nullable LocalDateTime epochMillisToLocalDateTimeUTC(final long millis) { + return millis == QueryConstants.NULL_LONG ? null + : LocalDateTime.ofEpochSecond(millis / 1_000L, (int) ((millis % 1_000L) * DateTimeUtils.MILLI), + ZoneOffset.UTC); + } + +} diff --git a/extensions/parquet/table/src/test/java/io/deephaven/parquet/table/TestTransferUtils.java b/extensions/parquet/table/src/test/java/io/deephaven/parquet/table/TestTransferUtils.java new file mode 100644 index 00000000000..03a9ab96b62 --- /dev/null +++ b/extensions/parquet/table/src/test/java/io/deephaven/parquet/table/TestTransferUtils.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.parquet.table; + +import io.deephaven.parquet.table.util.TransferUtils; +import io.deephaven.time.DateTimeUtils; +import io.deephaven.util.QueryConstants; +import junit.framework.TestCase; +import org.junit.Test; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; + +final public class TestTransferUtils { + + @Test + public void testEpochNanosUTC() { + final long nanos = 123456789123456789L; + final Instant dt2 = Instant.ofEpochSecond(0, nanos); + final LocalDateTime ldt = LocalDateTime.ofInstant(dt2, ZoneId.of("UTC")); + TestCase.assertEquals(nanos, TransferUtils.epochNanosUTC(ldt)); + TestCase.assertEquals(QueryConstants.NULL_LONG, TransferUtils.epochNanosUTC(null)); + } + + @Test + public void testEpochNanosTo() { + final long nanos = 123456789123456789L; + final Instant dt2 = Instant.ofEpochSecond(0, nanos); + final LocalDateTime ldt = LocalDateTime.ofInstant(dt2, ZoneId.of("UTC")); + TestCase.assertEquals(ldt, TransferUtils.epochNanosToLocalDateTimeUTC(nanos)); + TestCase.assertNull(TransferUtils.epochNanosToLocalDateTimeUTC(QueryConstants.NULL_LONG)); + } + + @Test + public void testEpochMicrosTo() { + long nanos = 123456789123456789L; + final long micros = DateTimeUtils.nanosToMicros(nanos); + nanos = DateTimeUtils.microsToNanos(micros); + final Instant dt2 = Instant.ofEpochSecond(0, nanos); + final LocalDateTime ldt = LocalDateTime.ofInstant(dt2, ZoneId.of("UTC")); + TestCase.assertEquals(ldt, TransferUtils.epochMicrosToLocalDateTimeUTC(micros)); + TestCase.assertNull(TransferUtils.epochMicrosToLocalDateTimeUTC(QueryConstants.NULL_LONG)); + } + + @Test + public void testEpochMillisTo() { + long nanos = 123456789123456789L; + final long millis = DateTimeUtils.nanosToMillis(nanos); + nanos = DateTimeUtils.millisToNanos(millis); + final Instant dt2 = Instant.ofEpochSecond(0, nanos); + final LocalDateTime ldt = LocalDateTime.ofInstant(dt2, ZoneId.of("UTC")); + TestCase.assertEquals(ldt, TransferUtils.epochMillisToLocalDateTimeUTC(millis)); + TestCase.assertNull(TransferUtils.epochMillisToLocalDateTimeUTC(QueryConstants.NULL_LONG)); + } +} diff --git a/replication/static/src/main/java/io/deephaven/replicators/ReplicateParquetTransferObjects.java b/replication/static/src/main/java/io/deephaven/replicators/ReplicateParquetTransferObjects.java index eb8333ebfeb..508386a3b0c 100644 --- a/replication/static/src/main/java/io/deephaven/replicators/ReplicateParquetTransferObjects.java +++ b/replication/static/src/main/java/io/deephaven/replicators/ReplicateParquetTransferObjects.java @@ -69,9 +69,10 @@ public static void main(String[] args) throws IOException { replaceAll(PARQUET_INSTANT_VECTOR_TRANSFER_PATH, PARQUET_TIME_VECTOR_TRANSFER_PATH, null, NO_EXCEPTIONS, pairs); pairs = new String[][] { + {"io.deephaven.time.DateTimeUtils", "io.deephaven.parquet.table.util.TransferUtils"}, {"InstantArrayTransfer", "LocalDateTimeArrayTransfer"}, {"InstantVectorTransfer", "LocalDateTimeVectorTransfer"}, - {"DateTimeUtils.epochNanos", "DateTimeUtils.epochNanosUTC"}, + {"DateTimeUtils.epochNanos", "TransferUtils.epochNanosUTC"}, {"Instant", "LocalDateTime"} }; replaceAll(PARQUET_INSTANT_ARRAY_TRANSFER_PATH, PARQUET_LOCAL_DATE_TIME_ARRAY_TRANSFER_PATH, null, @@ -80,9 +81,10 @@ public static void main(String[] args) throws IOException { NO_EXCEPTIONS, pairs); pairs = new String[][] { + {"io.deephaven.time.DateTimeUtils", "io.deephaven.parquet.table.util.TransferUtils"}, {"TimeTransfer", "LocalDateTimeTransfer"}, {"LocalTime", "LocalDateTime"}, - {"DateTimeUtils.nanosOfDay", "DateTimeUtils.epochNanosUTC"} + {"DateTimeUtils.nanosOfDay", "TransferUtils.epochNanosUTC"} }; replaceAll(PARQUET_TIME_TRANSFER_PATH, PARQUET_LOCAL_DATE_TIME_TRANSFER_PATH, null, NO_EXCEPTIONS, pairs);