This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 30d26952b0 [arrow] Fix nanosecond timestamp conversion for pre-epoch 
values (#9299)
30d26952b0 is described below

commit 30d26952b0e6c0e21850f300bde5dafa750306fd
Author: jackylee <[email protected]>
AuthorDate: Thu Aug 20 09:44:10 2026 +0800

    [arrow] Fix nanosecond timestamp conversion for pre-epoch values (#9299)
---
 .../converter/Arrow2PaimonVectorConverter.java     |  3 +-
 .../paimon/arrow/vector/ArrowFormatWriterTest.java | 39 ++++++++++++++++++++++
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git 
a/paimon-arrow/src/main/java/org/apache/paimon/arrow/converter/Arrow2PaimonVectorConverter.java
 
b/paimon-arrow/src/main/java/org/apache/paimon/arrow/converter/Arrow2PaimonVectorConverter.java
index e3a9a53d51..4ce6871809 100644
--- 
a/paimon-arrow/src/main/java/org/apache/paimon/arrow/converter/Arrow2PaimonVectorConverter.java
+++ 
b/paimon-arrow/src/main/java/org/apache/paimon/arrow/converter/Arrow2PaimonVectorConverter.java
@@ -462,7 +462,8 @@ public interface Arrow2PaimonVectorConverter {
             } else if (precision >= 4 && precision <= 6) {
                 return Timestamp.fromMicros(value);
             } else {
-                return Timestamp.fromEpochMillis(value / 1_000_000, (int) 
(value % 1_000_000));
+                return Timestamp.fromEpochMillis(
+                        Math.floorDiv(value, 1_000_000L), (int) 
Math.floorMod(value, 1_000_000L));
             }
         }
 
diff --git 
a/paimon-arrow/src/test/java/org/apache/paimon/arrow/vector/ArrowFormatWriterTest.java
 
b/paimon-arrow/src/test/java/org/apache/paimon/arrow/vector/ArrowFormatWriterTest.java
index fd257450aa..d8cfd8fde9 100644
--- 
a/paimon-arrow/src/test/java/org/apache/paimon/arrow/vector/ArrowFormatWriterTest.java
+++ 
b/paimon-arrow/src/test/java/org/apache/paimon/arrow/vector/ArrowFormatWriterTest.java
@@ -53,6 +53,8 @@ import org.apache.arrow.vector.IntVector;
 import org.apache.arrow.vector.TimeMicroVector;
 import org.apache.arrow.vector.TimeNanoVector;
 import org.apache.arrow.vector.TimeSecVector;
+import org.apache.arrow.vector.TimeStampNanoTZVector;
+import org.apache.arrow.vector.TimeStampNanoVector;
 import org.apache.arrow.vector.VarBinaryVector;
 import org.apache.arrow.vector.VarCharVector;
 import org.apache.arrow.vector.VectorSchemaRoot;
@@ -587,6 +589,43 @@ public class ArrowFormatWriterTest {
         }
     }
 
+    @Test
+    public void testArrowBundleRecordsWithPreEpochNanoTimestamps() {
+        RowType rowType =
+                RowType.of(
+                        new DataField(0, "ts_nano", DataTypes.TIMESTAMP(9)),
+                        new DataField(
+                                1, "ts_ltz_nano", 
DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(9)));
+
+        // 1969-12-31T23:59:59.999999999, i.e. one nanosecond before the epoch
+        long nanos = -1L;
+
+        try (RootAllocator allocator = new RootAllocator()) {
+            TimeStampNanoVector tsVector = new TimeStampNanoVector("ts_nano", 
allocator);
+            tsVector.allocateNew(1);
+            tsVector.setSafe(0, nanos);
+            tsVector.setValueCount(1);
+
+            TimeStampNanoTZVector tsLtzVector =
+                    new TimeStampNanoTZVector("ts_ltz_nano", allocator, "UTC");
+            tsLtzVector.allocateNew(1);
+            tsLtzVector.setSafe(0, nanos);
+            tsLtzVector.setValueCount(1);
+
+            List<FieldVector> vectors = Arrays.asList(tsVector, tsLtzVector);
+            try (VectorSchemaRoot vectorSchemaRoot = new 
VectorSchemaRoot(vectors)) {
+                vectorSchemaRoot.setRowCount(1);
+
+                Iterator<InternalRow> iterator =
+                        new ArrowBundleRecords(vectorSchemaRoot, rowType, 
true).iterator();
+                InternalRow row = iterator.next();
+                Timestamp expected = Timestamp.fromEpochMillis(-1, 999_999);
+                assertThat(row.getTimestamp(0, 9)).isEqualTo(expected);
+                assertThat(row.getTimestamp(1, 9)).isEqualTo(expected);
+            }
+        }
+    }
+
     @Test
     public void testCWriter() {
         try (ArrowFormatCWriter writer = new 
ArrowFormatCWriter(PRIMITIVE_TYPE, 4096, true)) {

Reply via email to