Skip to content

feat: date input - #529

Merged
stefan-gorules merged 3 commits into
masterfrom
feat/date-inputs
Sep 29, 2026
Merged

stefan-gorules merged 3 commits into
masterfrom
feat/date-inputs

Conversation

@stefan-gorules

Copy link
Copy Markdown
Contributor

Summary

Inputs declared as dates now arrive as real date values in graphs and policies, instead of plain strings. The caller's original text is kept, so outputs, string(), templates and string functions behave exactly as before, while date comparisons and methods work without d().

What changes

Declared dates are dates

  • Graph input node properties declared as { "type": "string", "format": "date" | "date-time" } (also nullable, anyOf [date, null], with annotation keys like title/description/examples) are converted to dates before downstream nodes run.
  • Policy data-model properties of type date (entities, relationships, references, globals, arrays) are converted before evaluation.
  • A converted date keeps the caller's text: graph/policy output, traces, JSON-schema output validation, JS function nodes and bindings all see the exact input string (offsets, milliseconds and date-only values echo back unchanged).
  • A date passed into a child graph input declared as a plain string, or a child with no input schema, arrives as its text.

Parsing (d() and inputs share one parser)

  • Strings with an explicit offset or Z keep their real instant (previously the offset was dropped and the wall-clock time was read in the server zone).
  • Local times inside a DST gap move forward by the gap instead of failing.
  • New accepted forms: ISO without offset (2023-10-15T14:30[:45[.123]]), compact (20231015, 20231015T1430[45]), offset variants (+0200, +02, +02:00), slash dates (2023/10/15[ 14:30[:45]]), 2023-10, 2023. New forms are matched by exact shape; existing formats are unchanged.
  • d(dateField, 'Zone') re-reads the field's original text in that zone, as before.

Dates and strings work together

  • ==, !=, <, <=, >, >=, in, contains between a date and a string compare as dates (e.g. birthDate == '1990-05-01', string cells in decision tables).
  • String positions accept a converted date via its text: string functions, object keys (rates[d], d in obj), indexing and slicing, concatenation, bool().
  • Deprecated date helpers (date, time, year, dayOfWeek, dateString, startOf, …) accept dates.
  • string(date) works for all dates; type(date) returns 'date'.

Type checker

  • Declared dates are typed date; date/string comparisons, membership and concatenation are allowed; a date is accepted where a string argument or slicing is expected.
  • Calling a date method on a string or number errors with a hint to use d(...).

Behaviour changes

  • Policy date fields must hold a parseable date (empty string still allowed); arbitrary text is now rejected at input validation.
  • Time methods on offset strings (e.g. d('…T10:00:00+05:00').hour()) use the real instant in the server zone.
  • A plain string compared with a date is no longer a static error.
  • type() of a declared date field is 'date'.

Testing

  • New cases in core/expression/tests/data/date.csv (formats, offsets, DST gaps, near-misses, date/string comparisons).
  • All corpora compared against master with the .temp probe: expressions, graphs, graph/policy diagnostics and policies identical; one intended analysis change (string vs date comparison).
  • Performance: d() parsing at master speed; converting 15k declared dates adds ~0.1 s (graphs) / ~0.08 s (policies).

- graph format:date/date-time inputs and policy date properties arrive as
  dates that keep their original text for output, string() and string
  functions
- d() keeps the instant of offset/Z strings, resolves DST gaps and accepts
  ISO forms without offset, compact, slash-separated, YYYY-MM and YYYY
- dates compare with date strings in ==, !=, <, >, in and contains, and
  concatenate with strings; deprecated date helpers accept dates
- string(date), type() reports date, and date-to-string at string inputs
- parse new date formats by exact shape; keep master formats first and
  guard DST-gap and extreme-year overflows
- text-carrying dates act as strings for object keys, in-object, index,
  slice, concatenation and bool
- deprecated helpers fall back to the date instant; time() accepts dates
- schema-less child inputs receive date text; dates satisfy string
  parameters and slicing in the type checker
- convert policy input before validation so dates are parsed once;
  share rewrite helpers between graph and policy conversion
- every valid date exposes a text form (original or RFC3339), so string
  functions and slicing on computed dates match the type checker
- date and string types merge to string; reference ids typed as dates
  resolve through their text
- input nodes convert declared dates and hand every other converted date
  back as its original text, following combinators only for structure
- date format checks no longer allocate
@stefan-gorules
stefan-gorules merged commit 39916c9 into master Sep 29, 2026
59 checks passed
@stefan-gorules
stefan-gorules deleted the feat/date-inputs branch September 29, 2026 08:00
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