Skip to content

[Task] Implement more commonly used converter classes #1017

Open

Description

@delei

Motivation

During usage, we may need to convert read or written data into specific formats. Apache Fesod (Incubating) provides a flexible converter mechanism that allows users to define custom data conversion rules to meet various business requirements. Many converter classes are already built in, but some are still missing.

How to complete

Please link this issue in the description of the PR.

This will be a long-term task, allowing all the volunteers to divide it into multiple PRs for completion. Each PR can contain one or more converters, and each converter needs to provide the corresponding unit test code.

Only classes compatible with JDK 8 are supported. Each converter must implement the org.apache.fesod.sheet.converters.Converter interface, and please leave a comment outlining your specific implementation proposal.

Task List

The following are some conversions that are currently required

Please feel free to suggest any type converters you require, and please leave a comment in this issue.

The new proposal needs to be published for at least 24 hours. If there are no objections during this period, please feel free to submit your PR at any time. These will be added to the task list and assigned to volunteers later.

Activity

  1. added theissue type on Aug 16, 2026
  2. changed the title [-][Task] Implement more commonly used Converter classes[/-] [+][Task] Implement more commonly used converter classes[/+] on Aug 16, 2026
  3. alexsmolya commented on Aug 16, 2026

    @alexsmolya

    Here is an implementation proposal for java.time.ZonedDateTime converters, following the established LocalDateTime / LocalDate pattern:

    1. Proposed Converter Family (org.apache.fesod.sheet.converters.zoneddatetime)

    • ZonedDateTimeDateConverter (Write -> Excel DATE cell):
      • Emits WriteCellData(value.toLocalDateTime()) with default date format (yyyy-MM-dd HH:mm:ss).
    • ZonedDateTimeNumberConverter (Bidirectional Excel NUMBER serial):
      • Read: Parses Excel numeric serial to LocalDateTime (respecting use1904windowing), then assigns ZoneId.systemDefault() (localDateTime.atZone(ZoneId.systemDefault())).
      • Write: Converts value.toLocalDateTime() to numeric serial via DateUtil.getExcelDate(value.toLocalDateTime(), use1904).
    • ZonedDateTimeStringConverter (Bidirectional Excel STRING cell):
      • Read: Parses according to @DateTimeFormat if specified, or standard DateUtils patterns, attaching ZoneId.systemDefault() when no zone/offset is present in the input string.
      • Write: Formats date-time using @DateTimeFormat (default yyyy-MM-dd HH:mm:ss) and configured Locale.

    2. Timezone & Lossiness Semantics

    • Numeric & Date cells: Native Excel sheets store temporal values as zone-less numbers/dates. Writing ZonedDateTime necessarily preserves the local wall-clock time (zonedDateTime.toLocalDateTime()) while omitting the ZoneId/offset in the Excel file.
    • Reading numeric cells: Converts to LocalDateTime and attaches ZoneId.systemDefault(), matching the convention used across existing Date / LocalDateTime conversions.
    • String cells: When explicit zone/offset patterns (e.g. yyyy-MM-dd'T'HH:mm:ssXXX) are used via @DateTimeFormat, the offset/zone can be parsed or emitted verbatim.

    3. Registration & Test Coverage

    • Register ZonedDateTimeNumberConverter and ZonedDateTimeStringConverter in DefaultConverterLoader.initAllConverter().
    • Register ZonedDateTimeDateConverter and ZonedDateTimeStringConverter in DefaultConverterLoader.initDefaultWriteConverter().
    • Add unit tests in ConverterTest (supportJavaTypeKey, supportExcelTypeKey, read/write assertions for Date, Number, String).
    • Add round-trip integration coverage in ConverterDataTest across all supported formats (XLSX, XLS, CSV, etc.).
    • Validate immutability in DefaultConverterLoaderTest.

    Feedback and thoughts from the community are welcome!

  4. delei commented on Aug 16, 2026

    @delei
    MemberAuthor

    Here is an implementation proposal for java.time.ZonedDateTime converters, following the established LocalDateTime / LocalDate pattern

    Hi, @alexsmolya , welcome !

    SGTM, +1.

    BTW, the unit test class can be independently added to the org.apache.fesod.sheet.converter package. For example, add a ZonedDateTimeConverterTest class.

    Welcome, the proposal is to be published for 24 hours, if no objections are raised, the task will be assigned to you.

  5. SyedIshmumAhnaf commented on Aug 16, 2026

    @SyedIshmumAhnaf
    Contributor

    I’d like to work on the java.sql.Timestamp converter support.

    My proposed approach is to follow the existing Date / LocalDateTime converter pattern and add a dedicated Timestamp converter family under org.apache.fesod.sheet.converters:

    • TimestampDateConverter
      • Default write path for Timestamp
      • Preserve the existing date-format handling used by the other temporal converters
    • TimestampNumberConverter
      • Read Excel numeric date values into Timestamp
      • Write Timestamp values as Excel date serials
      • Reuse the existing date utilities and respect use1904windowing
    • TimestampStringConverter
      • Read and write string values using the existing DateUtils formatting/parsing behavior
      • Respect @DateTimeFormat and the configured locale

    For registration, I plan to follow the current LocalDateTime setup in DefaultConverterLoader:

    • register the Number and String converters in initAllConverter()
    • register the Date converter as the default write converter
    • register the String converter for string-formatted writes

    Since converter lookup is keyed by the declared Java class, the existing java.util.Date converters do not automatically cover fields declared as java.sql.Timestamp, so I would keep the change scoped to adding explicit Timestamp support rather than changing the converter lookup mechanism.

    For tests, I plan to add a dedicated TimestampConverterTest covering the converter keys and read/write behavior, including the relevant date-format / 1904-windowing cases, plus the existing loader or round-trip coverage where appropriate.

    I’ll keep the implementation JDK 8 compatible and limited to the Timestamp slice of this issue.

    If this direction looks good, I’d be happy to take it.

  6. delei commented on Aug 17, 2026

    @delei
    MemberAuthor

    I’d like to work on the java.sql.Timestamp converter support.

    Hi, @SyedIshmumAhnaf

    SGTM, +1.

    Welcome, the proposal is to be published for 24 hours, if no objections are raised, the task will be assigned to you.

  7. delei commented on Aug 17, 2026

    @delei
    MemberAuthor

    Here is an implementation proposal for java.time.ZonedDateTime converters, following the established LocalDateTime / LocalDate pattern

    Hi, @alexsmolya , welcome !

    SGTM, +1.

    BTW, the unit test class can be independently added to the org.apache.fesod.sheet.converter package. For example, add a ZonedDateTimeConverterTest class.

    Welcome, the proposal is to be published for 24 hours, if no objections are raised, the task will be assigned to you.

    Hi, @alexsmolya

    It has been assigned to you. Please refer to the code contribution guidelines and feel free to submit a PR at any time, and please link this issue in the description of the PR.

  8. delei commented on Aug 17, 2026

    @delei
    MemberAuthor

    I’d like to work on the java.sql.Timestamp converter support.

    Hi, @SyedIshmumAhnaf

    SGTM, +1.

    Welcome, the proposal is to be published for 24 hours, if no objections are raised, the task will be assigned to you.

    Hi, @SyedIshmumAhnaf

    It has been assigned to you. Please refer to the code contribution guidelines and feel free to submit a PR at any time, and please link this issue in the description of the PR.

  9. AhmedYoussef98 commented on Aug 17, 2026

    @AhmedYoussef98

    I'd like to work on the java.sql.Clob converter (still unassigned in the task list).

    Proposed approach, following the existing String converter family (StringStringConverter, StringNumberConverter) under a new org.apache.fesod.sheet.converters.clob package:

    • ClobStringConverter (bidirectional, Excel STRING cell)
      • Read: builds a java.sql.Clob from the cell's string value via javax.sql.rowset.serial.SerialClob (JDK 8 compatible, no external deps), i.e. new SerialClob(cellData.getStringValue().toCharArray()).
      • Write: extracts the full contents with clob.getSubString(1, (int) clob.length()) and wraps it in a WriteCellData<>(...), matching StringStringConverter's write path.

    Registration: add to DefaultConverterLoader.initAllConverter() (as the String-keyed converters are), keyed on Clob.class / CellDataTypeEnum.STRING.

    Tests: add a ClobConverterTest under org.apache.fesod.sheet.converter (same location as StringPathnameImageConverterTest/CustomConverterTest), covering supportJavaTypeKey/supportExcelTypeKey, round-trip read/write, and an empty-string edge case. SQLException from SerialClob construction will propagate per the Converter interface's throws Exception contract.

    Scope is limited to this one converter — happy to take another (e.g. java.sql.Clob's counterpart on read-only numeric/boolean cells) as a follow-up if useful. Will link this issue in the PR per the contribution guide.

  10. delei commented on Aug 17, 2026

    @delei
    MemberAuthor

    I'd like to work on the java.sql.Clob converter (still unassigned in the task list).
    ...

    • Write: extracts the full contents with clob.getSubString(1, (int) clob.length()) and wraps it in a WriteCellData<>(...), matching StringStringConverter's write path.

    Hi, @AhmedYoussef98

    SGTM, +1.

    FYI, regarding string slicing, please note that the maximum text length in Excel cells is 32767. If possible, it is recommended to adhere to this limit and provide similar test cases in the unit tests.

    Welcome, the proposal is to be published for 24 hours, if no objections are raised, the task will be assigned to you.

  11. Mikkey-f commented on Aug 20, 2026

    @Mikkey-f
    Contributor

    I'd like to work on java.time.OffsetDateTime converter support.

    Proposed approach: follow the existing LocalDateTime / ZonedDateTime converter family pattern, adding three converters under org.apache.fesod.sheet.converters:

    • OffsetDateTimeStringConverter — OffsetDateTime ↔ String
    • OffsetDateTimeNumberConverter — OffsetDateTime ↔ Number (epoch-based, consistent with existing Date/LocalDateTime numeric conversion)
    • OffsetDateTimeDateConverter — OffsetDateTime ↔ java.util.Date

    Each will implement the Converter interface and come with corresponding JUnit 5 tests, mirroring the structure of the recently added ZonedDateTime converter tests.

  12. leehaut commented on Aug 22, 2026

    @leehaut
    Contributor

    I'd like to work on java.time.LocalTime converter support.

    Fesod already has LocalDate / LocalDateTime converters, and WriteCellData already maps java.sql.Time via toLocalTime().atDate(DateUtils.EPOCH). A dedicated LocalTime converter family would close that gap for time-of-day fields (DB TIME columns, business hours, schedules) without requiring users to fall back to String or LocalDateTime.

    1. Proposed Converter Family (org.apache.fesod.sheet.converters.localtime)

    Following the existing LocalDate / LocalDateTime pattern:

    • LocalTimeDateConverter (Write -> Excel DATE cell):
      • Emits WriteCellData(value.atDate(DateUtils.EPOCH)) with default format HH:mm:ss.
      • Reuses the same epoch-date convention already used for java.sql.Time in WriteCellData / CsvCell.
    • LocalTimeNumberConverter (Bidirectional Excel NUMBER serial):
      • Read: DateUtils.getLocalDateTime(serial, use1904windowing).toLocalTime(), so both Excel-native time fractions (0.5 = 12:00:00) and full datetime serials round-trip to the same wall-clock time.
      • Write: DateUtil.getExcelDate(value.atDate(DateUtils.EPOCH), use1904), consistent with the DATE write path.
    • LocalTimeStringConverter (Bidirectional Excel STRING cell):
      • Read / Write: parse and format with @DateTimeFormat if present, otherwise HH:mm:ss (and HH:mm when the input has no seconds).
      • Respect the configured Locale.

    Small DateUtils additions will be needed (mirroring parseLocalDate / format(LocalDate)):

    • defaultLocalTimeFormat = "HH:mm:ss"
    • parseLocalTime(...) / format(LocalTime, ...)
    • time-only pattern detection for HH:mm:ss / HH:mm (current switchDateFormat only covers date/datetime lengths)

    2. Time-only Semantics

    • Excel has no native time-only cell type. Time is stored as a datetime serial (or a day fraction) and displayed via number format.
    • Writing: preserve the wall-clock time and attach DateUtils.EPOCH (1970-01-01) as the date component, then apply HH:mm:ss so Excel shows time only.
    • Reading: drop any date component with toLocalTime(). A numeric cell of 0.5 and a datetime serial that happens to be 12:00:00 both become LocalTime.of(12, 0, 0).
    • This is the time-only counterpart of LocalDate (which keeps the date and zeros the time).

    3. Registration & Test Coverage

    • Register LocalTimeNumberConverter and LocalTimeStringConverter in DefaultConverterLoader.initAllConverter().
    • Register LocalTimeDateConverter and LocalTimeStringConverter in DefaultConverterLoader.initDefaultWriteConverter().
    • Add a dedicated LocalTimeConverterTest under org.apache.fesod.sheet.converter, covering converter keys, DATE/NUMBER/STRING read-write, @DateTimeFormat, use1904windowing, and the date-dropping behavior.
    • Add round-trip coverage in ConverterDataTest where appropriate.
    • Validate loader immutability still holds in DefaultConverterLoaderTest.

    Scope is limited to java.time.LocalTime (JDK 8). java.sql.Time can be a follow-up if useful; converter lookup is keyed by the declared Java class, so existing Date converters do not cover LocalTime fields.

    If this direction looks good, I’d be happy to take it.

  13. 43 remaining items

  14. CodeMan-cmd commented on Sep 23, 2026

    @CodeMan-cmd

    Proposal for three types that are not on the task list yet. I checked the current behaviour on main (4e3f3aa) with a bean per type, and all of them fail on read and on write:

    write Instant        -> ExcelWriteDataConvertException: Can not find 'Converter' support class Instant.
    write java.sql.Date  -> ExcelWriteDataConvertException: Can not find 'Converter' support class Date.
    write YearMonth      -> ExcelWriteDataConvertException: Can not find 'Converter' support class YearMonth.
    write UUID           -> ExcelWriteDataConvertException: Can not find 'Converter' support class UUID.
    read  Instant        -> ExcelWriteDataConvertException: Can not find 'Converter' support class Instant.
    read  java.sql.Date  -> ExcelWriteDataConvertException: Can not find 'Converter' support class Date.
    read  YearMonth      -> ExcelWriteDataConvertException: Can not find 'Converter' support class YearMonth.
    read  UUID           -> ExcelWriteDataConvertException: Can not find 'Converter' support class UUID.
    

    java.sql.Date is worth calling out separately: it extends java.util.Date, which does have converters, but the converter map is keyed by the exact class, so a java.sql.Date field gets nothing. It is the sibling of java.sql.Timestamp, which is already on the list.

    Proposal 1 - java.time.Instant (converters/instant/)

    • InstantDateConverter (Excel DATE): write Date.from(value) as WriteCellData<Date>; read cellData.getDateValue().toInstant().
    • InstantNumberConverter (Excel NUMBER serial): read and write through LocalDateTime like the localdatetime family, so use1904windowing and the number format keep working; atZone(ZoneId.systemDefault()).toInstant().
    • InstantStringConverter (Excel STRING): DateUtils.format(...) / parseDate(...) with the @DateTimeFormat value, falling back to the default pattern.

    Proposal 2 - java.sql.Date and java.sql.Time (converters/sqldate/, converters/sqltime/)

    Mirror the existing converters/date/ family one to one (*DateConverter, *NumberConverter, *StringConverter), with toLocalDate() / toLocalTime() as the intermediate, and register them in DefaultConverterLoader. Same shape as the java.sql.Timestamp proposal that is already assigned, so the sql family stays consistent.

    Proposal 3 - java.time.YearMonth (converters/yearmonth/)

    Excel has no month type, so YearMonthStringConverter as yyyy-MM plus YearMonthNumberConverter through the first day of the month, which keeps sorting and date arithmetic in the sheet working.

    All three proposals are JDK 8 only, implement org.apache.fesod.sheet.converters.Converter, and would come with unit tests per converter (write, read and a round trip through xlsx) plus the DefaultConverterLoader registration.

    I will leave this comment for the 24 hours mentioned above and then open the PRs, one type family per PR. If you would rather have them in a different shape (for example Instant as a string only, or YearMonth as a DATE cell of the first day), tell me and I will adjust before the PR.

  15. CodeMan-cmd commented on Sep 23, 2026

    @CodeMan-cmd

    Implemented the three proposals: #1133

    converters/sqldate, converters/sqltime, converters/instant and converters/yearmonth, each with a round trip test over xlsx, xls and csv. They are in one PR because all of them register in DefaultConverterLoader and separate PRs would conflict there; I can split it if you prefer.

    Verification on my machine with Temurin 1.8.0_472: 928 tests, 0 failures, and spotless:check passes.

  16. BigDataDZ commented on Oct 8, 2026

    @BigDataDZ
    Contributor

    I'd like to propose a follow-up batch of four JDK 8 compatible types that are neither on the task list nor proposed yet (verified against DefaultConverterLoader and this thread): java.time.Month, java.time.DayOfWeek, java.time.Period and java.time.Duration.

    Proposed approach - one bidirectional STRING converter per type, following the *StringConverter pattern:

    1. MonthStringConverter (converters/month): writes Month#getDisplayName(TextStyle.FULL, locale) respecting GlobalConfiguration.locale (or a @DateTimeFormat custom pattern with numeric uuuu-MM style values also accepted on read); reads case-insensitively via Month#valueOf and 1-12 numerically.
    2. DayOfWeekStringConverter (converters/dayofweek): same shape as above over DayOfWeek, with 1-7 numeric read support (ISO-8601 Monday=1).
    3. PeriodStringConverter (converters/period): writes Period#toString() (ISO-8601 P1Y2M3D); reads via Period#parse, null stays null.
    4. DurationStringConverter (converters/duration): writes Duration#toString() (PT5H30M); reads via Duration#parse, null stays null.

    Each ships with JUnit 5 unit tests (round-trip, locale handling where applicable, invalid input reported as ExcelDataConvertException instead of being silently coerced) and registration in DefaultConverterLoader. Happy to split them into one PR per type or batch two-and-two, whichever maintainers prefer.

  17. Mikkey-f commented on Oct 12, 2026

    @Mikkey-f
    Contributor

    I'd like to propose and take the missing number converter for java.time.Year — the follow-up to YearStringConverter, which landed via #1087 (background discussion in #1216).

    Current behaviour on main (verified at bf9bf92): Year ships only the STRING converter, so the (Year, NUMBER) read key is unmapped and a numeric year column fails on read:

    read a cell containing 2026 into a Year field
    -> ExcelDataConvertException: Converter not found, convert NUMBER to java.time.Year
    

    Date-formatted cells fail the same way, since they are NUMBER cells at read time. The sibling date-like types (LocalDate, LocalTime, OffsetDateTime, java.util.Date) each ship a number converter, so this closes the gap #1087 left in the family.

    Proposed converter — YearNumberConverter under converters/year, following the *NumberConverter pattern:

    • a date-formatted cell → the year of the Excel serial date it represents, consistent with the siblings;
    • any other numeric cell → the year itself (2026 → Year.of(2026); a serial reading would give 1905, which is not what a year column means);
    • read side only: Year keeps writing as STRING through YearStringConverter, unchanged.

    Implementation is up as #1217, with a unit test plus an end-to-end read test. It was opened earlier today as a bug fix, before the reclassification in #1216 — apologies for skipping the 24-hour notice; happy to hold it if that step should apply.

    The plain-number branch is the design point worth a look: if strict family consistency is preferred (always read as a date serial), it can be switched.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions