Fix IsoFormattingDateDataFormatter

The format used the ISO_OFFSET_DATE_TIME is the wrong one and leads to errors
formatting the date. Instead we should have used the ISO_LOCAL_DATE_TIME instead.

This commit fixes that and also includes a bug fix for the XLSX variant as that didn't
use the overridden method. The correct method for this has been overridden now also
formatting the dates/times for that using the ISO_LOCAL_DATE_TIME format.

Tests for different types have been added as well, as to make sure this
keeps working for newer versions.

Closes: #121
This commit is contained in:
Marten Deinum
2024-08-07 14:11:52 +02:00
parent b6e2b97068
commit cc72e8d616
5 changed files with 148 additions and 2 deletions

View File

@@ -28,7 +28,7 @@ import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
/**
* Specialized subclass for additionally formatting the date into an ISO date/time.
* Specialized subclass for formatting the date into an ISO date/time and ignore the format as given in the Excel file.
*
* @author Marten Deinum
*
@@ -44,6 +44,15 @@ public class IsoFormattingDateDataFormatter extends DataFormatter {
super(locale);
}
@Override
public String formatRawCellContents(double value, int formatIndex, String formatString, boolean use1904Windowing) {
if (DateUtil.isADateFormat(formatIndex, formatString) && DateUtil.isValidExcelDate(value)) {
return super.formatRawCellContents(value, formatIndex, "yyyy-MM-ddTHH:mm:ss",
use1904Windowing);
}
return super.formatRawCellContents(value, formatIndex, formatString, use1904Windowing);
}
@Override
public String formatCellValue(Cell cell, FormulaEvaluator evaluator, ConditionalFormattingEvaluator cfEvaluator) {
if (cell == null) {
@@ -60,7 +69,7 @@ public class IsoFormattingDateDataFormatter extends DataFormatter {
if (cellType == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell, cfEvaluator)) {
LocalDateTime value = cell.getLocalDateTimeCellValue();
return (value != null) ? value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) : "";
return (value != null) ? value.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) : "";
}
return super.formatCellValue(cell, evaluator, cfEvaluator);
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.batch.extensions.excel.poi;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import org.springframework.batch.extensions.excel.mapping.PassThroughRowMapper;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
public class PoiItemReaderTypesTest {
@Test
public void shouldBeAbleToReadMultipleTypes() throws Exception {
var reader = new PoiItemReader<String[]>();
reader.setResource(new ClassPathResource("types.xls"));
reader.setRowMapper(new PassThroughRowMapper());
reader.setLinesToSkip(1); // Skip header
reader.setUserLocale(Locale.US); // Use a Locale to not be dependent on environment
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
var row1 = reader.read();
var row2 = reader.read();
assertThat(row1).containsExactly("1", "1.0", "5/12/24", "13:14:55", "5/12/24 13:14", "hello world");
assertThat(row2).containsExactly("2", "2.5", "8/8/23", "11:12:13", "8/8/23 11:12", "world hello");
}
@Test
public void shouldBeAbleToReadMultipleTypesWithDatesAsIso() throws Exception {
var reader = new PoiItemReader<String[]>();
reader.setResource(new ClassPathResource("types.xls"));
reader.setRowMapper(new PassThroughRowMapper());
reader.setLinesToSkip(1); // Skip header
reader.setUserLocale(Locale.US); // Use a Locale to not be dependent on environment
reader.setDatesAsIso(true);
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
var row1 = reader.read();
var row2 = reader.read();
assertThat(row1).containsExactly("1", "1.0", "2024-05-12T00:00:00", "1899-12-31T13:14:55", "2024-05-12T13:14:55", "hello world");
assertThat(row2).containsExactly("2", "2.5", "2023-08-08T00:00:00", "1899-12-31T11:12:13", "2023-08-08T11:12:13", "world hello");
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.batch.extensions.excel.streaming;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import org.springframework.batch.extensions.excel.mapping.PassThroughRowMapper;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
public class StreamingXlsxTypesTest {
@Test
public void shouldBeAbleToReadMultipleTypes() throws Exception {
var reader = new StreamingXlsxItemReader<String[]>();
reader.setResource(new ClassPathResource("types.xlsx"));
reader.setRowMapper(new PassThroughRowMapper());
reader.setLinesToSkip(1); // Skip header
reader.setUserLocale(Locale.US); // Use a Locale to not be dependent on environment
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
var row1 = reader.read();
var row2 = reader.read();
assertThat(row1).containsExactly("1", "1.0", "5/12/24", "13:14:55", "5/12/24 13:14", "hello world");
assertThat(row2).containsExactly("2", "2.5", "8/8/23", "11:12:13", "8/8/23 11:12", "world hello");
}
@Test
public void shouldBeAbleToReadMultipleTypesWithDatesAsIso() throws Exception {
var reader = new StreamingXlsxItemReader<String[]>();
reader.setResource(new ClassPathResource("types.xlsx"));
reader.setRowMapper(new PassThroughRowMapper());
reader.setLinesToSkip(1); // Skip header
reader.setUserLocale(Locale.US); // Use a Locale to not be dependent on environment
reader.setDatesAsIso(true);
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
var row1 = reader.read();
var row2 = reader.read();
assertThat(row1).containsExactly("1", "1.0", "2024-05-12T00:00:00", "1899-12-31T13:14:55", "2024-05-12T13:14:55", "hello world");
assertThat(row2).containsExactly("2", "2.5", "2023-08-08T00:00:00", "1899-12-31T11:12:13", "2023-08-08T11:12:13", "world hello");
}
}

Binary file not shown.

Binary file not shown.