Merge pull request #140 from spring-projects/improve-isodateformatter
Improve IsoFormattingDateDataFormatter
This commit is contained in:
@@ -25,14 +25,13 @@ import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.DataFormatter;
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
import org.apache.poi.ss.usermodel.ExcelNumberFormat;
|
||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||
|
||||
/**
|
||||
* Specialized subclass for formatting the date into an ISO date/time and ignore the format as given in the Excel file.
|
||||
*
|
||||
* @author Marten Deinum
|
||||
*
|
||||
* @see DateTimeFormatter#ISO_OFFSET_DATE_TIME
|
||||
*/
|
||||
public class IsoFormattingDateDataFormatter extends DataFormatter {
|
||||
|
||||
@@ -46,9 +45,10 @@ public class IsoFormattingDateDataFormatter extends DataFormatter {
|
||||
|
||||
@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);
|
||||
String formatToUse = determineFormat(formatIndex);
|
||||
return super.formatRawCellContents(value, formatIndex, formatToUse, use1904Windowing);
|
||||
}
|
||||
return super.formatRawCellContents(value, formatIndex, formatString, use1904Windowing);
|
||||
}
|
||||
@@ -60,17 +60,34 @@ public class IsoFormattingDateDataFormatter extends DataFormatter {
|
||||
}
|
||||
|
||||
CellType cellType = cell.getCellType();
|
||||
if (cellType == CellType.FORMULA) {
|
||||
if (evaluator == null) {
|
||||
return cell.getCellFormula();
|
||||
}
|
||||
cellType = evaluator.evaluateFormulaCell(cell);
|
||||
if (cellType == CellType.FORMULA && useCachedValuesForFormulaCells()) {
|
||||
cellType = cell.getCachedFormulaResultType();
|
||||
}
|
||||
|
||||
if (cellType == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell, cfEvaluator)) {
|
||||
if (cellType != CellType.STRING && DateUtil.isCellDateFormatted(cell, cfEvaluator)) {
|
||||
String formatToUse = determineFormat(ExcelNumberFormat.from(cell, cfEvaluator).getIdx());
|
||||
LocalDateTime value = cell.getLocalDateTimeCellValue();
|
||||
return (value != null) ? value.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) : "";
|
||||
return (value != null) ? value.format(DateTimeFormatter.ofPattern(formatToUse)) : "";
|
||||
}
|
||||
return super.formatCellValue(cell, evaluator, cfEvaluator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the format to use for either date, time of datetime. Based on the internal formats used by Excel.
|
||||
* 14, 15, 16, 17 are dates only
|
||||
* 18, 19, 20, 21 are times only
|
||||
* anything else is interpreted as a datetime, including custom formats that might be in use!
|
||||
* @param formatIndex the format index from excel.
|
||||
* @return the format to use, never {@code null}.
|
||||
*/
|
||||
|
||||
private String determineFormat(int formatIndex) {
|
||||
if (formatIndex >= 14 && formatIndex < 18) {
|
||||
return "yyyy-MM-dd";
|
||||
}
|
||||
else if (formatIndex >= 18 && formatIndex < 22) {
|
||||
return "HH:mm:ss";
|
||||
}
|
||||
return "yyyy-MM-dd'T'HH:mm:ss";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
class PoiItemReaderTypesTests {
|
||||
class PoiItemReaderXlsTypesTests {
|
||||
|
||||
@Test
|
||||
void shouldBeAbleToReadMultipleTypes() throws Exception {
|
||||
@@ -38,7 +38,6 @@ class PoiItemReaderTypesTests {
|
||||
reader.setUserLocale(Locale.US); // Use a Locale to not be dependent on environment
|
||||
reader.afterPropertiesSet();
|
||||
|
||||
|
||||
reader.open(new ExecutionContext());
|
||||
|
||||
var row1 = reader.read();
|
||||
@@ -62,8 +61,7 @@ class PoiItemReaderTypesTests {
|
||||
|
||||
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");
|
||||
|
||||
assertThat(row1).containsExactly("1", "1.0", "2024-05-12", "13:14:55", "2024-05-12T13:14:55", "hello world");
|
||||
assertThat(row2).containsExactly("2", "2.5", "2023-08-08", "11:12:13", "2023-08-08T11:12:13", "world hello");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
class PoiItemReaderXlsxTypesTests {
|
||||
|
||||
@Test
|
||||
void shouldBeAbleToReadMultipleTypes() throws Exception {
|
||||
var reader = new PoiItemReader<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
|
||||
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-12", "13:14:55", "2024-05-12T13:14:55", "hello world");
|
||||
assertThat(row2).containsExactly("2", "2.5", "2023-08-08", "11:12:13", "2023-08-08T11:12:13", "world hello");
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,6 @@ class StreamingXlsxTypesTests {
|
||||
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
|
||||
@@ -60,9 +59,7 @@ class StreamingXlsxTypesTests {
|
||||
|
||||
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");
|
||||
|
||||
assertThat(row1).containsExactly("1", "1.0", "2024-05-12", "13:14:55", "2024-05-12T13:14:55", "hello world");
|
||||
assertThat(row2).containsExactly("2", "2.5", "2023-08-08", "11:12:13", "2023-08-08T11:12:13", "world hello");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user