Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .metis/backlog/bugs/GQLITE-T-0342.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
id: dst-duration-across-transition
level: task
title: "DST: duration across a DST transition ignores the gained/lost hour"
short_code: "GQLITE-T-0342"
created_at: 2026-06-01T00:00:00.000000+00:00
updated_at: 2026-06-01T00:00:00.000000+00:00
parent:
blocked_by: []
archived: false
tags:
- "#task"
- "#phase/backlog"
- "#bug"
exit_criteria_met: false
initiative_id: NULL
---

# DST: duration across a DST transition ignores the gained/lost hour

## Type
- [x] Bug

## Priority
- [ ] P2 - Medium (TCK conformance; blocks the "100% TCK" goal)

## Objective
`duration.inSeconds` / `duration.between` over an interval that crosses a DST
transition must account for the gained/lost hour (wall-clock vs elapsed time).
Closes **Temporal10 [8]** (8 examples).

## Impact Assessment
- **Affected:** openCypher TCK Temporal10 [8] "Should handle durations at daylight
saving time day" — 8 example rows.
- **Reproduction:**
```cypher
RETURN duration.inSeconds(
datetime({year:2017, month:10, day:29, hour:0, timezone:'Europe/Stockholm'}),
localdatetime({year:2017, month:10, day:29, hour:4})
) AS d
```
- **Expected vs Actual:** expected `PT5H` (2017-10-29 is the Stockholm fall-back
day; 00:00->04:00 wall clock = 5 real hours because 03:00 falls back to 02:00);
actual `PT4H` (flat UTC diff using a single offset, missing the extra hour).
Also `... date({year:2017,month:10,day:30})` expects `PT25H`, we give `PT24H`.

## Root cause (shared — see also [[GQLITE-T-0343]] / [[GQLITE-T-0344]])
`apply_duration_to_temporal` / the temporal-diff helpers compute elapsed time with
ONE offset for the whole interval. Across a DST transition the offset changes
mid-interval, so the elapsed seconds differ from `end_utc - start_utc` computed
with a single offset. Correct handling needs the exact transition INSTANT for the
named zone, which requires real IANA tzdata (see T-0344). Implementation analysis
in [[GQLITE-T-0341]] (initiative [[GQLITE-I-0049]]).

## Acceptance Criteria
- [ ] Temporal10 [8] all 8 examples pass
- [ ] Zero TCK regressions (rigorous full pass-set diff); unit 944/944; functional clean

## Notes
Deferred from the +30 Temporal push (PR #88). Likely depends on the IANA-tzdata
work in [[GQLITE-T-0344]] (need transition instants, not just an offset-by-date).
64 changes: 64 additions & 0 deletions .metis/backlog/bugs/GQLITE-T-0343.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
id: dst-named-zone-offset-approximation
level: task
title: "DST: named-zone offset uses coarse month approximation, not historical rules"
short_code: "GQLITE-T-0343"
created_at: 2026-06-01T00:00:00.000000+00:00
updated_at: 2026-06-01T00:00:00.000000+00:00
parent:
blocked_by: []
archived: false
tags:
- "#task"
- "#phase/backlog"
- "#bug"
exit_criteria_met: false
initiative_id: NULL
---

# DST: named-zone offset uses coarse month approximation, not historical rules

## Type
- [x] Bug

## Priority
- [ ] P2 - Medium (TCK conformance; blocks "100% TCK")

## Objective
Resolve a named zone's UTC offset for a given date using the zone's actual DST
transition dates, including historical changes — not the current coarse
"April–September = summer" month heuristic. Closes **Temporal3 [10]** (2 remaining
tz-conversion examples) and is a prerequisite for clean DST elsewhere.

## Impact Assessment
- **Affected:** `named_tz_offset()` in `src/backend/runtime/udf_helpers.c`, used by
datetime construction, parsing, `duration.between`, the `.offset`/`.epochSeconds`
accessors, and time rendering.
- **Reproduction:**
```cypher
RETURN datetime({year:1984, month:3, day:28, hour:12, timezone:'Europe/Stockholm'})
```
Expected `1984-03-28T12:00+02:00[Europe/Stockholm]` (DST started 1984-03-25);
the coarse month rule yields `+01:00` for March. (Direct construction was made
to work; the SELECT/tz-conversion forms in Temporal3 [10] ex31/32 remain.)

## Root cause + the trap (CRITICAL)
The coarse heuristic is **load-bearing**. A naive "modern" last-Sunday-of-March..
October EU rule REGRESSED **-52 examples**, because the TCK uses HISTORICALLY
accurate IANA data: pre-1996 EU DST ended the last Sunday of SEPTEMBER (so
`1984-10-11 Stockholm = +01:00`, not `+02:00`). A regression-free improvement was
prototyped — historical end-month `(y>=1996)?Oct:Sep` + threading the real base
date into `_gql_tz_offset_for(tz, _gql_date_compose(... $.date, $.datetime))` — and
it fixes individual examples but flips no full scenario (so it was reverted to keep
PR #88 clean). Full correctness needs real IANA transition tables (see
[[GQLITE-T-0344]]). Detailed analysis: [[GQLITE-T-0341]] / [[GQLITE-I-0049]].

## Acceptance Criteria
- [ ] Temporal3 [10] all examples pass
- [ ] No regression in Temporal1 [10], Temporal3 [3]/[9]/[11] (the -52 trap)
- [ ] Rigorous full pass-set diff zero regressions; unit 944/944; functional clean

## Notes
Re-derive the regression-free foundation from the 2026-06-01 note in
[[GQLITE-T-0341]] when picking this up. Shares root cause with [[GQLITE-T-0342]],
[[GQLITE-T-0344]].
68 changes: 68 additions & 0 deletions .metis/backlog/bugs/GQLITE-T-0344.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
id: dst-named-zone-string-parse-lmt
level: task
title: "DST: datetime string parse doesn't resolve named-zone historical/LMT offset"
short_code: "GQLITE-T-0344"
created_at: 2026-06-01T00:00:00.000000+00:00
updated_at: 2026-06-01T00:00:00.000000+00:00
parent:
blocked_by: []
archived: false
tags:
- "#task"
- "#phase/backlog"
- "#bug"
exit_criteria_met: false
initiative_id: NULL
---

# DST: datetime string parse doesn't resolve named-zone historical/LMT offset

## Type
- [x] Bug

## Priority
- [ ] P3 - Low (needs an embedded IANA tz database; largest/most data-heavy)

## Objective
Parsing a datetime string that carries a named zone must insert the resolved
numeric offset (including pre-standardization Local Mean Time) before the
`[Region]` suffix. Closes **Temporal2 [6]** (2 examples) and is the umbrella
"embed IANA tzdata" work the other two DST bugs depend on.

## Impact Assessment
- **Affected:** `gql_normalize_datetime_func` in `src/backend/runtime/udf_helpers.c`.
- **Reproduction / Expected vs Actual:**
- `datetime('2015-07-21T21:40:32.142[Europe/London]')`
expected `2015-07-21T21:40:32.142+01:00[Europe/London]`,
actual `2015-07-21T21:40:32.142[Europe/London]` (no resolved offset inserted).
- `datetime('1818-07-21T21:40:32.142[Europe/Stockholm]')`
expected `1818-07-21T21:40:32.142+00:53:28[Europe/Stockholm]` — **Local Mean
Time** (Stockholm's longitude-based offset before standardized zones in 1879).

## Root cause
1. The datetime string normalizer keeps the `[Region]` bracket but never computes
and inserts the offset for the value's date.
2. `+00:53:28` cannot be produced by ANY rule — it is historical LMT data. This is
the hard floor: full Temporal DST conformance requires embedding the real IANA
tz database (transition instants + historical/LMT offset records). A rule-based
approximation (see [[GQLITE-T-0343]]) cannot reach these cases.

## Suggested approach
- Embed a compact subset of IANA tzdata for the zones the TCK exercises
(Europe/Stockholm, Europe/London, Europe/Paris, Europe/Berlin, America/New_York,
America/Los_Angeles, Pacific/Honolulu, America/Anchorage, Asia/Tokyo,
Asia/Shanghai, Australia/Sydney, Pacific/Auckland, Australia/Eucla, ...),
including historical transitions and pre-standard LMT, OR vendor a tz library.
- Replace `named_tz_offset` + the transition logic with lookups against it; this
then unblocks [[GQLITE-T-0342]] (across-transition elapsed) and
[[GQLITE-T-0343]] (offset-by-date).

## Acceptance Criteria
- [ ] Temporal2 [6] examples pass (incl. the 1818 LMT case)
- [ ] Rigorous full pass-set diff zero regressions; unit 944/944; functional clean

## Notes
This is the foundational DST item; [[GQLITE-T-0342]] and [[GQLITE-T-0343]] likely
collapse into it once real tzdata is available. Context: [[GQLITE-T-0341]],
[[GQLITE-I-0049]].
9 changes: 9 additions & 0 deletions .metis/initiatives/GQLITE-I-0049/tasks/GQLITE-T-0341.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,12 @@ Dug into the 12 remaining DST scenarios empirically. Findings:
- RECOMMENDATION: close T-0341 as "Temporal non-DST done (+30)"; open a separate
task "embed IANA tzdata for full temporal DST conformance" (large, data-heavy)
for the 12 DST scenarios.

### 2026-06-01: DST gaps filed as bugs
Non-DST Temporal closed via PR #88 (main 3758, +30). The 12 DST scenarios are now
tracked as follow-up bugs:
- [[GQLITE-T-0342]] — duration across a DST transition (Temporal10 [8], 8)
- [[GQLITE-T-0343]] — named-zone offset coarse approximation / historical rules
(Temporal3 [10], 2); documents the -52-regression trap
- [[GQLITE-T-0344]] — datetime string parse named-zone historical/LMT offset
(Temporal2 [6], 2); the foundational "embed IANA tzdata" item the others depend on
Loading