-
Notifications
You must be signed in to change notification settings - Fork 0
Design Notes
Where the ideas came from, and the decisions that are not obvious from the API.
| Part | Source |
|---|---|
| Civil conversions | H. Hinnant, chrono-Compatible Low-Level Date Algorithms, the days_from_civil and civil_from_days pair C++20 adopted for <chrono>
|
| Adjuster semantics | java.time TemporalAdjusters.dayOfWeekInMonth
|
| Arithmetic semantics | java.time LocalDate.plusMonths, Period.between
|
| Overflow policy | TC39 Temporal overflow: constrain | reject
|
| Resolver semantics | Noda Time ZoneLocalMappingResolver, Temporal disambiguation
|
| Rounding modes | TC39 Temporal |
| ISO week date | ISO 8601 §4.1.4 |
| Easter | Anonymous Gregorian computus, Meeus / Jones / Butcher |
| Business-day conventions and day counts | ISDA 2006 Definitions |
| Bracketed zone suffix | RFC 9557 |
Everything derives from the Hinnant pair. Day-of-week, the adjusters, ISO weeks, DST boundaries, the holiday calendars and the expiry cycles are all computed from it rather than reimplemented.
This is a correctness property. A library with two date implementations has two
chances to be wrong and no way to notice when they disagree. The same reasoning
appears throughout at smaller scale: is_holiday is defined as holiday_name
being non-na, so a date cannot be closed and nameless; is_valid_date is the
exact predicate new_datetime enforces, so the constructor and the predicate
cannot drift; crosses_midnight is derived from the times rather than stored,
because a stored flag can disagree with the fields it describes and eventually
does.
Weekday is an enum because 0=Sunday versus 1=Monday confusion is the most
common class of date bug. Known is an enum because Pine's bool cannot hold
na at all, so "not known" has no room in a yes/no answer. Known.UNKNOWN will
not type-check where a bool is wanted, which means reading it as "no" has to
be written down via is_yes() rather than happening by default.
The convention exists so a signature can be predicted rather than looked up: a
question about a civil date is a method on DateTime, a function that builds a
date takes loose ints, a function that takes an instant takes it first, and
float utc always means a fixed offset. The one exception, Zone.to_unix and
its probes, is documented at its definitions. It reads civil fields as local in
a zone, which is the one thing a DateTime cannot express.
period_between follows java.time's specification rather than its
implementation. Over 1970 to 2200 the two disagree on 18 date pairs out of
4,550, and in every one of those java.time fails its own documented round-trip
promise. The property a.plus_period(a.period_between(b)) == b holds here.
Choosing the spec over the reference implementation is a real decision and worth stating rather than leaving as a silent difference.
Unscheduled closures and lunar holidays live in dated tables. A yyyymmdd key
reads better, but string data compiles at two tokens per character, and roughly
twelve hundred dates at eight digits each is five figures of compiled weight for
keys the code only ever compares whole.
Storing three base-36 digits of the day number instead saved 6,135 characters, about 12,000 compiled tokens, and brought the library from 104,509 under the 100,256 publish cap. The tables also carry leading and trailing sentinel commas, so a date can never match as a substring of its neighbour and membership builds only a five-byte needle rather than copying the whole table per call.
Asking a calendar day by day costs one holiday-chain call per day, and over thirty years that is enough to reach Pine's per-loop time limit, which is a runtime error rather than merely slow.
So trading_days_between and holidays_between invert it: propose the handful
of days a calendar could shut on, test only those, and subtract from a
closed-form weekday count. The proposal is allowed to be wrong in one direction
only. A proposed non-holiday gets filtered out; a day never proposed would be
invisible. So the anchors are a superset over each calendar's whole modelled
range, and membership stays with the same is_holiday every other accessor
uses, so this cannot become a second opinion about what a holiday is.
A session is a recurring local-time window resolved against a calendar. Defined that way it survives daylight saving, holidays and half days without any of them being special-cased at the call site.
That definition is also what makes is_last_bar answer on the bar itself. The
close instant comes from the calendar, so the test is a comparison against a
known bound rather than an inference from the next bar's existence.
Breaks are modelled as a hole inside one window rather than a boundary between two, matching how TradingView's own session strings read them, so day markers fire once.
Session.Cal defaults to na. A default of NYSE would shut a Tokyo session on
Thanksgiving and trade it through Golden Week. There is no separate
"holiday aware" flag either, because a flag plus a calendar could hold the state
"calendar off, calendar NYSE", which is not a thing a session can be.
Rather than a general "returns na on failure", every @returns commits to one
of RAISE, na, Known.UNKNOWN, false, or an in-band number. The distinction
that does the most work is the first two: nth_weekday_of_month raises on
nth = 0, an invalid argument, and returns na for a fifth Friday a month does
not contain, a valid question with no answer.
The in-band clause is why time_to_close does not return 0 while a session
runs. Zero is a real distance, so it cannot also be a flag.
A general parse(str, pattern). A DstRule escape hatch for zones outside the
enum. Locale data. An instant-plus-exchange convenience layer. Each is absent
because a partial version would fail in ways that look like data problems rather
than like missing features.
Previous: Versioning and Data Currency · Next: FAQ · See also: Scope and Limitations
std_time v1 · API Index · Task Index · Scope and Limitations · Verification
Calendar data current to the horizons on Versioning and Data Currency. Shanghai, Bombay and Singapore answer exactly through 2026.
MPL-2.0 · Copyright (c) 2026 Jesse Sanford · published on TradingView as The_Peaceful_Lizard
Start here
The model
- Core Concepts
- Civil and Exact Arithmetic
- Value Semantics
- Error Model
- Time Zones
- Exchange Calendars
- Trading Days and Day Counts
- Expiries
- Sessions
- Formatting and Parsing
- Choosing the Right Tool
- Pitfalls
Recipes
Reference
- API Index · Task Index
- DateTime
- Session
- Zone
- Exchange
- Period · Interval
- Weekday · Enums
- Free functions
- Glossary
The fine print