Problem
A cube brush on a histogram over a time-zone-aware Datetime column whose zone is not UTC keeps the wrong rows.
The client commits each edge as a UTC wall-clock string without an offset: fvPhysicalToTemporal in runtime/cube.js formats the physical value with getUTC*. The server reads a string without an offset on a zone-aware column as wall-clock time in the column's zone (_typed_temporal_lit in trace/base.py). So each bound moves by the zone's UTC offset, which is 1 or 2 hours for Europe/Brussels. The committed selection then keeps other rows than the bars that the user brushed.
Reproduction
At the predicate level, on fix/cube-source-grid (PR #134). main builds the strings the same way.
import datetime as dt
import polars as pl
from flexviz.predicates import predicates_to_expr
from flexviz.spec import SelectionPredicate
row = dt.datetime(2024, 8, 2, 6, 4, 2, 441000, tzinfo=dt.timezone.utc)
# What the cube commits for the bar that holds the row: UTC wall-clock time.
rng = ["2024-08-02 06:04:02.441000", "2024-08-02 06:04:02.455000"]
for tz in ("UTC", "Europe/Brussels"):
df = pl.DataFrame({"t": pl.Series([row]).dt.convert_time_zone(tz)})
clause = {"column": "t", "range": rng, "closed": "left"}
pred = SelectionPredicate.model_validate({"clauses": [clause]})
print(tz, df.filter(predicates_to_expr([pred], df.schema)).height)
# UTC 1
# Europe/Brussels 0
A bound that falls in the spring daylight-saving gap of the zone, for example 2024-03-31 02:30:00 for Europe/Brussels, raises a ComputeError when the query is collected: "datetime '2024-03-31 02:30:00' is non-existent in time zone 'Europe/Brussels'".
Scope
Fix direction
Find out in which zone the display draws a zone-aware column first. Then pick one:
- Send each edge with an explicit offset (
Z). _typed_temporal_lit already converts an offset string to the UTC instant on a zone-aware column, and keeps the wall-clock time on a naive column. The box needs a separate string that Plotly can parse.
- Send the column's zone in the cube header, and format the strings as wall-clock time in that zone, as the display shows them. Bounds in a daylight-saving gap or overlap still need a rule.
- Refuse a cube for a zone-aware column whose zone is not UTC, as for
Datetime("ns"), so the brush falls back to the server path.
Found in the review of PR #134.
Problem
A cube brush on a histogram over a time-zone-aware
Datetimecolumn whose zone is not UTC keeps the wrong rows.The client commits each edge as a UTC wall-clock string without an offset:
fvPhysicalToTemporalinruntime/cube.jsformats the physical value withgetUTC*. The server reads a string without an offset on a zone-aware column as wall-clock time in the column's zone (_typed_temporal_litintrace/base.py). So each bound moves by the zone's UTC offset, which is 1 or 2 hours forEurope/Brussels. The committed selection then keeps other rows than the bars that the user brushed.Reproduction
At the predicate level, on
fix/cube-source-grid(PR #134).mainbuilds the strings the same way.A bound that falls in the spring daylight-saving gap of the zone, for example
2024-03-31 02:30:00forEurope/Brussels, raises aComputeErrorwhen the query is collected: "datetime '2024-03-31 02:30:00' is non-existent in time zone 'Europe/Brussels'".Scope
Fix direction
Find out in which zone the display draws a zone-aware column first. Then pick one:
Z)._typed_temporal_litalready converts an offset string to the UTC instant on a zone-aware column, and keeps the wall-clock time on a naive column. The box needs a separate string that Plotly can parse.Datetime("ns"), so the brush falls back to the server path.Found in the review of PR #134.