Time Primitives#

Classes that represent time anchors and time windows used throughout variable extraction. TimeAnchor wraps a column name and an optional offset; TimeWindow pairs a tmin and tmax anchor into a single object passed through the extraction pipeline.

class corr_vars.utils.time.TimeAnchor(bound)[source]#

Bases: object

Parameters:

bound (str | tuple[str, str] | datetime | date | Expr)

column: str | None#
delta: tuple[str, ...] | None#
expr: Expr#
property is_relative: bool#

Whether a delta was applied — independently of what it was applied to.

property is_literal: bool#

Whether this anchor is a fixed timestamp rather than a column.

copy()[source]#

Return a copy of this anchor.

The copy shares only immutable state — column, delta and the polars expression — so re-pointing one of them leaves the original alone.

Return type:

TimeAnchor

shifted_by(delta)[source]#

Return a copy of this anchor moved by delta.

Deltas stack: shifting ("icu_admission", "+2h") by "-1h" keeps the column, applies both offsets and appends to delta. A fixed timestamp is moved to the offset timestamp.

Either way the result reports is_relative, and a shifted literal stays is_literal: the two describe different things — what the anchor is fixed to, and whether it was moved.

Parameters:

delta (str | timedelta) – Offset such as "24h" or "-30m".

Returns:

The shifted anchor.

Return type:

TimeAnchor

Raises:

ValueError – If delta is not a valid offset, or if shifting a fixed timestamp leaves the representable datetime range — which is what moving UNBOUNDED_TMIN further back or UNBOUNDED_TMAX further forward does.

class corr_vars.utils.time.TimeWindow(tmin=None, tmax=None)[source]#

Bases: object

Parameters:
  • tmin (TimeAnchor | str | tuple[str, str] | datetime | date | None)

  • tmax (TimeAnchor | str | tuple[str, str] | datetime | date | None)

tmin: TimeAnchor#
tmax: TimeAnchor#
classmethod from_obs_level(obs_level)[source]#

Build a TimeWindow from an observation level’s t_min / t_max.

Parameters:

obs_level (ObsLevel)

Return type:

TimeWindow

classmethod from_anchor_and_duration(anchor, duration)[source]#

Build [anchor, anchor + duration] from one anchor and a length.

Spares callers from repeating the anchor on both bounds — instead of TimeWindow("icu_admission", ("icu_admission", "+28d")) write TimeWindow.from_anchor_and_duration("icu_admission", "28d"). This is the natural shape for a T0-plus-horizon follow-up window.

Parameters:
  • anchor (TimeAnchor | str | tuple[str, str] | datetime | date) – The window start (T0). A column name, (column, delta) tuple, datetime/date literal, or an existing TimeAnchor.

  • duration (str | timedelta) – Horizon length as a polars-duration string ("28d") or a timedelta. A leading sign is optional (+).

Return type:

TimeWindow

anchored_to_day(day_start=None)[source]#

Return a copy with both bounds snapped to a day boundary.

Snaps tmin and tmax via truncate_to_day() (day_start=None for calendar days, "6h" for ICU days). The original window is unchanged, so only the caller that wants day-anchored bounds is affected. When tmax is tmin + Nd both bounds shift by the same intra-day amount, so the horizon length is preserved.

Parameters:

day_start (str | timedelta | None)

Return type:

TimeWindow

time_difference(*, unit='s', total=True)[source]#
Parameters:
  • unit (Literal['s', 'm', 'h', 'd', 'w'])

  • total (bool)

Return type:

Expr

property tmin_expr: Expr#
property filled_tmin_expr: Expr#
property tmax_expr: Expr#
property filled_tmax_expr: Expr#
property tmid_expr: Expr#
property duration_expr: Expr#
property is_relative: bool#
property is_literal: bool#
property any_timebound_in_year_9999_expr: Expr#
property any_timebound_null_expr: Expr#
property tmin_after_tmax_expr: Expr#
class corr_vars.utils.time.WindowRelation(value)[source]#

Bases: Flag

CONTAINED = 1#
OVERLAPS_LEFT = 2#
OVERLAPS_RIGHT = 4#
COVERS_WINDOW = 8#
ANY_LEFT_OVERLAP = 11#
ANY_RIGHT_OVERLAP = 13#
ANY_OVERLAP = 15#
class corr_vars.utils.time.WindowOverlap[source]#

Bases: object

static contains_expr(record, window, closed='both')[source]#
Parameters:
Return type:

Expr

static relation_expr(record, window)[source]#
Parameters:
Return type:

dict[WindowRelation, Expr]

static overlap_expr(record, window, relation)[source]#
Parameters:
Return type:

Expr

static classify_expr(record, window, *, default=None)[source]#
Parameters:
Return type:

Expr

corr_vars.utils.time.compatible_with_time_anchor(df, time_anchor)[source]#
Parameters:
  • df (DataFrame | LazyFrame)

  • time_anchor (TimeAnchor)

Return type:

bool

corr_vars.utils.time.compatible_with_time_window(df, time_window)[source]#
Parameters:
  • df (DataFrame | LazyFrame)

  • time_window (TimeWindow)

Return type:

bool

corr_vars.utils.time.resolve_time_anchor(value, parent)[source]#

Resolve a requirement’s tmin / tmax against the parent’s anchor.

Four notations are accepted:

  • "inherit" — the parent’s anchor unchanged.

  • ("inherit", "-1h") — the parent’s anchor shifted by the delta. In vars.json this is written as ["inherit", "-1h"].

  • "-1h" — shorthand for the previous form; any bare delta is read relative to the parent, since no column is named like one.

  • anything else — an anchor of its own (column, (column, delta) or None for unbounded), returned untouched.

Parameters:
  • value (Union[str, tuple[str, str], Literal['inherit'], None]) – The requirement’s configured anchor.

  • parent (TimeAnchor) – The anchor of the same side of the parent variable’s window.

Return type:

TimeAnchor | str | tuple[str, str] | None

Returns:

The resolved anchor, ready to be passed to TimeWindow.

corr_vars.utils.time.truncate_to_day(expr, *, day_start=None)[source]#

Snap a datetime expression to the start of the day it falls in.

day_start shifts where a “day” begins, letting the same helper express different day conventions:

  • None — calendar day: the boundary is midnight (00:00).

  • "6h" — ICU day: the boundary is 06:00, so timestamps between midnight and 06:00 roll into the previous day (05:59 → 06:00 yesterday, 06:00 → 06:00 today). The offset-truncate-offset form handles this wrap without any hour-of-day branching.

The result keeps the Datetime dtype (at the boundary time), so downstream datetime arithmetic is unaffected. day_start is a non-negative offset.

Parameters:
  • expr (Expr)

  • day_start (str | timedelta | None)

Return type:

Expr

corr_vars.utils.time.format_delta(delta)[source]#

Render a chain of offsets with an explicit sign in front of each.

A positive offset is stored without a sign, so spelling every sign out is what keeps a chain readable: ("2h", "-1h", "3d") becomes "+ 2h - 1h + 3d".

Parameters:

delta (str | Sequence[str]) – The offsets, or a single one.

Return type:

str

Returns:

The chain with an operator in front of every offset.