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..7d1c765d0 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 @@ -70,6 +70,9 @@ import org.apache.fesod.sheet.converters.longconverter.LongBooleanConverter; import org.apache.fesod.sheet.converters.longconverter.LongNumberConverter; import org.apache.fesod.sheet.converters.longconverter.LongStringConverter; +import org.apache.fesod.sheet.converters.offsetdatetime.OffsetDateTimeDateConverter; +import org.apache.fesod.sheet.converters.offsetdatetime.OffsetDateTimeNumberConverter; +import org.apache.fesod.sheet.converters.offsetdatetime.OffsetDateTimeStringConverter; import org.apache.fesod.sheet.converters.shortconverter.ShortBooleanConverter; import org.apache.fesod.sheet.converters.shortconverter.ShortNumberConverter; import org.apache.fesod.sheet.converters.shortconverter.ShortStringConverter; @@ -122,6 +125,8 @@ private static void initAllConverter() { putAllConverter(new LocalTimeNumberConverter()); putAllConverter(new LocalTimeStringConverter()); + putAllConverter(new OffsetDateTimeNumberConverter()); + putAllConverter(new OffsetDateTimeStringConverter()); putAllConverter(new DoubleBooleanConverter()); putAllConverter(new DoubleNumberConverter()); @@ -160,6 +165,7 @@ private static void initDefaultWriteConverter() { putWriteConverter(new LocalDateTimeDateConverter()); putWriteConverter(new LocalDateDateConverter()); putWriteConverter(new LocalTimeDateConverter()); + putWriteConverter(new OffsetDateTimeDateConverter()); putWriteConverter(new DoubleNumberConverter()); putWriteConverter(new FloatNumberConverter()); putWriteConverter(new IntegerNumberConverter()); @@ -181,6 +187,7 @@ private static void initDefaultWriteConverter() { putWriteStringConverter(new LocalDateStringConverter()); putWriteStringConverter(new LocalDateTimeStringConverter()); putWriteStringConverter(new LocalTimeStringConverter()); + putWriteStringConverter(new OffsetDateTimeStringConverter()); putWriteStringConverter(new DoubleStringConverter()); putWriteStringConverter(new FloatStringConverter()); putWriteStringConverter(new IntegerStringConverter()); diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/offsetdatetime/OffsetDateTimeDateConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/offsetdatetime/OffsetDateTimeDateConverter.java new file mode 100644 index 000000000..940f38162 --- /dev/null +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/offsetdatetime/OffsetDateTimeDateConverter.java @@ -0,0 +1,55 @@ +/* + * 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.offsetdatetime; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import org.apache.fesod.common.util.StringUtils; +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; + +/** OffsetDateTime and date converter. */ +public class OffsetDateTimeDateConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return OffsetDateTime.class; + } + + @Override + public WriteCellData convertToExcelData( + OffsetDateTime value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) + throws Exception { + LocalDateTime localDateTime = value.toLocalDateTime(); + WriteCellData cellData = new WriteCellData<>(localDateTime); + String format = null; + if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) { + format = contentProperty.getDateTimeFormatProperty().getFormat(); + if (StringUtils.isEmpty(format)) { + format = null; + } + } + WorkBookUtil.fillDataFormat(cellData, format, DateUtils.defaultDateFormat); + return cellData; + } +} diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/offsetdatetime/OffsetDateTimeNumberConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/offsetdatetime/OffsetDateTimeNumberConverter.java new file mode 100644 index 000000000..d08856300 --- /dev/null +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/offsetdatetime/OffsetDateTimeNumberConverter.java @@ -0,0 +1,64 @@ +/* + * 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.offsetdatetime; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +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; + +/** OffsetDateTime and number converter. */ +public class OffsetDateTimeNumberConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return OffsetDateTime.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public OffsetDateTime convertToJavaData( + ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + LocalDateTime localDateTime = DateUtils.getLocalDateTime( + cellData.getNumberValue().doubleValue(), DateUtils.isDate1904(contentProperty, globalConfiguration)); + if (localDateTime == null) { + return null; + } + return localDateTime.atZone(ZoneId.systemDefault()).toOffsetDateTime(); + } + + @Override + public WriteCellData convertToExcelData( + OffsetDateTime value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return new WriteCellData<>(BigDecimal.valueOf(DateUtil.getExcelDate( + value.toLocalDateTime(), DateUtils.isDate1904(contentProperty, globalConfiguration)))); + } +} diff --git a/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/offsetdatetime/OffsetDateTimeStringConverter.java b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/offsetdatetime/OffsetDateTimeStringConverter.java new file mode 100644 index 000000000..e7e10dde1 --- /dev/null +++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/offsetdatetime/OffsetDateTimeStringConverter.java @@ -0,0 +1,62 @@ +/* + * 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.offsetdatetime; + +import java.time.OffsetDateTime; +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; + +/** OffsetDateTime and string converter. */ +public class OffsetDateTimeStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return OffsetDateTime.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public OffsetDateTime convertToJavaData( + ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return DateUtils.parseOffsetDateTime( + cellData.getStringValue(), format(contentProperty), globalConfiguration.getLocale()); + } + + @Override + public WriteCellData convertToExcelData( + OffsetDateTime value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return new WriteCellData<>(DateUtils.format(value, format(contentProperty), globalConfiguration.getLocale())); + } + + private String format(ExcelContentProperty contentProperty) { + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { + return null; + } + return contentProperty.getDateTimeFormatProperty().getFormat(); + } +} 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 9fd5365a1..8839dacbe 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 @@ -32,6 +32,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.Date; @@ -164,6 +165,21 @@ public static LocalTime parseLocalTime(String timeString, String timeFormat, Loc return LocalTime.parse(timeString, getCacheDateTimeFormat(timeFormat, local)); } + /** + * convert string to date, requiring the string to carry an explicit offset + * + * @param dateString date string, e.g. 2020-01-02T03:04:05+08:00 + * @param dateFormat date format, empty means ISO_OFFSET_DATE_TIME + * @param local local + * @return + */ + public static OffsetDateTime parseOffsetDateTime(String dateString, String dateFormat, Locale local) { + if (StringUtils.isEmpty(dateFormat)) { + return OffsetDateTime.parse(dateString, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + return OffsetDateTime.parse(dateString, getCacheDateTimeFormat(dateFormat, local)); + } + /** * convert string to date * @@ -328,6 +344,24 @@ public static String format(LocalTime time, String timeFormat, Locale local) { return time.format(getCacheDateTimeFormat(timeFormat, local)); } + /** + * Format date, preserving the offset in the output + * + * @param date date + * @param dateFormat date format, empty means ISO_OFFSET_DATE_TIME + * @param local local + * @return format string + */ + public static String format(OffsetDateTime date, String dateFormat, Locale local) { + if (date == null) { + return null; + } + if (StringUtils.isEmpty(dateFormat)) { + return date.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + return date.format(getCacheDateTimeFormat(dateFormat, local)); + } + /** * Format date * diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/converter/OffsetDateTimeConverterTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converter/OffsetDateTimeConverterTest.java new file mode 100644 index 000000000..11d665a49 --- /dev/null +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/converter/OffsetDateTimeConverterTest.java @@ -0,0 +1,228 @@ +/* + * 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.converter; + +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeParseException; +import java.util.Locale; +import org.apache.fesod.sheet.converters.ConverterKeyBuild; +import org.apache.fesod.sheet.converters.DefaultConverterLoader; +import org.apache.fesod.sheet.converters.offsetdatetime.OffsetDateTimeDateConverter; +import org.apache.fesod.sheet.converters.offsetdatetime.OffsetDateTimeNumberConverter; +import org.apache.fesod.sheet.converters.offsetdatetime.OffsetDateTimeStringConverter; +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; + +@Tag(Tags.UNIT) +class OffsetDateTimeConverterTest { + private static final OffsetDateTime VALUE = OffsetDateTime.of(2020, 1, 2, 3, 4, 5, 0, ZoneOffset.ofHours(8)); + + @AfterEach + void tearDown() { + DateUtils.removeThreadLocalCache(); + } + + @Test + void dateConverterDropsOffsetWhilePreservingLocalDateTime() throws Exception { + WriteCellData result = + new OffsetDateTimeDateConverter().convertToExcelData(VALUE, null, new GlobalConfiguration()); + Assertions.assertEquals(CellDataTypeEnum.DATE, result.getType()); + Assertions.assertEquals(VALUE.toLocalDateTime(), result.getDateValue()); + } + + @Test + void numberConverterDropsOffsetWhilePreservingLocalDateTime() { + OffsetDateTimeNumberConverter converter = new OffsetDateTimeNumberConverter(); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + WriteCellData written = converter.convertToExcelData(VALUE, null, globalConfiguration); + OffsetDateTime read = + converter.convertToJavaData(new ReadCellData<>(written.getNumberValue()), null, globalConfiguration); + Assertions.assertEquals( + VALUE.toLocalDateTime().atZone(ZoneId.systemDefault()).toOffsetDateTime(), read); + } + + @Test + void stringConverterPreservesOffsetInIsoText() throws Exception { + OffsetDateTimeStringConverter converter = new OffsetDateTimeStringConverter(); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + WriteCellData written = converter.convertToExcelData(VALUE, null, globalConfiguration); + Assertions.assertEquals( + VALUE, + converter.convertToJavaData(new ReadCellData<>(written.getStringValue()), null, globalConfiguration)); + } + + @Test + void stringConverterUsesConfiguredPattern() throws Exception { + OffsetDateTimeStringConverter converter = new OffsetDateTimeStringConverter(); + ExcelContentProperty property = new ExcelContentProperty(); + property.setDateTimeFormatProperty(new DateTimeFormatProperty("yyyy-MM-dd HH:mm:ss Z", false)); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + Assertions.assertEquals( + "2020-01-02 03:04:05 +0800", + converter + .convertToExcelData(VALUE, property, globalConfiguration) + .getStringValue()); + } + + @Test + void stringConverterRejectsTextWithoutOffset() { + OffsetDateTimeStringConverter converter = new OffsetDateTimeStringConverter(); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + Assertions.assertThrows( + DateTimeParseException.class, + () -> converter.convertToJavaData( + new ReadCellData<>("2020-01-02T03:04:05"), null, globalConfiguration)); + Assertions.assertThrows( + DateTimeParseException.class, + () -> converter.convertToJavaData( + new ReadCellData<>("2020-01-02 03:04:05"), null, globalConfiguration)); + } + + @Test + void stringConverterRejectsTextNotMatchingConfiguredPattern() { + OffsetDateTimeStringConverter converter = new OffsetDateTimeStringConverter(); + ExcelContentProperty property = new ExcelContentProperty(); + property.setDateTimeFormatProperty(new DateTimeFormatProperty("yyyy/MM/dd HH:mm:ss XXX", false)); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + ReadCellData cellData = new ReadCellData<>("2020-01-02T03:04:05"); + Assertions.assertThrows( + DateTimeParseException.class, + () -> converter.convertToJavaData(cellData, property, globalConfiguration)); + } + + @Test + void stringConverterReadsBackConfiguredPatternWithOffset() { + OffsetDateTimeStringConverter converter = new OffsetDateTimeStringConverter(); + ExcelContentProperty property = new ExcelContentProperty(); + property.setDateTimeFormatProperty(new DateTimeFormatProperty("yyyy-MM-dd HH:mm:ss Z", false)); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + ReadCellData cellData = new ReadCellData<>("2020-01-02 03:04:05 +0800"); + Assertions.assertEquals(VALUE, converter.convertToJavaData(cellData, property, globalConfiguration)); + } + + @Test + void stringConverterUsesDefaultLocaleWhenLocaleIsNull() throws Exception { + OffsetDateTimeStringConverter converter = new OffsetDateTimeStringConverter(); + ExcelContentProperty property = new ExcelContentProperty(); + property.setDateTimeFormatProperty(new DateTimeFormatProperty("yyyy-MM-dd HH:mm:ss Z", false)); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + globalConfiguration.setLocale(null); + Assertions.assertEquals( + "2020-01-02 03:04:05 +0800", + converter + .convertToExcelData(VALUE, property, globalConfiguration) + .getStringValue()); + } + + @Test + void stringConverterHonoursConfiguredLocale() throws Exception { + OffsetDateTimeStringConverter converter = new OffsetDateTimeStringConverter(); + ExcelContentProperty property = new ExcelContentProperty(); + property.setDateTimeFormatProperty(new DateTimeFormatProperty("dd MMMM yyyy HH:mm:ss XXX", false)); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + globalConfiguration.setLocale(Locale.GERMAN); + WriteCellData written = converter.convertToExcelData(VALUE, property, globalConfiguration); + Assertions.assertEquals("02 Januar 2020 03:04:05 +08:00", written.getStringValue()); + Assertions.assertEquals( + VALUE, + converter.convertToJavaData( + new ReadCellData<>(written.getStringValue()), property, globalConfiguration)); + } + + @Test + void numberConverterReturnsNullForInvalidExcelDate() { + OffsetDateTimeNumberConverter converter = new OffsetDateTimeNumberConverter(); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + Assertions.assertNull( + converter.convertToJavaData(new ReadCellData<>(BigDecimal.valueOf(-1)), null, globalConfiguration)); + } + + @Test + void dateConverterFallsBackToDefaultFormatForEmptyDateTimeFormat() throws Exception { + OffsetDateTimeDateConverter converter = new OffsetDateTimeDateConverter(); + ExcelContentProperty property = new ExcelContentProperty(); + property.setDateTimeFormatProperty(new DateTimeFormatProperty("", false)); + WriteCellData result = converter.convertToExcelData(VALUE, property, new GlobalConfiguration()); + Assertions.assertEquals( + DateUtils.defaultDateFormat, + result.getWriteCellStyle().getDataFormatData().getFormat()); + } + + @Test + void numberConverterDefaultsNullUse1904windowingToFalse() { + OffsetDateTimeNumberConverter converter = new OffsetDateTimeNumberConverter(); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + globalConfiguration.setUse1904windowing(null); + WriteCellData written = converter.convertToExcelData(VALUE, null, globalConfiguration); + Assertions.assertNotNull(written.getNumberValue()); + } + + @Test + void stringConverterWithEmptyOrNullPatternFallsBackToIso() throws Exception { + OffsetDateTimeStringConverter converter = new OffsetDateTimeStringConverter(); + GlobalConfiguration globalConfiguration = new GlobalConfiguration(); + + ExcelContentProperty emptyProperty = new ExcelContentProperty(); + emptyProperty.setDateTimeFormatProperty(new DateTimeFormatProperty("", false)); + WriteCellData writtenEmpty = converter.convertToExcelData(VALUE, emptyProperty, globalConfiguration); + Assertions.assertEquals( + VALUE, + converter.convertToJavaData( + new ReadCellData<>(writtenEmpty.getStringValue()), emptyProperty, globalConfiguration)); + + ExcelContentProperty nullFormatProperty = new ExcelContentProperty(); + nullFormatProperty.setDateTimeFormatProperty(new DateTimeFormatProperty(null, false)); + WriteCellData writtenNullFormat = + converter.convertToExcelData(VALUE, nullFormatProperty, globalConfiguration); + Assertions.assertEquals( + VALUE, + converter.convertToJavaData( + new ReadCellData<>(writtenNullFormat.getStringValue()), + nullFormatProperty, + globalConfiguration)); + } + + @Test + void convertersAreRegisteredForSupportedDirections() { + Assertions.assertEquals( + OffsetDateTimeDateConverter.class, + DefaultConverterLoader.loadDefaultWriteConverter() + .get(ConverterKeyBuild.buildKey(OffsetDateTime.class)) + .getClass()); + Assertions.assertEquals( + 2, + DefaultConverterLoader.loadAllConverter().entrySet().stream() + .filter(entry -> entry.getKey().getClazz() == OffsetDateTime.class) + .count()); + } +} diff --git a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java index a31454da7..9836bfd8c 100644 --- a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java +++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java @@ -26,7 +26,10 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.Calendar; import java.util.Date; import java.util.Locale; @@ -476,6 +479,30 @@ void test_isADateFormat_Cache() throws NoSuchFieldException, IllegalAccessExcept Assertions.assertTrue(res2); } + @Test + void test_parseOffsetDateTime() { + OffsetDateTime expected = OffsetDateTime.of(2020, 1, 2, 3, 4, 5, 0, ZoneOffset.ofHours(8)); + Assertions.assertEquals(expected, DateUtils.parseOffsetDateTime("2020-01-02T03:04:05+08:00", null, Locale.US)); + Assertions.assertEquals(expected, DateUtils.parseOffsetDateTime("2020-01-02T03:04:05+08:00", "", Locale.US)); + Assertions.assertEquals( + expected, + DateUtils.parseOffsetDateTime( + "02 Januar 2020 03:04:05 +08:00", "dd MMMM yyyy HH:mm:ss XXX", Locale.GERMAN)); + Assertions.assertThrows( + DateTimeParseException.class, + () -> DateUtils.parseOffsetDateTime("2020-01-02T03:04:05", null, Locale.US)); + } + + @Test + void test_format_OffsetDateTime() { + OffsetDateTime value = OffsetDateTime.of(2020, 1, 2, 3, 4, 5, 0, ZoneOffset.ofHours(8)); + Assertions.assertNull(DateUtils.format((OffsetDateTime) null, null, Locale.US)); + Assertions.assertEquals("2020-01-02T03:04:05+08:00", DateUtils.format(value, null, Locale.US)); + Assertions.assertEquals("2020-01-02T03:04:05+08:00", DateUtils.format(value, "", Locale.US)); + Assertions.assertEquals( + "02 Januar 2020 03:04:05 +08:00", DateUtils.format(value, "dd MMMM yyyy HH:mm:ss XXX", Locale.GERMAN)); + } + @Test void test_removeThreadLocalCache() throws NoSuchFieldException, IllegalAccessException { DateUtils.format(new Date(), "yyyy-MM-dd");