[ 
https://issues.apache.org/jira/browse/WW-5686?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Lukasz Lenart updated WW-5686:
------------------------------
    Summary: <s:date/> renders a java.sql.Date with the current wall-clock 
time, making DateTest.testJavaSqlDate flaky  (was: &lt;s:date/&gt; renders a 
java.sql.Date with the current wall-clock time, making DateTest.testJavaSqlDate 
flaky)

> <s:date/> renders a java.sql.Date with the current wall-clock time, making 
> DateTest.testJavaSqlDate flaky
> ---------------------------------------------------------------------------------------------------------
>
>                 Key: WW-5686
>                 URL: https://issues.apache.org/jira/browse/WW-5686
>             Project: Struts 2
>          Issue Type: Bug
>            Reporter: Lukasz Lenart
>            Priority: Minor
>
> {{org.apache.struts2.components.Date.end}} fills in the missing time-of-day 
> of a {{java.sql.Date}} from the current clock:
> {code:java}Object dateObject = findValue(name);
> if (dateObject instanceof java.sql.Date) {
>     date = ((java.sql.Date) 
> dateObject).toLocalDate().atTime(LocalTime.now(tz)).atZone(tz);
> } else if (dateObject instanceof java.sql.Time) {
>     date = ((java.sql.Time) 
> dateObject).toLocalTime().atDate(ZonedDateTime.now(tz).toLocalDate()).atZone(tz);
> }
> {code}
> Two consequences.
> h3. 1. The rendered output is non-deterministic
> A {{java.sql.Date}} carries no time-of-day, so any format that includes time 
> fields renders whatever the wall clock happens to say at render time. The 
> same value rendered twice in one page produces two different strings.
> This was not always the behaviour. WW-5197 (6.0.3) added {{java.sql.Date}} 
> support as {{toLocalDate().atStartOfDay(tz)}} — deterministic midnight. 
> WW-5272 (commit {{08de24588}}, 6.2.0, "Extends &lt;s:date/&gt; to support 
> java.sql.Time") changed it to {{atTime(LocalTime.now(tz))}} while adding the 
> {{java.sql.Time}} branch, and changed {{DateTest}} in the same commit from 
> {{getDateInstance(MEDIUM)}} to {{getDateTimeInstance(MEDIUM, MEDIUM)}} so the 
> assertion would cover the newly rendered time. The {{java.sql.Time}} branch 
> genuinely needs a date to complete a {{ZonedDateTime}}, but the 
> {{java.sql.Date}} branch has no equivalent need for _now's_ time — midnight 
> completed it just as well, and did so reproducibly. This looks like 
> collateral of the {{java.sql.Time}} work rather than an intended change to 
> {{java.sql.Date}} rendering, and it shipped without a note.
> h3. 2. {{DateTest.testJavaSqlDate}} is inherently flaky
> The test builds its expected string from {{new 
> java.sql.Date(System.currentTimeMillis())}}, whose underlying millis still 
> carry the capture-time time-of-day, and compares it against output whose time 
> comes from {{LocalTime.now()}} at render. The two disagree whenever the clock 
> crosses a second boundary between the two calls.
> Observed on the SonarCloud job of [PR 
> #1859|https://github.com/apache/struts/pull/1859] (an unrelated OGNL change):
> {code}DateTest.testJavaSqlDate:104 expected:<Aug 23, 2026, 4:37:1[4] PM> but 
> was:<Aug 23, 2026, 4:37:1[5] PM>
> {code}
> The same commit passed Build and Test on JDK 17, 21 and 25 — only that one 
> job happened to straddle the boundary. The failure window is roughly the 
> elapsed time between the two calls, so it is rare but will keep failing 
> unrelated PRs.
> {{testJavaSqlTime}} is not affected in practice: it formats with 
> {{hh:mm:ss}}, and {{toLocalTime()}} preserves the value's own time, so the 
> substituted date is never rendered. It would only misfire across a midnight 
> boundary.
> h3. Suggested fix
> Restore {{toLocalDate().atStartOfDay(tz)}} for {{java.sql.Date}} and assert 
> against a fixed instant in the test rather than the current time. That 
> reverts {{java.sql.Date}} rendering to its pre-6.2.0 semantics, so it needs a 
> Version Notes entry.
> If the current behaviour is instead considered intentional, the test still 
> has to stop racing the clock — inject a fixed clock or assert only the date 
> fields — and the substitution should be documented on the tag.
> _Affects:_ 6.2.0 onwards, on every maintained line.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to