Skip to content

WW-5814 Opt-in offset-aware ISO date-times for java.util.Date - #2059

Merged
lukaszlenart merged 1 commit into
mainfrom
WW-5814-dateconverter-iso-offset
Oct 25, 2026
Merged

lukaszlenart merged 1 commit into
mainfrom
WW-5814-dateconverter-iso-offset

Conversation

@lukaszlenart

Copy link
Copy Markdown
Member

Fixes WW-5814

Problem

DateConverter accepts ISO date-times ending in Z for java.util.Date properties (since WW-5813 through explicit 'Z'-literal formats), but treats the Z as a literal. 2026-10-25T05:14:42.000Z, the form JavaScript's Date.toISOString() produces, is read in the server's default time zone, so a UTC timestamp from a client is shifted by the server's offset. Numeric offsets (+02:00) are rejected.

Change

Reading Z as UTC changes the instant every existing ...Z value converts to, silently and with no conversion error, so it is opt-in:

  • new constant struts.converter.date.isoOffsetAware (StrutsConstants.STRUTS_CONVERTER_DATE_ISO_OFFSET_AWARE), default false in default.properties
  • false: unchanged, Z read as server-local time
  • true: a java.util.Date target (and Calendar, which converts through it) first tries DateTimeFormatter.ISO_OFFSET_DATE_TIME:
    • Z means UTC
    • numeric offsets are honoured
    • 0-9 fractional digits are read as a fraction (with the flag off, .5Z reads as 5 ms, because .SSS counts digits)
  • input without an offset falls through to the existing formats unchanged
  • a year outside Date's range is a conversion error instead of an escaping IllegalArgumentException

The default flips to true in 8.0.0: WW-5815.

Out of scope:

  • java.sql.Timestamp, which has no ISO support today
  • the java.time types: OffsetDateTime already parses offsets, and the Local* types have no zone
  • the JSON plugin's own date handling

Tests

  • Off by default, using the container's DateConverter.
  • Setting the constant through initDispatcher turns the reading on.
  • With the flag on:
    • Z with and without milliseconds is read as UTC
    • +02:00 is honoured
    • .5 reads as half a second
    • input without an offset keeps the local reading
    • an out-of-range year is rejected
  • The Z tests pin Asia/Tokyo as the default zone and restore it in tearDown, so they cannot pass vacuously on a UTC build machine.
  • Each test was seen failing first. The range check was also confirmed by removing it.
  • Full core suite on JDK 17 and JDK 25, plus the spring, junit, javatemplates and json plugins on JDK 17, all green.

Docs

  • 7.5.0 release notes: the new constant.
  • struts-site: the constant needs a line on the configuration page.

🤖 Generated with Claude Code

….util.Date

DateConverter reads the Z of an ISO date-time such as
2026-10-25T05:14:42.000Z as a literal, so a UTC timestamp from a client
is interpreted in the server's default time zone. Reading it correctly
shifts every such value by the server's offset without a conversion
error, so it is opt-in for 7.5.0: struts.converter.date.isoOffsetAware,
default false. WW-5815 flips the default in 8.0.0.

When enabled, a java.util.Date target (and Calendar, which converts
through it) first tries DateTimeFormatter.ISO_OFFSET_DATE_TIME: Z means
UTC, numeric offsets are honoured and 0-9 fractional digits are read as
a fraction. Input without an offset falls through to the existing
formats unchanged. A year outside Date's range is a conversion error.

The Z tests pin Asia/Tokyo as the default zone, so they cannot pass
vacuously on a UTC build machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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.

🟢 Approval recommended

Static review found no blocking issues in the opt-in behavior, configuration wiring, or regression coverage; tests were not executed during this review.

No open issues 🎉

What changed in this PR

Adds opt-in offset-aware ISO date-time parsing for java.util.Date in Struts, preserving existing behavior by default.

Changes:

  • Introduces struts.converter.date.isoOffsetAware, defaulting to false.
  • Parses UTC and numeric offsets when enabled, with conversion errors for dates outside the supported range.
  • Adds regression tests for configuration wiring, offsets, fractional seconds, and legacy fallback behavior.
File Description
core/​src/​test/​java/​org/​apache/​struts2/​conversion/​impl/​DateConverterTest.java Tests opt-in parsing and backward compatibility.
core/​src/​main/​resources/​org/​apache/​struts2/​default.properties Documents and disables the option by default.
core/​src/​main/​java/​org/​apache/​struts2/​StrutsConstants.java Defines the public configuration constant.
core/​src/​main/​java/​org/​apache/​struts2/​conversion/​impl/​DateConverter.java Implements offset-aware parsing and range-error handling.

Review effort: Balanced

@sonarqubecloud

Copy link
Copy Markdown

@lukaszlenart
lukaszlenart merged commit f8df275 into main Oct 25, 2026
9 checks passed
@lukaszlenart
lukaszlenart deleted the WW-5814-dateconverter-iso-offset branch October 25, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants