Skip to content

Cube brush on a time-zone-aware source (not UTC) commits its edges in the wrong zone #139

Description

@jvdd

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:

  1. 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.
  2. 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.
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions