You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
dtype: datetime works end to end — it declares, binds date-typed data, builds
and solves. The one thing it cannot do is appear in a where, because the
grammar's value production has no date literal. So a datetime dimension is
usable exactly as long as nothing about the model is conditional on time.
What works, and where the wall is
Verified against a three-day horizon with load bound from a polars frame of datetime.date values:
SPEC §6 gives value ::= NUMBER | NAME_OR_STRING. A bare 2024-01-01 fails on
the -; the quoted form fails because a quoted string is not a value either.
There is no third spelling.
Why it matters more than the corpus suggests
Every one of the 16 shipped models declares snapshot: {dtype: int}, so nothing
in the repo exercises this. That is not because integer snapshots are natural —
PyPSA's own snapshots are timestamps, and the ports convert them to 0, 1, 2 …
to get in the door.
The constructs it removes are the ones the ladder was built to demonstrate. With
a datetime snapshot you cannot write ramp limits (where: "snapshot > 0"),
non-cyclic storage seeding (where: "snapshot == 0"), or unit commitment's
boundary rows — rungs 2, 3 and the MILP entry. Nine where clauses across four
ported models are unwritable on the dtype the domain actually uses.
The workaround, and what it costs
A bool parameter carrying the mask works, and solves correctly (objective
50.0, first snapshot dropped):
This is defensible under SPEC §11 — computing a mask is data prep. What it costs
is that "the first snapshot" stops being a statement in the model and becomes a
column that has to be regenerated whenever the horizon moves. Two files must
agree about which row is first, and nothing checks that they do.
Options
A date literal in the where grammar. Extends value with an ISO-8601
form. Interacts with SPEC §1's deliberate decision to keep YAML 1.1's implicit
timestamp resolution — the where string is a quoted scalar, so the literal
inside it is never touched by that, but the two need to agree on what a date
means.
Coordinate helpers instead — Track 1 item 3, index(dim, i) with negative i from the end. This is the better answer for the dominant case: where: "snapshot == index(snapshot, 0)" says "the first snapshot" on any dtype and
survives the horizon moving, which a hardcoded literal does not. It does not
cover comparing against a specific date, which is a real thing to want
(a policy start year, a maintenance window).
Refuse dtype: datetime at declaration until one of the above lands, so
the language stops accepting a dimension it cannot filter. Worse for anyone
using it successfully today without a where, and there is no way to know how
many that is.
Options 1 and 2 are complementary rather than alternatives; 3 is a stopgap that
trades a loud failure late for a loud failure early.
Related: _yaml.py already flags datetime as "accepted and does not yet
implement", pointing at the dtype guard from #65 (closed). That note is about
label coercion; this is the separate half.
Note
The following content was generated by AI.
dtype: datetimeworks end to end — it declares, binds date-typed data, buildsand solves. The one thing it cannot do is appear in a
where, because thegrammar's
valueproduction has no date literal. So a datetime dimension isusable exactly as long as nothing about the model is conditional on time.
What works, and where the wall is
Verified against a three-day horizon with
loadbound from a polars frame ofdatetime.datevalues:wherewhere: "snapshot > 2024-01-01"SchemaError: Failed to parse where stringwhere: "snapshot > '2024-01-01'"SchemaError: Failed to parse where stringwhere: "snapshot != 2024-01-01"SchemaError: Failed to parse where stringSPEC §6 gives
value ::= NUMBER | NAME_OR_STRING. A bare2024-01-01fails onthe
-; the quoted form fails because a quoted string is not avalueeither.There is no third spelling.
Why it matters more than the corpus suggests
Every one of the 16 shipped models declares
snapshot: {dtype: int}, so nothingin the repo exercises this. That is not because integer snapshots are natural —
PyPSA's own snapshots are timestamps, and the ports convert them to
0, 1, 2 …to get in the door.
The constructs it removes are the ones the ladder was built to demonstrate. With
a datetime
snapshotyou cannot write ramp limits (where: "snapshot > 0"),non-cyclic storage seeding (
where: "snapshot == 0"), or unit commitment'sboundary rows — rungs 2, 3 and the MILP entry. Nine
whereclauses across fourported models are unwritable on the dtype the domain actually uses.
The workaround, and what it costs
A
boolparameter carrying the mask works, and solves correctly (objective50.0, first snapshot dropped):
This is defensible under SPEC §11 — computing a mask is data prep. What it costs
is that "the first snapshot" stops being a statement in the model and becomes a
column that has to be regenerated whenever the horizon moves. Two files must
agree about which row is first, and nothing checks that they do.
Options
wheregrammar. Extendsvaluewith an ISO-8601form. Interacts with SPEC §1's deliberate decision to keep YAML 1.1's implicit
timestamp resolution — the where string is a quoted scalar, so the literal
inside it is never touched by that, but the two need to agree on what a date
means.
index(dim, i)with negativeifrom the end. This is the better answer for the dominant case:where: "snapshot == index(snapshot, 0)"says "the first snapshot" on any dtype andsurvives the horizon moving, which a hardcoded literal does not. It does not
cover comparing against a specific date, which is a real thing to want
(a policy start year, a maintenance window).
dtype: datetimeat declaration until one of the above lands, sothe language stops accepting a dimension it cannot filter. Worse for anyone
using it successfully today without a
where, and there is no way to know howmany that is.
Options 1 and 2 are complementary rather than alternatives; 3 is a stopgap that
trades a loud failure late for a loud failure early.
Related:
_yaml.pyalready flags datetime as "accepted and does not yetimplement", pointing at the dtype guard from #65 (closed). That note is about
label coercion; this is the separate half.