Skip to content

[2.x] Validate the date-time format without Ethlo with the time format rules (#1316) - #1336

Merged
stevehu merged 4 commits into
networknt:2.xfrom
Obrams:fix/1316-date-time-fallback-2.x
Oct 20, 2026
Merged

stevehu merged 4 commits into
networknt:2.xfrom
Obrams:fix/1316-date-time-fallback-2.x

Conversation

@Obrams

@Obrams Obrams commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

2.x counterpart of #1335. Refs #1316, the fallback items: the empty fraction, the missing seconds and the hour-only offset that JavaTimeOffsetDateTime.isValid accepts without Ethlo. The Ethlo items (-00:00, offsets past ±18:00, fractions longer than 9 digits) are not in here.

Problem

Without Ethlo on the classpath, date-time on 2.x is checked with OffsetDateTime.parse(..), the same as on master: DateFormat.java, DateTimeFormat.java and TimeFormat.java are identical on both branches. So 2.x accepts 2020-01-01T12:00Z (no seconds), +01 (no offset minutes), +01:00:00 (offset seconds) and 12:00:00.Z (empty fraction), and rejects a leap second, an offset beyond ±18:00 and a fraction longer than nine digits, which RFC 3339 allows and format: time accepts since #1315.

Fix

The commits from #1335 cherry-picked as they are, no conflicts. The fallback checks the three parts of full-date "T" full-time separately: the T/t separator, the date through DateFormat.isValid(..) and the time through TimeFormat.parse(..), which returns the parsed fields; isValid on both is the former matches(..) body. A leap second is accepted only at the end of a June 30 or a December 31 in UTC, after applying the offset. TimeFormat also gets the range check on the hour and minute of a leap second and the explicit HH:MM:SS check, so format: time on 2.x is fixed with it and has its own CHANGELOG line.

With Ethlo on the classpath nothing changes, so Draft 4/6/7 with default settings are not affected.

As on master, one difference between the two paths remains: Ethlo also checks that a leap second was actually inserted on that date, the fallback doesn't carry that table. The CHANGELOG says so.

Tests

The same tests as in #1335, including the one that loads the library through a class loader without Ethlo and validates date-time through a schema. DateTimeFormatTest, TimeFormatTest and DateFormatTest pass on 2.x (94 tests). Changelog entries added under Unreleased on 2.x.

The java.time fallback accepted a time without seconds, an offset
without minutes or with seconds and an empty fraction, and rejected a
leap second and an offset beyond 18:00. It now parses the date on its
own and checks the time with the rules of the time format.

Refs networknt#1316
@stevehu

stevehu commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Review notes. This branch's source and tests are identical to the master PR (#1335), so the same findings apply. I built the 2.x branch and DateTimeFormatTest / TimeFormatTest pass.

  1. Leap-second path lacks a range check on the local hour/minute. 2020-01-01T24:59:60+01:00, 2020-01-01T23:89:60+00:30 and 2020-01-01T45:59:60+22:00 are accepted by the fallback. OffsetDateTime.parse and Ethlo both reject them. Fix: require hr <= 23 && min <= 59 before normalizing in TimeFormat.isValid.
  2. Leap seconds are accepted on any date (2021-03-15T23:59:60Z), where Ethlo only allows June 30 / December 31. This is a new fail-open compared with the old fallback, so either check the date or call it out in the CHANGELOG.
  3. Test gaps: overflow cases from (1), negative-offset leap seconds, calendar edges (2021-02-29, 2020-13-01), and an explicit assertion that Ethlo is on the classpath for bothPathsRejectValuesThatAreNotRfc3339.
  4. Smaller points: seconds-less rejection depends on a swallowed exception from getLong(SECOND_OF_MINUTE). The date check duplicates DateFormat. The CHANGELOG entry doesn't flag the fail-open behavior.
  5. The description says "counterpart of #MMMM", which should be Validate the date-time format without Ethlo with the time format rules (#1316) #1335.

Details and repro values are in the comment on #1335.

…llback

Review of networknt#1335: a leap second has to be at the end of a June 30 or a
December 31 in UTC, the hour and minute of a leap second are range
checked, a time without seconds is rejected explicitly, and the date
goes through DateFormat.

Refs networknt#1316
@Obrams

Obrams commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review, all of it is in the second commit (9118992, cherry-picked to #1336 as dc8d957).

  1. Range check on the leap second path: TimeFormat.isValid now rejects hr > 23 || min > 59 || sec > 60 before it normalizes to UTC, so 24:59:60+01:00, 23:89:60+00:30 and 45:59:60+22:00 fail. This was in TimeFormat before this PR, so format: time had the same hole; both are covered by the new TimeFormatTest cases.

  2. Leap second date: went with checking the date rather than noting it. The fallback converts the local date and time to UTC with the offset and requires June 30 or December 31, 23:59. So 2017-01-01T00:59:60+01:00 and 2016-12-31T18:59:60-05:00 pass, 2021-03-15T23:59:60Z and 2016-12-31T23:59:60+01:00 don't. Ethlo goes one step further and checks that a leap second was really inserted on that date; the fallback doesn't carry that table, which the CHANGELOG now says.

  3. Seconds: TimeFormat.isValid checks the HH:MM:SS structure up front instead of relying on getLong(SECOND_OF_MINUTE) throwing.

  4. Date: DateFormat.matches moved to a static isValid, the same shape as TimeFormat, and the fallback calls it, which also gives it the 0–9999 year range.

  5. Tests: the overflow values from (1), negative-offset and wrapped-date leap seconds, 2021-02-29, 2020-13-01, 23:59:61, and bothPathsRejectValuesThatAreNotRfc3339 now asserts that com.ethlo.time.ITU loads before going through the schema. 87 tests across the three format test classes, mvn test is green (9089, 30 skipped as before).

@Obrams

Obrams commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Same commits cherry-picked, see #1335.

@stevehu

stevehu commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Thanks for the second commit. I re-reviewed dc8d957 against the master PR (#1335). The source is identical, and DateTimeFormatTest and TimeFormatTest pass here (34 and 53 tests). The earlier correctness findings are fixed, and I found no remaining correctness bugs. Remaining points:

  1. Test parity with Validate the date-time format without Ethlo with the time format rules (#1316) #1335. Validate the date-time format without Ethlo with the time format rules (#1316) #1335 has a third commit (0e5974e) that this PR lacks. It adds negative-offset leap seconds (1998-12-31T15:59:60.123-08:00 valid, -07:00 invalid), the year-range edges (-001-01-01T00:00:00Z, 10000-01-01T00:00:00Z, 0000-01-01T00:00:00Z, 9999-12-31T23:59:59Z) and the Classes.isPresent assertion. Without them, nothing on 2.x pins the sign handling in offsetMinutes. Please cherry-pick it.
  2. Description placeholder. The description still says "2.x counterpart of #MMMM". It should say Validate the date-time format without Ethlo with the time format rules (#1316) #1335.
  3. Same minor points as on Validate the date-time format without Ethlo with the time format rules (#1316) #1335.
    • The leap-second date check duplicates the UTC normalization already in TimeFormat.isValid.
    • format: time now rejects previously accepted values and deserves its own CHANGELOG line.
    • The no-Ethlo wiring is not tested end to end.

…hout Ethlo

Review of networknt#1335: TimeFormat.parse returns the fields of a full-time and the
date-time fallback uses them for the leap second date instead of reading the
string again. The time format change gets its own CHANGELOG line, and a test
loads the library without Ethlo and validates date-time through a schema.

Refs networknt#1316
@Obrams

Obrams commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

0e5974e was already here as 39cfddd, pushed shortly after your review. fcd9bd6 is cherry-picked as abed82d. Description fixed.

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