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

delei pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fesod.git


The following commit(s) were added to refs/heads/main by this push:
     new f688ba9c fix: CsvCell crashes on java.sql.Date/Time due to unsupported 
toInstant() (#954)
f688ba9c is described below

commit f688ba9c49cb632193cd603fc031169eccb2a354
Author: ian zhang <[email protected]>
AuthorDate: Sat Jul 25 21:01:08 2026 +0800

    fix: CsvCell crashes on java.sql.Date/Time due to unsupported toInstant() 
(#954)
---
 .../apache/fesod/sheet/metadata/csv/CsvCell.java   |  9 ++-
 .../fesod/sheet/metadata/data/WriteCellData.java   |  3 +-
 .../org/apache/fesod/sheet/util/DateUtils.java     |  6 ++
 .../org/apache/fesod/sheet/format/CsvRowTest.java  | 88 ++++++++++++++++++++++
 4 files changed, 104 insertions(+), 2 deletions(-)

diff --git 
a/fesod-sheet/src/main/java/org/apache/fesod/sheet/metadata/csv/CsvCell.java 
b/fesod-sheet/src/main/java/org/apache/fesod/sheet/metadata/csv/CsvCell.java
index 740f1f26..cd6e8e7c 100644
--- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/metadata/csv/CsvCell.java
+++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/metadata/csv/CsvCell.java
@@ -36,6 +36,7 @@ import lombok.Getter;
 import lombok.Setter;
 import org.apache.fesod.sheet.enums.NumericCellTypeEnum;
 import org.apache.fesod.sheet.metadata.data.FormulaData;
+import org.apache.fesod.sheet.util.DateUtils;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.ss.usermodel.CellBase;
 import org.apache.poi.ss.usermodel.CellStyle;
@@ -164,7 +165,13 @@ public class CsvCell extends CellBase {
         if (value == null) {
             return;
         }
-        this.dateValue = LocalDateTime.ofInstant(value.toInstant(), 
ZoneId.systemDefault());
+        if (value instanceof java.sql.Date) {
+            this.dateValue = ((java.sql.Date) 
value).toLocalDate().atStartOfDay();
+        } else if (value instanceof java.sql.Time) {
+            this.dateValue = ((java.sql.Time) 
value).toLocalTime().atDate(DateUtils.EPOCH);
+        } else {
+            this.dateValue = LocalDateTime.ofInstant(value.toInstant(), 
ZoneId.systemDefault());
+        }
         this.cellType = CellType.NUMERIC;
         this.numericCellType = NumericCellTypeEnum.DATE;
     }
diff --git 
a/fesod-sheet/src/main/java/org/apache/fesod/sheet/metadata/data/WriteCellData.java
 
b/fesod-sheet/src/main/java/org/apache/fesod/sheet/metadata/data/WriteCellData.java
index 0985423f..c326907f 100644
--- 
a/fesod-sheet/src/main/java/org/apache/fesod/sheet/metadata/data/WriteCellData.java
+++ 
b/fesod-sheet/src/main/java/org/apache/fesod/sheet/metadata/data/WriteCellData.java
@@ -36,6 +36,7 @@ import lombok.NoArgsConstructor;
 import lombok.Setter;
 import org.apache.fesod.common.util.ListUtils;
 import org.apache.fesod.sheet.enums.CellDataTypeEnum;
+import org.apache.fesod.sheet.util.DateUtils;
 import org.apache.fesod.sheet.write.metadata.style.WriteCellStyle;
 import org.apache.poi.ss.usermodel.CellStyle;
 
@@ -172,7 +173,7 @@ public class WriteCellData<T> extends CellData<T> {
         if (dateValue instanceof java.sql.Date) {
             this.dateValue = ((java.sql.Date) 
dateValue).toLocalDate().atStartOfDay();
         } else if (dateValue instanceof java.sql.Time) {
-            this.dateValue = ((java.sql.Time) 
dateValue).toLocalTime().atDate(java.time.LocalDate.of(1970, 1, 1));
+            this.dateValue = ((java.sql.Time) 
dateValue).toLocalTime().atDate(DateUtils.EPOCH);
         } else {
             this.dateValue = LocalDateTime.ofInstant(dateValue.toInstant(), 
ZoneId.systemDefault());
         }
diff --git 
a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java 
b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java
index 53a70c1b..895f6dce 100644
--- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java
+++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/DateUtils.java
@@ -87,6 +87,12 @@ public class DateUtils {
     // for format which start with "年" or "月" or "日" or "时" or "分" or "秒" 
could be a Chinese date
     private static final Pattern date_ptrn6 = 
Pattern.compile("(年|月|日|时|分|秒)+");
 
+    /**
+     * The epoch date (1970-01-01) used as the date component when converting
+     * {@code java.sql.Time} to {@code LocalDateTime}.
+     */
+    public static final LocalDate EPOCH = LocalDate.of(1970, 1, 1);
+
     public static final String DATE_FORMAT_10 = "yyyy-MM-dd";
     public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss";
     public static final String DATE_FORMAT_16 = "yyyy-MM-dd HH:mm";
diff --git 
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/format/CsvRowTest.java 
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/format/CsvRowTest.java
index 2af4a1b7..0130e78a 100644
--- a/fesod-sheet/src/test/java/org/apache/fesod/sheet/format/CsvRowTest.java
+++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/format/CsvRowTest.java
@@ -20,14 +20,20 @@
 package org.apache.fesod.sheet.format;
 
 import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.List;
 import org.apache.fesod.sheet.FastExcel;
+import org.apache.fesod.sheet.metadata.csv.CsvCell;
 import org.apache.fesod.sheet.metadata.csv.CsvRow;
 import org.apache.fesod.sheet.metadata.csv.CsvSheet;
 import org.apache.fesod.sheet.metadata.csv.CsvWorkbook;
 import org.apache.fesod.sheet.testkit.Tags;
+import org.apache.fesod.sheet.util.DateUtils;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellType;
 import org.junit.jupiter.api.Assertions;
@@ -120,6 +126,88 @@ public class CsvRowTest {
                 .doWrite(modelData());
     }
 
+    /**
+     * Verifies that {@link CsvCell} handles {@link java.sql.Date} the same 
way as
+     * {@link org.apache.fesod.sheet.metadata.data.WriteCellData}: the date is 
extracted
+     * via {@code toLocalDate().atStartOfDay()}, stripping any time component 
that may
+     * exist in the underlying milliseconds (common when JDBC drivers create
+     * {@code java.sql.Date} from a {@code java.util.Date} with time info).
+     */
+    @Test
+    void testCsvCellSqlDateConversion() {
+        // Create a java.sql.Date from a java.util.Date that has a time 
component
+        Calendar cal = Calendar.getInstance();
+        cal.set(2023, Calendar.JUNE, 15, 23, 30, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        java.sql.Date sqlDate = new java.sql.Date(cal.getTimeInMillis());
+
+        Cell cell = csvRow.createCell(0, CellType.NUMERIC);
+        cell.setCellValue(sqlDate);
+
+        LocalDateTime dateValue = ((CsvCell) cell).getLocalDateTimeCellValue();
+        // java.sql.Date is date-only: derive expected value from sqlDate 
itself to avoid timezone sensitivity
+        Assertions.assertEquals(sqlDate.toLocalDate().atStartOfDay(), 
dateValue);
+    }
+
+    /**
+     * Verifies that {@link CsvCell} handles {@link java.sql.Time} the same 
way as
+     * {@link org.apache.fesod.sheet.metadata.data.WriteCellData}: the time is 
extracted
+     * via {@code toLocalTime().atDate(DateUtils.EPOCH)}, stripping any date
+     * component that may exist in the underlying milliseconds.
+     */
+    @Test
+    void testCsvCellSqlTimeConversion() {
+        // Create a java.sql.Time from a java.util.Date that has a date 
component
+        Calendar cal = Calendar.getInstance();
+        cal.set(2023, Calendar.JUNE, 15, 12, 30, 45);
+        cal.set(Calendar.MILLISECOND, 0);
+        java.sql.Time sqlTime = new java.sql.Time(cal.getTimeInMillis());
+
+        Cell cell = csvRow.createCell(0, CellType.NUMERIC);
+        cell.setCellValue(sqlTime);
+
+        LocalDateTime dateValue = ((CsvCell) cell).getLocalDateTimeCellValue();
+        // java.sql.Time is time-only: derive expected value from sqlTime 
itself to avoid timezone sensitivity
+        Assertions.assertEquals(sqlTime.toLocalTime().atDate(DateUtils.EPOCH), 
dateValue);
+    }
+
+    /**
+     * Real-file integration test: writes a physical CSV file containing
+     * {@code java.sql.Date} and {@code java.sql.Time} values via the
+     * {@link CsvCell} API, then reads the file back to verify the output.
+     * <p>
+     * Without the fix, {@code CsvCell.setCellValueImpl(Date)} calls
+     * {@code value.toInstant()} which throws {@code 
UnsupportedOperationException}
+     * on Java 9+ for {@code java.sql.Date}/{@code java.sql.Time}.
+     */
+    @Test
+    void csvWrite_withSqlDateAndTime_producesCorrectFile() throws Exception {
+        File csvFile = new File(tempDir, "sql-date-test.csv");
+
+        try (java.io.Writer writer = Files.newBufferedWriter(csvFile.toPath(), 
StandardCharsets.UTF_8)) {
+            CsvWorkbook workbook = new CsvWorkbook(writer, null, false, false, 
StandardCharsets.UTF_8, false);
+            CsvSheet sheet = (CsvSheet) workbook.createSheet();
+            CsvRow row = (CsvRow) sheet.createRow(0);
+
+            // java.sql.Date — without fix: UnsupportedOperationException
+            Cell dateCell = row.createCell(0, CellType.NUMERIC);
+            dateCell.setCellValue(java.sql.Date.valueOf("2024-01-15"));
+
+            // java.sql.Time — without fix: UnsupportedOperationException
+            Cell timeCell = row.createCell(1, CellType.NUMERIC);
+            timeCell.setCellValue(java.sql.Time.valueOf("12:30:45"));
+
+            sheet.close();
+        }
+
+        // Read file back and verify date/time strings
+        List<String> lines = Files.readAllLines(csvFile.toPath(), 
StandardCharsets.UTF_8);
+        Assertions.assertEquals(1, lines.size());
+        String line = lines.get(0);
+        Assertions.assertTrue(line.contains("2024-01-15"), "CSV should contain 
date 2024-01-15, got: " + line);
+        Assertions.assertTrue(line.contains("12:30:45"), "CSV should contain 
time 12:30:45, got: " + line);
+    }
+
     private static List<SimpleCsvData> modelData() {
         List<SimpleCsvData> data = new ArrayList<>();
         data.add(new SimpleCsvData("1", "Jackson", "20"));


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to