Skip to content

Honour the time-precision extension on dateTime, time and Period boundaries - #135

Merged
bryantaustin13 merged 1 commit into
mainfrom
claude/focused-galileo-yvz3wv
Sep 21, 2026
Merged

bryantaustin13 merged 1 commit into
mainfrom
claude/focused-galileo-yvz3wv

Conversation

@alexzautke

Copy link
Copy Markdown
Contributor

Why

FHIR dateTime and time require minutes and seconds once an hour is present, but CQL allows hour- and minute-precision values (@2005-05-10T10, @T10). An engine that returns valid FHIR from $cql therefore has to zero-pad the missing components, and the FHIR extensions pack provides time-precision (trial-use, value set of UCUM time-duration codes) to declare the real precision on the primitive element (_valueDateTime, _valueTime, _start, _end).

Firely Server (via the Firely CQL SDK) emits exactly that, and today the runner reads 2005-05-10T10:00:00Z + time-precision = h as @2005-05-10T10:00:00Z, so every hour- or minute-precision result fails against expectations such as @2005-05-10T10 or { @T10, @T11, @T12 }. The DateTimeExtractor already carried a TODO for this.

What

  • value-type-extractor-utils.ts: declaredTimePrecision(element) reads the extension from a primitive's companion element; applyDeclaredTimePrecision(value, element) drops the components padded beyond the declared precision (h → hh, min → hh:mm, s → hh:mm:ss, ms → unchanged). Values without the extension, with a code outside h/min/s/ms, or without a time-of-day are returned unchanged, and any timezone offset is kept as sent. Nothing changes for engines that do not send the extension.
  • DateTimeExtractor, TimeExtractor and DateTimeIntervalExtractor apply it to valueDateTime/_valueDateTime, valueTime/_valueTime and valuePeriod.start|end / _start|_end.
  • Unit tests for each extractor (hour, minute, second, millisecond, unknown code, date-only value, list of times, Period boundaries incl. Interval<System.Time>), and a README paragraph next to the existing quantity-precision note.

Effect on cql-tests against a conformant engine

Verification

npx vitest run test/: 235 passed (224 before). tsc --noEmit clean. Prettier clean on the touched src/ and test/ files (README.md already fails prettier --check on main, unchanged here).

🤖 Generated with Claude Code

https://claude.ai/code/session_01HrgCec45seYogQkmqRpSUi


Generated by Claude Code

…daries

FHIR dateTime and time require minutes and seconds once an hour is
present, while CQL allows hour- and minute-precision values. An engine
that emits valid FHIR zero-pads the missing components and declares the
real precision with the time-precision extension
(http://hl7.org/fhir/StructureDefinition/time-precision) on the
primitive element. The extractors now drop the padded components again,
so `2005-05-10T10:00:00Z` declared at `h` is read as `@2005-05-10T10Z`
and compares against the `@2005-05-10T10` style expectations in
cql-tests. Values without the extension, with an unknown code, or
without a time-of-day are unchanged, as is any timezone offset.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HrgCec45seYogQkmqRpSUi
@alexzautke
alexzautke marked this pull request as ready for review September 17, 2026 17:53

@bryantaustin13 bryantaustin13 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.

Looks good

@bryantaustin13
bryantaustin13 merged commit 3698c34 into main Sep 21, 2026
bryantaustin13 added a commit that referenced this pull request Sep 22, 2026
Resolves the conflict in datetime-interval-extractor.ts, which arose because this
branch predates #129 and #135 and carried an older copy of the whole file.

Taking either side alone would have lost work:

- main's side drops this branch's null guards and its `highClosed: high !== null`,
  leaving an absent Period boundary reported as closed.
- this branch's side drops #135's applyDeclaredTimePrecision on the `_start`/`_end`
  companion elements and #129's List<...> unwrapping in declaredPointType, which
  would have reverted time-precision support and lists of temporal intervals.

The resolution keeps all of it: this branch's early-return guards and derived
highClosed, wrapping main's precision-aware boundary extraction, with #129's
List unwrapping untouched above.

Verified after resolution: 247 tests pass, and each behaviour checked directly —
a Period with hour time-precision extracts as @T10/@t12, List<Interval<System.Date>>
still resolves to Date literals, an absent end yields highClosed:false, and null
valuePeriod / valueRange / boundary no longer throw. tsc reports only the two
pre-existing rest-routes.ts errors present on main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

3 participants