diff --git a/.metis/backlog/bugs/GQLITE-T-0342.md b/.metis/backlog/bugs/GQLITE-T-0342.md new file mode 100644 index 00000000..bca35c56 --- /dev/null +++ b/.metis/backlog/bugs/GQLITE-T-0342.md @@ -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). diff --git a/.metis/backlog/bugs/GQLITE-T-0343.md b/.metis/backlog/bugs/GQLITE-T-0343.md new file mode 100644 index 00000000..2fbaae84 --- /dev/null +++ b/.metis/backlog/bugs/GQLITE-T-0343.md @@ -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]]. diff --git a/.metis/backlog/bugs/GQLITE-T-0344.md b/.metis/backlog/bugs/GQLITE-T-0344.md new file mode 100644 index 00000000..f29febc9 --- /dev/null +++ b/.metis/backlog/bugs/GQLITE-T-0344.md @@ -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]]. diff --git a/.metis/initiatives/GQLITE-I-0049/tasks/GQLITE-T-0341.md b/.metis/initiatives/GQLITE-I-0049/tasks/GQLITE-T-0341.md index e04f07ea..6edb2b92 100644 --- a/.metis/initiatives/GQLITE-I-0049/tasks/GQLITE-T-0341.md +++ b/.metis/initiatives/GQLITE-I-0049/tasks/GQLITE-T-0341.md @@ -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