Skip to content

feat: add ZonedDateTime converters - #1020

Open
alexsmolya wants to merge 5 commits into
apache:mainfrom
alexsmolya:agent/zoneddatetime-converter
Open

feat: add ZonedDateTime converters#1020
alexsmolya wants to merge 5 commits into
apache:mainfrom
alexsmolya:agent/zoneddatetime-converter

Conversation

@alexsmolya

@alexsmolya alexsmolya commented Aug 17, 2026

Copy link
Copy Markdown

Purpose of the pull request

Related: #1017

What's changed?

Adds the approved java.time.ZonedDateTime converter family and registers it with the default converter loader.

  • DATE and NUMBER writes use toLocalDateTime(), intentionally dropping zone/offset while preserving local wall-clock fields.
  • Numeric reads attach ZoneId.systemDefault().
  • STRING conversion supports the accepted ISO and configured formatting/parsing semantics.
  • Added dedicated ZonedDateTimeConverterTest coverage for supported directions, registration, formatting, and timezone-lossiness behavior.

Checklist

  • I have read the Contributor Guide.
  • I have written the necessary doc or comment.
  • I have added the necessary unit tests and all cases have passed.

Focused validation: 6 ZonedDateTime tests passed; Java 1.8-targeted compilation, Spotless, and git diff --check passed.

@delei delei added the PR: first-time contributor first-time contributor label Aug 18, 2026
@delei
delei requested a lite review from Copilot August 18, 2026 00:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class java.time.ZonedDateTime converter support to the fesod-sheet module, integrating it into the default converter registry and providing unit coverage to validate the expected zone/offset handling behavior.

Changes:

  • Introduces ZonedDateTime converters for STRING, NUMBER, and DATE write scenarios.
  • Registers the new converters in DefaultConverterLoader for default read/write discovery.
  • Adds unit tests to validate conversion behavior and default registration.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/DefaultConverterLoader.java Registers ZonedDateTime converters in the default loader maps.
fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/zoneddatetime/ZonedDateTimeDateConverter.java Adds DATE write converter (drops zone via toLocalDateTime() and applies data format).
fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/zoneddatetime/ZonedDateTimeNumberConverter.java Adds NUMBER read/write converter using Excel serial dates and ZoneId.systemDefault() on read.
fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/zoneddatetime/ZonedDateTimeStringConverter.java Adds STRING read/write converter with ISO/custom pattern formatting and parsing fallback.
fesod-sheet/src/test/java/org/apache/fesod/sheet/converter/ZonedDateTimeConverterTest.java Adds targeted tests for conversion semantics and loader registration.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@nkuprins nkuprins left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a test for use1904windowing :)

@alexsmolya

Copy link
Copy Markdown
Author

Added focused use1904windowing coverage for ZonedDateTime, including global and field-level configuration plus write/read round-trip behavior. Targeted and related converter tests pass.

@bengbengbalabalabeng

bengbengbalabalabeng commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

The newly added files in this PR are implemented from scratch and are not derived from Alibaba's EasyExcel. Therefore, no EasyExcel-related license header is required for these files.

Please refer to: https://github.com/apache/fesod/blob/main/fesod-sheet/src/main/java/org/apache/fesod/sheet/FesodSheet.java

WriteCellData<?> cellData = new WriteCellData<>(localDateTime);
String format = null;
if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) {
format = contentProperty.getDateTimeFormatProperty().getFormat();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty @DateTimeFormat values are passed through to WorkBookUtil.fillDataFormat as-is. fillDataFormat only substitutes the default format when the argument is null — an empty string ("") is written into the cell style as-is, so @DateTimeFormat(value = "") produces a DATE cell with no format at all instead of falling back to yyyy-MM-dd HH:mm:ss.

Suggest normalizing the empty format to null before the call:

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

This also keeps the DATE direction consistent with the string converter below, which already falls back when the format is empty.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in f882ea6: empty DATE formats are normalized to null before fillDataFormat, so the existing yyyy-MM-dd HH:mm:ss default is applied. Added a regression test.

|| contentProperty.getDateTimeFormatProperty() == null
|| StringUtils.isEmpty(
contentProperty.getDateTimeFormatProperty().getFormat())) {
return DateTimeFormatter.ISO_ZONED_DATE_TIME;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DateTimeFormatter.ofPattern(...) is invoked for every cell conversion — once in convertToJavaData and once in convertToExcelData. In the per-cell hot path (large sheets) this rebuilds the same formatter over and over, since the pattern and locale change only per property, not per cell.

Suggest caching formatters per (pattern, locale), e.g. a ThreadLocal map with the ISO default kept as a shared constant:

private static final ThreadLocal<Map<String, DateTimeFormatter>> FORMATTER_CACHE = new ThreadLocal<>();

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in f882ea6 by reusing the existing bounded per-thread locale/pattern formatter cache in DateUtils for configured patterns. No new converter-local ThreadLocal was introduced; ISO remains the shared constant.

return DateTimeFormatter.ofPattern(
contentProperty.getDateTimeFormatProperty().getFormat(), locale);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty @DateTimeFormat values are handled inconsistently across the three converters:

  • ZonedDateTimeStringConverter (line 81) falls back to ISO_ZONED_DATE_TIME2020-01-02T03:04:05Z
  • ZonedDateTimeDateConverter (line 54) passes "" through to fillDataFormat → cell ends up with no format at all
  • ZonedDateTimeNumberConverter → the cell is formatted with the workbook default

So the same @DateTimeFormat(value = "") produces three different outputs depending on the cell type. Suggest picking one behavior — falling back to the default yyyy-MM-dd HH:mm:ss on all three keeps it consistent with the other date-time families.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DATE defect is fixed in f882ea6. I left the three representations defaults intentionally distinct: STRING uses ISO_ZONED_DATE_TIME to preserve zone and offset text, while DATE and NUMBER use Excel date semantics and the workbook default. This matches the existing converter-family conventions, so a blanket yyyy-MM-dd HH:mm:ss fallback would change intended STRING behavior.

@Mikkey-f

Copy link
Copy Markdown
Contributor

Thanks for addressing all three points — verified locally, all tests green (8/8). One heads-up: the PR is currently in a CONFLICTING state (DefaultConverterLoader, after #1032 was merged to main) — could you rebase on the latest main when you get a chance?

alexsmolya and others added 5 commits August 26, 2026 19:13
…mpty format pattern

- Add @tag(Tags.UNIT) to ZonedDateTimeConverterTest following repository conventions
- Handle empty or null format strings in ZonedDateTimeStringConverter by falling back to ISO_ZONED_DATE_TIME
- Add regression coverage for empty and null format patterns
@alexsmolya
alexsmolya force-pushed the agent/zoneddatetime-converter branch from f882ea6 to 0c342db Compare August 26, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: first-time contributor first-time contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants