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 1b3a51ab21 [arrow] Fix second-precision timestamp conversion for 
pre-epoch values (#9600)
1b3a51ab21 is described below

commit 1b3a51ab21c9ca5dc5ba57d63ca668504be81a6e
Author: Eunbin Son <[email protected]>
AuthorDate: Mon Sep 7 23:44:47 2026 +0900

    [arrow] Fix second-precision timestamp conversion for pre-epoch values 
(#9600)
---
 .../java/org/apache/paimon/arrow/ArrowUtils.java     |  2 +-
 .../paimon/arrow/vector/ArrowFormatWriterTest.java   | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/paimon-arrow/src/main/java/org/apache/paimon/arrow/ArrowUtils.java 
b/paimon-arrow/src/main/java/org/apache/paimon/arrow/ArrowUtils.java
index 92812bbeab..298180de6b 100644
--- a/paimon-arrow/src/main/java/org/apache/paimon/arrow/ArrowUtils.java
+++ b/paimon-arrow/src/main/java/org/apache/paimon/arrow/ArrowUtils.java
@@ -325,7 +325,7 @@ public class ArrowUtils {
 
     private static long nonCastedTimestampToEpoch(Timestamp timestamp, int 
precision) {
         if (precision == 0) {
-            return timestamp.getMillisecond() / 1000;
+            return Math.floorDiv(timestamp.getMillisecond(), 1000L);
         } else if (precision >= 1 && precision <= 3) {
             return timestamp.getMillisecond();
         } else if (precision >= 4 && precision <= 6) {
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 1742b836c2..a13f7ee9b2 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
@@ -163,6 +163,26 @@ public class ArrowFormatWriterTest {
         }
     }
 
+    @Test
+    public void testWritePreEpochSecondPrecisionTimestamp() {
+        RowType rowType =
+                RowType.of(DataTypes.TIMESTAMP(0), 
DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(0));
+        try (ArrowFormatWriter writer = new ArrowFormatWriter(rowType, 16, 
true)) {
+            // 1969-12-31T23:59:59.500, i.e. 500 millis before the epoch
+            Timestamp preEpoch = Timestamp.fromEpochMillis(-500);
+            writer.write(GenericRow.of(preEpoch, preEpoch));
+            writer.flush();
+
+            VectorSchemaRoot vectorSchemaRoot = writer.getVectorSchemaRoot();
+            ArrowBatchReader arrowBatchReader = new ArrowBatchReader(rowType, 
true);
+            InternalRow row = 
arrowBatchReader.readBatch(vectorSchemaRoot).iterator().next();
+
+            // sub-second millis must be truncated towards negative infinity, 
not towards zero
+            assertThat(row.getTimestamp(0, 
0).toString()).isEqualTo("1969-12-31T23:59:59");
+            assertThat(row.getTimestamp(1, 
0).toString()).isEqualTo("1969-12-31T23:59:59");
+        }
+    }
+
     @Test
     public void testMissingMapColumnVectorizedRoundTrip() {
         RowType inputRowType = RowType.builder().field("id", 
DataTypes.INT()).build();

Reply via email to