Skip to content

[Bug] @DateTimeFormat use1904windowing DEFAULT is collapsed to false, bypassing the global 1904 fallback #1042

Description

@Mikkey-f

Search before asking

Fesod version

2.0.2-incubating+ (current main)

JDK version

JDK 8+ (reproducible on any)

Operating system

Any

Steps To Reproduce

  1. Create a POJO with a LocalDateTime (or Date) field annotated with @DateTimeFormat for the pattern only, leaving use1904windowing at its default:
public class DemoData {
    @ExcelProperty("time")
    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")   // use1904windowing left at DEFAULT
    private LocalDateTime time;
}
  1. Read a workbook whose date windowing is 1904, either by builder setting or by a file carrying the 1904 flag:
FesodSheet.read(path)
    .head(DemoData.class)
    .use1904windowing(true)   // global setting
    .sheet()
    .doReadSync();
  1. Observe the parsed LocalDateTime — serial numbers are interpreted with the 1900 window (offset by 1462 days) instead of 1904.

Current Behavior

DateTimeFormatProperty.build() collapses the annotation's use1904windowing() default (BooleanEnum.DEFAULT = null) to false:

return new DateTimeFormatProperty(
        dateTimeFormat.value(),
        BooleanUtils.isTrue(dateTimeFormat.use1904windowing().getBooleanValue()));

So whenever a field carries @DateTimeFormat (even for the pattern only), the date-number converters consume false and the global use1904windowing setting is bypassed:

Path 1904 value used
No annotation globalConfiguration.getUse1904windowing() (e.g. .use1904windowing(true) on the builder)
@DateTimeFormat with DEFAULT falseglobal setting is bypassed
@DateTimeFormat(use1904windowing = TRUE/FALSE) explicit value (correct)

The same POJO behaves differently on the read path (serial → date) and write path (date → serial) depending on whether the field happens to carry the annotation.

Expected Behavior

DEFAULT should keep its "user did not specify" semantics (as BooleanEnum's javadoc states — an enum "to determine whether the user has added the enumeration"). The converters should fall back to globalConfiguration.getUse1904windowing() when the property value is null, with the existing null-safe global default of false unchanged.

Suggested fix:

  1. DateTimeFormatProperty.build(): pass use1904windowing().getBooleanValue() through as-is (keep DEFAULT as null)
  2. Date-number converters (Date, LocalDate, LocalDateTime, LocalTime, ZonedDateTime, OffsetDateTime): when the property value is null, fall back to the global configuration — the OffsetDateTimeNumberConverter already implements this pattern
  3. Regression test: @DateTimeFormat without use1904windowing + global .use1904windowing(true) → follows the global setting

Anything else?

Historical note from #433: GlobalConfiguration's use1904windowing = Boolean.FALSE default was introduced in 2021 to fix a test NPE — that null-safe global default stays untouched by this proposal.

Are you willing to submit a PR?

  • I'm willing to submit a PR!

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions