Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve IsoFormattingDateDataFormatter #140

Merged
merged 1 commit into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@
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 {

Expand All @@ -46,9 +45,10 @@ public IsoFormattingDateDataFormatter(Locale 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);
String formatToUse = determineFormat(formatIndex);
return super.formatRawCellContents(value, formatIndex, formatToUse, use1904Windowing);
}
return super.formatRawCellContents(value, formatIndex, formatString, use1904Windowing);
}
Expand All @@ -60,17 +60,34 @@ public String formatCellValue(Cell cell, FormulaEvaluator evaluator, Conditional
}

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";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import static org.assertj.core.api.Assertions.assertThat;


class PoiItemReaderTypesTests {
class PoiItemReaderXlsTypesTests {

@Test
void shouldBeAbleToReadMultipleTypes() throws Exception {
Expand All @@ -38,7 +38,6 @@ void shouldBeAbleToReadMultipleTypes() throws Exception {
reader.setUserLocale(Locale.US); // Use a Locale to not be dependent on environment
reader.afterPropertiesSet();


reader.open(new ExecutionContext());

var row1 = reader.read();
Expand All @@ -62,8 +61,7 @@ void shouldBeAbleToReadMultipleTypesWithDatesAsIso() throws Exception {

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");
}
}
Original file line number Diff line number Diff line change
@@ -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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ void shouldBeAbleToReadMultipleTypes() throws Exception {
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
Expand All @@ -60,9 +59,7 @@ void shouldBeAbleToReadMultipleTypesWithDatesAsIso() throws Exception {

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");
}

}
Loading