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]