From 716fdf3765ae352202b0bd46c67382fb02bacc8e Mon Sep 17 00:00:00 2001 From: Vinicius Fraga Date: Tue, 8 Mar 2022 08:37:50 -0300 Subject: [PATCH 1/5] Make UTC the default tz instead of using local tz --- .../arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessor.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessor.java index 0f50d3c4a46..2782ff58368 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessor.java @@ -37,6 +37,7 @@ import java.sql.Timestamp; import java.util.Calendar; import java.util.Map; +import java.util.TimeZone; import java.util.function.IntSupplier; /** @@ -51,6 +52,7 @@ public abstract class ArrowFlightJdbcAccessor implements Accessor { protected ArrowFlightJdbcAccessor(final IntSupplier currentRowSupplier, ArrowFlightJdbcAccessorFactory.WasNullConsumer wasNullConsumer) { + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); // set default TZ to UTC to avoid zone offset in Date/Time objects this.currentRowSupplier = currentRowSupplier; this.wasNullConsumer = wasNullConsumer; } From db808f2d1f43e437eb3b042441aacd00dd7befae Mon Sep 17 00:00:00 2001 From: Vinicius Fraga Date: Tue, 8 Mar 2022 09:53:42 -0300 Subject: [PATCH 2/5] Use Avatica DateTimeUtils for getString in Date/Time/TimeStamp --- .../driver/jdbc/accessor/ArrowFlightJdbcAccessor.java | 2 -- .../impl/calendar/ArrowFlightJdbcDateVectorAccessor.java | 7 +++++++ .../calendar/ArrowFlightJdbcTimeStampVectorAccessor.java | 7 +++++++ .../impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java | 7 +++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessor.java index 2782ff58368..0f50d3c4a46 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessor.java @@ -37,7 +37,6 @@ import java.sql.Timestamp; import java.util.Calendar; import java.util.Map; -import java.util.TimeZone; import java.util.function.IntSupplier; /** @@ -52,7 +51,6 @@ public abstract class ArrowFlightJdbcAccessor implements Accessor { protected ArrowFlightJdbcAccessor(final IntSupplier currentRowSupplier, ArrowFlightJdbcAccessorFactory.WasNullConsumer wasNullConsumer) { - TimeZone.setDefault(TimeZone.getTimeZone("UTC")); // set default TZ to UTC to avoid zone offset in Date/Time objects this.currentRowSupplier = currentRowSupplier; this.wasNullConsumer = wasNullConsumer; } diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java index b2be32e2d30..878a8105609 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java @@ -20,6 +20,7 @@ import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcDateVectorGetter.Getter; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcDateVectorGetter.Holder; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcDateVectorGetter.createGetter; +import static org.apache.calcite.avatica.util.DateTimeUtils.unixDateToString; import java.sql.Date; import java.sql.Timestamp; @@ -106,6 +107,12 @@ public Timestamp getTimestamp(Calendar calendar) { return new Timestamp(date.getTime()); } + @Override + public String getString() { + long milliseconds = timeUnit.toMillis(holder.value); + return unixDateToString((int) milliseconds); + } + protected static TimeUnit getTimeUnitForVector(ValueVector vector) { if (vector instanceof DateDayVector) { return TimeUnit.DAYS; diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java index c75bdf6e869..9878a023782 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java @@ -20,6 +20,7 @@ import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeStampVectorGetter.Getter; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeStampVectorGetter.Holder; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeStampVectorGetter.createGetter; +import static org.apache.calcite.avatica.util.DateTimeUtils.unixTimestampToString; import java.sql.Date; import java.sql.Time; @@ -131,6 +132,12 @@ public Timestamp getTimestamp(Calendar calendar) { return Timestamp.valueOf(localDateTime); } + @Override + public String getString() { + long milliseconds = timeUnit.toMillis(holder.value); + return unixTimestampToString((int) milliseconds); + } + protected static TimeUnit getTimeUnitForVector(TimeStampVector vector) { ArrowType.Timestamp arrowType = (ArrowType.Timestamp) vector.getField().getFieldType().getType(); diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java index a23f3314467..d666322d5b5 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java @@ -20,6 +20,7 @@ import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeVectorGetter.Getter; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeVectorGetter.Holder; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeVectorGetter.createGetter; +import static org.apache.calcite.avatica.util.DateTimeUtils.unixTimeToString; import java.sql.Time; import java.sql.Timestamp; @@ -138,6 +139,12 @@ public Timestamp getTimestamp(Calendar calendar) { return new Timestamp(time.getTime()); } + @Override + public String getString() { + long milliseconds = timeUnit.toMillis(holder.value); + return unixTimeToString((int) milliseconds); + } + protected static TimeUnit getTimeUnitForVector(ValueVector vector) { if (vector instanceof TimeNanoVector) { return TimeUnit.NANOSECONDS; From 95725af701d4d79c3f5fbfff0d4f1e0ab35887cc Mon Sep 17 00:00:00 2001 From: Vinicius Fraga Date: Thu, 10 Mar 2022 09:39:04 -0300 Subject: [PATCH 3/5] Correct usage for unix*ToString --- .../ArrowFlightJdbcDateVectorAccessor.java | 14 ++++++++++---- .../ArrowFlightJdbcTimeVectorAccessor.java | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java index 878a8105609..019ddc2b13d 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java @@ -20,6 +20,7 @@ import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcDateVectorGetter.Getter; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcDateVectorGetter.Holder; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcDateVectorGetter.createGetter; +import static org.apache.calcite.avatica.util.DateTimeUtils.MILLIS_PER_DAY; import static org.apache.calcite.avatica.util.DateTimeUtils.unixDateToString; import java.sql.Date; @@ -85,9 +86,7 @@ public Object getObject() { @Override public Date getDate(Calendar calendar) { - getter.get(getCurrentRow(), holder); - this.wasNull = holder.isSet == 0; - this.wasNullConsumer.setWasNull(this.wasNull); + fillHolder(); if (this.wasNull) { return null; } @@ -98,6 +97,12 @@ public Date getDate(Calendar calendar) { return new Date(DateTimeUtils.applyCalendarOffset(milliseconds, calendar)); } + private void fillHolder() { + getter.get(getCurrentRow(), holder); + this.wasNull = holder.isSet == 0; + this.wasNullConsumer.setWasNull(this.wasNull); + } + @Override public Timestamp getTimestamp(Calendar calendar) { Date date = getDate(calendar); @@ -109,8 +114,9 @@ public Timestamp getTimestamp(Calendar calendar) { @Override public String getString() { + fillHolder(); long milliseconds = timeUnit.toMillis(holder.value); - return unixDateToString((int) milliseconds); + return unixDateToString((int) (milliseconds / MILLIS_PER_DAY)); } protected static TimeUnit getTimeUnitForVector(ValueVector vector) { diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java index d666322d5b5..0c22313a821 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java @@ -20,6 +20,7 @@ import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeVectorGetter.Getter; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeVectorGetter.Holder; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeVectorGetter.createGetter; +import static org.apache.calcite.avatica.util.DateTimeUtils.MILLIS_PER_DAY; import static org.apache.calcite.avatica.util.DateTimeUtils.unixTimeToString; import java.sql.Time; @@ -117,9 +118,7 @@ public Object getObject() { @Override public Time getTime(Calendar calendar) { - getter.get(getCurrentRow(), holder); - this.wasNull = holder.isSet == 0; - this.wasNullConsumer.setWasNull(this.wasNull); + fillHolder(); if (this.wasNull) { return null; } @@ -130,6 +129,12 @@ public Time getTime(Calendar calendar) { return new Time(DateTimeUtils.applyCalendarOffset(milliseconds, calendar)); } + private void fillHolder() { + getter.get(getCurrentRow(), holder); + this.wasNull = holder.isSet == 0; + this.wasNullConsumer.setWasNull(this.wasNull); + } + @Override public Timestamp getTimestamp(Calendar calendar) { Time time = getTime(calendar); @@ -141,8 +146,9 @@ public Timestamp getTimestamp(Calendar calendar) { @Override public String getString() { + fillHolder(); long milliseconds = timeUnit.toMillis(holder.value); - return unixTimeToString((int) milliseconds); + return unixTimeToString((int) (milliseconds % MILLIS_PER_DAY)); } protected static TimeUnit getTimeUnitForVector(ValueVector vector) { From 7687a9576363988d86e955cf52dbaed4630c2e76 Mon Sep 17 00:00:00 2001 From: Vinicius Fraga Date: Thu, 10 Mar 2022 10:40:50 -0300 Subject: [PATCH 4/5] Add unit tests for Date/Time getString --- ...rrowFlightJdbcTimeStampVectorAccessor.java | 9 +------ ...ArrowFlightJdbcDateVectorAccessorTest.java | 25 +++++++++++++++++++ ...ArrowFlightJdbcTimeVectorAccessorTest.java | 25 +++++++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java index 9878a023782..a23883baf1e 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java @@ -20,7 +20,6 @@ import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeStampVectorGetter.Getter; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeStampVectorGetter.Holder; import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeStampVectorGetter.createGetter; -import static org.apache.calcite.avatica.util.DateTimeUtils.unixTimestampToString; import java.sql.Date; import java.sql.Time; @@ -132,12 +131,6 @@ public Timestamp getTimestamp(Calendar calendar) { return Timestamp.valueOf(localDateTime); } - @Override - public String getString() { - long milliseconds = timeUnit.toMillis(holder.value); - return unixTimestampToString((int) milliseconds); - } - protected static TimeUnit getTimeUnitForVector(TimeStampVector vector) { ArrowType.Timestamp arrowType = (ArrowType.Timestamp) vector.getField().getFieldType().getType(); @@ -184,7 +177,7 @@ protected static TimeZone getTimeZoneForVector(TimeStampVector vector) { String timezoneName = arrowType.getTimezone(); if (timezoneName == null) { - return TimeZone.getDefault(); + return TimeZone.getTimeZone("UTC"); } return TimeZone.getTimeZone(timezoneName); diff --git a/java/flight/flight-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessorTest.java b/java/flight/flight-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessorTest.java index 15a3705f07a..36af5134626 100644 --- a/java/flight/flight-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessorTest.java +++ b/java/flight/flight-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessorTest.java @@ -20,6 +20,7 @@ import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcDateVectorAccessor.getTimeUnitForVector; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; import java.sql.Date; import java.sql.Timestamp; @@ -205,6 +206,30 @@ public void testShouldGetStringBeConsistentWithVarCharAccessorWithCalendar() thr assertGetStringIsConsistentWithVarCharAccessor(calendar); } + @Test + public void testValidateGetStringTimeZoneConsistency() throws Exception { + accessorIterator.iterate(vector, (accessor, currentRow) -> { + final TimeZone defaultTz = TimeZone.getDefault(); + try { + final String string = accessor.getString(); // Should always be UTC as no calendar is provided + + // Validate with UTC + Date date = accessor.getDate(null); + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + collector.checkThat(date.toString(), is(string)); + + // Validate with different TZ + TimeZone.setDefault(TimeZone.getTimeZone(AMERICA_VANCOUVER)); + collector.checkThat(date.toString(), not(string)); + + collector.checkThat(accessor.wasNull(), is(false)); + } finally { + // Set default Tz back + TimeZone.setDefault(defaultTz); + } + }); + } + private void assertGetStringIsConsistentWithVarCharAccessor(Calendar calendar) throws Exception { try (VarCharVector varCharVector = new VarCharVector("", rootAllocatorTestRule.getRootAllocator())) { diff --git a/java/flight/flight-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessorTest.java b/java/flight/flight-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessorTest.java index 6dde8a8630b..d2f7eb336af 100644 --- a/java/flight/flight-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessorTest.java +++ b/java/flight/flight-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessorTest.java @@ -20,6 +20,7 @@ import static org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcTimeVectorAccessor.getTimeUnitForVector; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; import java.sql.Time; import java.sql.Timestamp; @@ -214,6 +215,30 @@ public void testShouldGetStringBeConsistentWithVarCharAccessorWithCalendar() thr assertGetStringIsConsistentWithVarCharAccessor(calendar); } + @Test + public void testValidateGetStringTimeZoneConsistency() throws Exception { + accessorIterator.iterate(vector, (accessor, currentRow) -> { + final TimeZone defaultTz = TimeZone.getDefault(); + try { + final String string = accessor.getString(); // Should always be UTC as no calendar is provided + + // Validate with UTC + Time time = accessor.getTime(null); + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + collector.checkThat(time.toString(), is(string)); + + // Validate with different TZ + TimeZone.setDefault(TimeZone.getTimeZone(AMERICA_VANCOUVER)); + collector.checkThat(time.toString(), not(string)); + + collector.checkThat(accessor.wasNull(), is(false)); + } finally { + // Set default Tz back + TimeZone.setDefault(defaultTz); + } + }); + } + private void assertGetStringIsConsistentWithVarCharAccessor(Calendar calendar) throws Exception { try (VarCharVector varCharVector = new VarCharVector("", rootAllocatorTestRule.getRootAllocator())) { From fdd4d163e798e39e17881c61cff6701f40c0f482 Mon Sep 17 00:00:00 2001 From: Vinicius Fraga Date: Thu, 10 Mar 2022 10:42:19 -0300 Subject: [PATCH 5/5] Check wasNull --- .../impl/calendar/ArrowFlightJdbcDateVectorAccessor.java | 3 +++ .../impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java index 019ddc2b13d..2a035efa1f6 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcDateVectorAccessor.java @@ -115,6 +115,9 @@ public Timestamp getTimestamp(Calendar calendar) { @Override public String getString() { fillHolder(); + if (wasNull) { + return null; + } long milliseconds = timeUnit.toMillis(holder.value); return unixDateToString((int) (milliseconds / MILLIS_PER_DAY)); } diff --git a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java index 0c22313a821..87aa4102327 100644 --- a/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java +++ b/java/flight/flight-jdbc-driver/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeVectorAccessor.java @@ -147,6 +147,9 @@ public Timestamp getTimestamp(Calendar calendar) { @Override public String getString() { fillHolder(); + if (wasNull) { + return null; + } long milliseconds = timeUnit.toMillis(holder.value); return unixTimeToString((int) (milliseconds % MILLIS_PER_DAY)); }