Skip to content

DateTime field should be truncated to minutes #4645 - #4646

Merged
ashklianko merged 3 commits into
masterfrom
issue-4645
Aug 25, 2026
Merged

DateTime field should be truncated to minutes #4645#4646
ashklianko merged 3 commits into
masterfrom
issue-4645

Conversation

@sgauruseu

Copy link
Copy Markdown
Member

No description provided.

@sgauruseu
sgauruseu requested a review from ashklianko August 21, 2026 10:27
Copilot AI lite review requested due to automatic review settings August 21, 2026 10:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the DateTime/Instant form inputs and descriptors so the UI and default-value handling operate at minute precision (dropping seconds and fractional seconds), aligning with the minute-granular pickers.

Changes:

  • Truncate DateTime/Instant default values (including relative expressions like now, +1d) to minute precision.
  • Render Instant/DateTime inputs at HH:mm precision, and update tests to cover truncation behavior.
  • Tighten public surface area by changing component barrel exports to avoid re-exporting test-only helpers.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/main/resources/assets/admin/common/js/form2/descriptor/InstantDescriptor.ts Truncates parsed instants/offsets/relative defaults to minute precision before creating Value.
src/main/resources/assets/admin/common/js/form2/descriptor/InstantDescriptor.test.ts Updates and adds tests asserting minute-precision defaults for Instant parsing.
src/main/resources/assets/admin/common/js/form2/descriptor/DateTimeDescriptor.ts Adds truncateToMinutes() and uses it to drop seconds/fractions for DateTime defaults.
src/main/resources/assets/admin/common/js/form2/descriptor/DateTimeDescriptor.test.ts Adds tests for minute truncation and for the new helper.
src/main/resources/assets/admin/common/js/form2/components/instant-input/InstantInput.tsx Displays Instant values in minutes (HH:mm); exports helper functions for tests.
src/main/resources/assets/admin/common/js/form2/components/instant-input/InstantInput.test.ts Switches to testing exported helpers; adds assertions that seconds/fractions aren’t displayed.
src/main/resources/assets/admin/common/js/form2/components/instant-input/index.ts Changes barrel export to avoid re-exporting helper functions.
src/main/resources/assets/admin/common/js/form2/components/date-time-input/index.ts Changes barrel export to avoid re-exporting helper functions.
src/main/resources/assets/admin/common/js/form2/components/date-time-input/DateTimeInput.tsx Truncates displayed DateTime values to minutes via shared helper.
src/main/resources/assets/admin/common/js/form2/components/date-time-input/DateTimeInput.test.ts Adds tests asserting valueToDisplay() truncates values with seconds/fractions.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 33 to 36
export function displayToStorage(s: string): string {
const date = new Date(s.replace(' ', 'T'));
if (Number.isNaN(date.getTime())) return `${s.replace(' ', 'T')}Z`;
const y = date.getUTCFullYear();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 05b8856.

displayToStorage() no longer appends Z when new Date(...) fails. That Z asserted "this is a valid UTC instant", which is exactly what an unparseable string is not: 2025-99-99 14:30 became 2025-99-99T14:30Z, which passes ValueTypeDateTime.isConvertible() (regex only) and then throws in DateTime.fromString():

Error: Invalid date string for Instant: 2025-99-99T14:30Z

Without the Z the fallback no longer matches the instant pattern, so newValue() returns a null value and the field shows the usual invalid-value validation instead of crashing. No regression is possible here: the fallback only runs when new Date() returns NaN, i.e. when no correct storage value exists for that input at all.

Went with this over wrapping newValue() in try/catch, since the latter would leave the same trap for every other caller.

Tests added for an impossible date (2025-99-99 14:30) and an out-of-range time (2025-06-15 25:99), plus the existing fallback test updated.

Note the root cause is broader: ValueTypeDateTime.isValid() validates by regex only, so any YYYY-99-99THH:mmZ string reaching newValue() throws regardless of the caller. Left out of this PR as it touches a widely used value type.

Drafted with AI assistance

Stopped appending `Z` to unparseable input in `displayToStorage`, so an impossible date no longer satisfies the instant pattern and makes `ValueTypeDateTime.newValue()` throw.
Added tests for an impossible date and an out-of-range time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sgauruseu sgauruseu linked an issue Aug 21, 2026 that may be closed by this pull request
Validated typed input with `DateHelper.parseDateTime`, so impossible dates no longer throw in `LocalDateTime.fromString` and no longer roll over to another date in Instant
Rejected input carrying seconds, so a typed value can no longer differ from the minute precision the field shows
Replaced `DISPLAY_PATTERN`, `parseDateFromDisplay`, `parseTimeFromDisplay` and `displayToStorage` with a single `parseDateTime` call shared by the input and the picker prefill
Exported `displayToValue` and `formatTimezoneLabel`, dropping the local copies of implementation the tests were pinning instead of the shipped code

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ashklianko

Copy link
Copy Markdown
Member

Pushed 4ba2e2a — scope grew a little past display truncation. Typed input in both fields is now validated with DateHelper.parseDateTime before a value is built. That closes the crash class from the review comment above on the DateTime side as well: 2025-02-30 09:15 passes the LocalDateTime regex and then throws in fromString, while Instant silently stored the same input as 2025-03-02T08:15:00Z. Input carrying seconds is now rejected rather than truncated, so a typed value can no longer differ from the minute precision the field displays — the docs specify yyyy-MM-dd hh:mm for both types.

DISPLAY_PATTERN, parseDateFromDisplay, parseTimeFromDisplay and displayToStorage are replaced by that single call, so the write path and the picker prefill can no longer disagree. This is the validator legacy used (DateTimePickerDateHelper.parseDateTime, which also zeroed seconds), so T-separated and date-only input are rejected again as they were before form2 — that leniency on master was a side effect of passing raw text to newValue(). Descriptor validate() is untouched, so existing content carrying seconds still reads fine.

Drafted with AI assistance

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

@ashklianko
ashklianko merged commit 40ae9ce into master Aug 25, 2026
5 checks passed
@ashklianko
ashklianko deleted the issue-4645 branch August 25, 2026 13:18
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.

DateTime field should be truncated to minutes

3 participants