diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java index f17d9b62c..665e2dac2 100644 --- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java @@ -73,6 +73,9 @@ import org.apache.fesod.sheet.converters.shortconverter.ShortBooleanConverter; import org.apache.fesod.sheet.converters.shortconverter.ShortNumberConverter; import org.apache.fesod.sheet.converters.shortconverter.ShortStringConverter; +import org.apache.fesod.sheet.converters.sqldate.SqlDateDateConverter; +import org.apache.fesod.sheet.converters.sqldate.SqlDateNumberConverter; +import org.apache.fesod.sheet.converters.sqldate.SqlDateStringConverter; import org.apache.fesod.sheet.converters.string.StringBooleanConverter; import org.apache.fesod.sheet.converters.string.StringErrorConverter; import org.apache.fesod.sheet.converters.string.StringNumberConverter; @@ -142,6 +145,8 @@ private static void initAllConverter() { putAllConverter(new ShortBooleanConverter()); putAllConverter(new ShortNumberConverter()); putAllConverter(new ShortStringConverter()); + putAllConverter(new SqlDateNumberConverter()); + putAllConverter(new SqlDateStringConverter()); putAllConverter(new StringBooleanConverter()); putAllConverter(new StringNumberConverter()); @@ -157,6 +162,7 @@ private static void initDefaultWriteConverter() { putWriteConverter(new BooleanBooleanConverter()); putWriteConverter(new ByteNumberConverter()); putWriteConverter(new DateDateConverter()); + putWriteConverter(new SqlDateDateConverter()); putWriteConverter(new LocalDateTimeDateConverter()); putWriteConverter(new LocalDateDateConverter()); putWriteConverter(new LocalTimeDateConverter()); @@ -178,6 +184,7 @@ private static void initDefaultWriteConverter() { putWriteStringConverter(new BooleanStringConverter()); putWriteStringConverter(new ByteStringConverter()); putWriteStringConverter(new DateStringConverter()); + putWriteStringConverter(new SqlDateStringConverter()); putWriteStringConverter(new LocalDateStringConverter()); putWriteStringConverter(new LocalDateTimeStringConverter()); putWriteStringConverter(new LocalTimeStringConverter()); diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/sqldate/SqlDateDateConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/sqldate/SqlDateDateConverter.java new file mode 100644 index 000000000..bb9f1ca85 --- /dev/null +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/sqldate/SqlDateDateConverter.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fesod.sheet.converters.sqldate; + +import java.sql.Date; +import org.apache.fesod.sheet.converters.Converter; +import org.apache.fesod.sheet.metadata.GlobalConfiguration; +import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; +import org.apache.fesod.sheet.util.DateUtils; +import org.apache.fesod.sheet.util.WorkBookUtil; + +/** + * Converter for {@link java.sql.Date} and Excel date cells. + */ +public class SqlDateDateConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return Date.class; + } + + @Override + public WriteCellData convertToExcelData( + Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) + throws Exception { + WriteCellData cellData = new WriteCellData<>(value); + String format = null; + if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) { + format = contentProperty.getDateTimeFormatProperty().getFormat(); + } + WorkBookUtil.fillDataFormat(cellData, format, DateUtils.defaultDateFormat); + return cellData; + } +} diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/sqldate/SqlDateNumberConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/sqldate/SqlDateNumberConverter.java new file mode 100644 index 000000000..f2a524e7e --- /dev/null +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/sqldate/SqlDateNumberConverter.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fesod.sheet.converters.sqldate; + +import java.math.BigDecimal; +import java.sql.Date; +import java.time.LocalDate; + +import org.apache.fesod.sheet.converters.Converter; +import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.metadata.GlobalConfiguration; +import org.apache.fesod.sheet.metadata.data.ReadCellData; +import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; +import org.apache.fesod.sheet.util.DateUtils; +import org.apache.poi.ss.usermodel.DateUtil; + +/** + * Converter for {@link java.sql.Date} and Excel number cells. + */ +public class SqlDateNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Date.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public Date convertToJavaData( + ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + LocalDate localDate = DateUtils.getLocalDate( + cellData.getNumberValue().doubleValue(), + DateUtils.isDate1904(contentProperty, globalConfiguration)); + + return localDate == null ? null : Date.valueOf(localDate); + } + + @Override + public WriteCellData convertToExcelData( + Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return new WriteCellData<>(BigDecimal.valueOf( + DateUtil.getExcelDate(value, DateUtils.isDate1904(contentProperty, globalConfiguration)))); + } +} diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/sqldate/SqlDateStringConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/sqldate/SqlDateStringConverter.java new file mode 100644 index 000000000..eaf4807bd --- /dev/null +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/sqldate/SqlDateStringConverter.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fesod.sheet.converters.sqldate; + +import java.sql.Date; +import java.text.ParseException; +import org.apache.fesod.sheet.converters.Converter; +import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.metadata.GlobalConfiguration; +import org.apache.fesod.sheet.metadata.data.ReadCellData; +import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; +import org.apache.fesod.sheet.util.DateUtils; + +/** + * Converter for {@link java.sql.Date} and Excel string cells. + */ +public class SqlDateStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return Date.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Date convertToJavaData( + ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) + throws ParseException { + java.util.Date date; + + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { + date = DateUtils.parseDate(cellData.getStringValue(), null); + } else { + date = DateUtils.parseDate( + cellData.getStringValue(), + contentProperty.getDateTimeFormatProperty().getFormat()); + } + + return new Date(date.getTime()); + } + + @Override + public WriteCellData convertToExcelData( + Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { + return new WriteCellData<>(DateUtils.format(value, null)); + } else { + return new WriteCellData<>(DateUtils.format( + value, contentProperty.getDateTimeFormatProperty().getFormat())); + } + } +} diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/sqldate/SqlDateConverterTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/sqldate/SqlDateConverterTest.java new file mode 100644 index 000000000..2df9f1e0f --- /dev/null +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converters/sqldate/SqlDateConverterTest.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fesod.sheet.converters.sqldate; + +import java.math.BigDecimal; +import java.sql.Date; +import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.metadata.GlobalConfiguration; +import org.apache.fesod.sheet.metadata.data.ReadCellData; +import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.metadata.property.DateTimeFormatProperty; +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; +import org.apache.fesod.sheet.testkit.Tags; +import org.apache.fesod.sheet.util.DateUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +/** + * Tests SQL date converters. + */ +@Tag(Tags.UNIT) +class SqlDateConverterTest { + + @AfterEach + void tearDown() { + DateUtils.removeThreadLocalCache(); + } + + @Test + void dateConverterSupportsSqlDate() { + SqlDateDateConverter converter = new SqlDateDateConverter(); + + Assertions.assertEquals(Date.class, converter.supportJavaTypeKey()); + } + + @Test + void dateConverterConvertsToExcelData() throws Exception { + SqlDateDateConverter converter = new SqlDateDateConverter(); + ExcelContentProperty contentProperty = contentProperty("yyyy-MM-dd"); + Date value = Date.valueOf("2026-09-06"); + + WriteCellData actual = converter.convertToExcelData(value, contentProperty, new GlobalConfiguration()); + + Assertions.assertEquals(value.toLocalDate().atStartOfDay(), actual.getDateValue()); + } + + @Test + void numberConverterConvertsToJavaData() { + SqlDateNumberConverter converter = new SqlDateNumberConverter(); + ReadCellData cellData = new ReadCellData<>(BigDecimal.ONE); + + Date actual = converter.convertToJavaData(cellData, null, new GlobalConfiguration()); + + Assertions.assertNotNull(actual); + Assertions.assertEquals(Date.class, actual.getClass()); + Assertions.assertEquals(CellDataTypeEnum.NUMBER, converter.supportExcelTypeKey()); + } + + @Test + void numberConverterUses1904Windowing() { + SqlDateNumberConverter converter = new SqlDateNumberConverter(); + GlobalConfiguration configuration = new GlobalConfiguration(); + configuration.setUse1904windowing(Boolean.TRUE); + ReadCellData cellData = new ReadCellData<>(BigDecimal.ONE); + + Date actual = converter.convertToJavaData(cellData, null, configuration); + + Assertions.assertEquals(new Date(DateUtils.getJavaDate(1, true).getTime()), actual); + } + + @Test + void numberConverterPrefersExplicitWindowingOverGlobal() { + SqlDateNumberConverter converter = new SqlDateNumberConverter(); + GlobalConfiguration configuration = new GlobalConfiguration(); + configuration.setUse1904windowing(Boolean.TRUE); + ExcelContentProperty contentProperty = contentProperty("yyyy-MM-dd", Boolean.FALSE); + + Date actual = converter.convertToJavaData(new ReadCellData<>(BigDecimal.ONE), contentProperty, configuration); + + Assertions.assertEquals(new Date(DateUtils.getJavaDate(1, false).getTime()), actual); + } + + @Test + void stringConverterConvertsToJavaData() throws Exception { + SqlDateStringConverter converter = new SqlDateStringConverter(); + ExcelContentProperty contentProperty = contentProperty("yyyy-MM-dd"); + ReadCellData cellData = new ReadCellData<>("2026-09-06"); + + Date actual = converter.convertToJavaData(cellData, contentProperty, new GlobalConfiguration()); + + Assertions.assertEquals(Date.valueOf("2026-09-06"), actual); + Assertions.assertEquals(CellDataTypeEnum.STRING, converter.supportExcelTypeKey()); + } + + @Test + void stringConverterConvertsToExcelData() { + SqlDateStringConverter converter = new SqlDateStringConverter(); + ExcelContentProperty contentProperty = contentProperty("yyyy-MM-dd"); + + WriteCellData actual = + converter.convertToExcelData(Date.valueOf("2026-09-06"), contentProperty, new GlobalConfiguration()); + + Assertions.assertEquals("2026-09-06", actual.getStringValue()); + } + + private static ExcelContentProperty contentProperty(String format) { + return contentProperty(format, null); + } + + private static ExcelContentProperty contentProperty(String format, Boolean use1904windowing) { + ExcelContentProperty contentProperty = new ExcelContentProperty(); + contentProperty.setDateTimeFormatProperty(new DateTimeFormatProperty(format, use1904windowing)); + return contentProperty; + } +}