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 501e33211e [common] Fix DateTimeUtils.truncate dropping sub-precision
fractional seconds (#8767)
501e33211e is described below
commit 501e33211ec6a427ffd4d2046e8cd141845a43fc
Author: Eunbin Son <[email protected]>
AuthorDate: Tue Jul 21 14:16:37 2026 +0900
[common] Fix DateTimeUtils.truncate dropping sub-precision fractional
seconds (#8767)
---
.../org/apache/paimon/utils/DateTimeUtils.java | 10 +++++--
.../org/apache/paimon/utils/DateTimeUtilsTest.java | 34 ++++++++++++++++++++++
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git
a/paimon-common/src/main/java/org/apache/paimon/utils/DateTimeUtils.java
b/paimon-common/src/main/java/org/apache/paimon/utils/DateTimeUtils.java
index e8b57caf1d..90c6d447f5 100644
--- a/paimon-common/src/main/java/org/apache/paimon/utils/DateTimeUtils.java
+++ b/paimon-common/src/main/java/org/apache/paimon/utils/DateTimeUtils.java
@@ -649,8 +649,14 @@ public class DateTimeUtils {
}
public static Timestamp truncate(Timestamp ts, int precision) {
- String fraction = Integer.toString(ts.toLocalDateTime().getNano());
- if (fraction.length() <= precision) {
+ // Pad to 9 digits so leading zeros are preserved, then count the
significant
+ // fractional digits by stripping trailing zeros (same approach as
formatTimestamp).
+ String fraction = pad(9, ts.toLocalDateTime().getNano());
+ int significant = fraction.length();
+ while (significant > 0 && fraction.charAt(significant - 1) == '0') {
+ significant--;
+ }
+ if (significant <= precision) {
return ts;
} else {
// need to truncate
diff --git
a/paimon-common/src/test/java/org/apache/paimon/utils/DateTimeUtilsTest.java
b/paimon-common/src/test/java/org/apache/paimon/utils/DateTimeUtilsTest.java
index 61cc0ac8f8..cbc8267e42 100644
--- a/paimon-common/src/test/java/org/apache/paimon/utils/DateTimeUtilsTest.java
+++ b/paimon-common/src/test/java/org/apache/paimon/utils/DateTimeUtilsTest.java
@@ -99,4 +99,38 @@ public class DateTimeUtilsTest {
TimeZone.setDefault(timeZone);
}
}
+
+ @Test
+ public void testTruncateDropsSubPrecisionFraction() {
+ // A fractional second below 0.1s has leading zeros in its nano
representation.
+ // The narrowing cast to precision 3 must drop all nanoseconds below
the millisecond.
+ Timestamp nineNanos =
Timestamp.fromLocalDateTime(LocalDateTime.of(1970, 1, 1, 0, 0, 0, 9));
+ assertThat(nineNanos.toLocalDateTime().getNano()).isEqualTo(9);
+ assertThat(DateTimeUtils.truncate(nineNanos,
3).toLocalDateTime().getNano()).isEqualTo(0);
+
+ // Truncating .000123456 to precision 6 must keep exactly 6 fractional
digits (.000123).
+ Timestamp micros =
+ Timestamp.fromLocalDateTime(LocalDateTime.of(1970, 1, 1, 0, 0,
0, 123_456));
+ assertThat(micros.toLocalDateTime().getNano()).isEqualTo(123_456);
+ assertThat(DateTimeUtils.truncate(micros,
6).toLocalDateTime().getNano())
+ .isEqualTo(123_000);
+ }
+
+ @Test
+ public void testTruncateIsIdempotent() {
+ // An already-truncated value stays unchanged when truncated again to
the same precision.
+ Timestamp truncated =
+ Timestamp.fromLocalDateTime(LocalDateTime.of(1970, 1, 1, 0, 0,
0, 123_000));
+ assertThat(DateTimeUtils.truncate(truncated,
6).toLocalDateTime().getNano())
+ .isEqualTo(123_000);
+ }
+
+ @Test
+ public void testTruncateNoOpAtMaxPrecision() {
+ // Precision 9 preserves all nanoseconds.
+ Timestamp full =
+ Timestamp.fromLocalDateTime(LocalDateTime.of(1970, 1, 1, 0, 0,
0, 123_456_789));
+ assertThat(DateTimeUtils.truncate(full, 9).toLocalDateTime().getNano())
+ .isEqualTo(123_456_789);
+ }
}