Bi-Temporal Reads
Every EvidentSource event sits on two time axes:
- Transaction time is when the database recorded the event. It is measured by the event’s revision, and by its
recordedtime. - Effective time is when the fact took effect. It is the event’s
time, or its recording time when it has none. A producer may set it in the past or the future.
They are different things. An interest accrual recorded today may take effect as of last week. A correction recorded this morning may take effect three months ago. A payment scheduled today may take effect next Friday.
The axes nest
Section titled “The axes nest”A read runs at a revision, and sees only what the database had recorded by then. Within that revision, it can order and cut events by effective time. So a bi-temporal read takes two steps, in this order:
- Pick a revision: what the database knew.
- Name a revision directly, or take the latest.
- To pick one by wall-clock time, call
DatabaseEffectiveAtTimestamp. It returns the latest revision whose transaction was recorded at or before that time.
- Cut by effective time within that revision.
- An event query takes an effective-time range, and returns the events whose effective time is at or before its end, in effective-time order.
- A State View read takes
effective_time_end_at.
There are no as_of_transaction_time or as_of_effective_time parameters. The revision is the first step, and the cut is the second.
What this answers
Section titled “What this answers”Take T, the last microsecond of last Tuesday.
- Today’s view of Tuesday: read at the latest revision, cut at
T. - Yesterday’s view of Tuesday: read at the revision in effect at the end of yesterday, cut at
T.
Both cover the same window of effective time. They differ only in how much had been recorded. So the difference between them is exactly what was recorded in between about Tuesday or earlier: the late reports and the corrections. That is “what did we learn, and when did we learn it”, as a read rather than an investigation.
More questions of the same shape:
- “What was the balance at 3:47 PM yesterday, as we knew it then?” Pick the revision in effect at 3:47 PM yesterday, and read the balance there.
- “What do we now believe the balance was at 3:47 PM yesterday?” Read at the latest revision, cut at 3:47 PM yesterday.
- “Show me the ledger before the reversal.” Read at the revision just before the reversal’s transaction.
Which reads are bi-temporal
Section titled “Which reads are bi-temporal”- Revision-ordered reads are mono-temporal. Only transaction time orders and bounds them, and an effective-time cut plays no part.
- Effective-time-ordered reads at a revision are bi-temporal. The revision bounds what is known, and effective time orders and cuts it.
A State View’s definition fixes which of the two orders it folds in. See State Changes & State Views.
Two practical notes
Section titled “Two practical notes”- A cut must be a real instant, and never a leap second. A State View read refuses a malformed cut rather than ignoring it, whatever the view’s order. A revision-ordered State View read ignores a well-formed cut, since its order doesn’t use one, and reports none.
- A read names its cut. Over REST and gRPC, an effective-time-ordered view refuses a read without one, and an event query refuses an effective-time range without an end. Ask for
nowby name, and the server resolves it, never before the revision you read was committed, and says which time it resolved it to: a REST read redirects to that time’s URL and reports it inx-effective-time-end-at, a State View’s gRPC reply carries it, andQueryEventsreports it in that response metadata. A revision-ordered State View has no cut to resolve, sonowthere answers directly. Inside a component, a query’s effective-time range without anend-atis not refused yet: it reads to the scope’s cut on a scoped database, and otherwise has no cut, so it includes events dated in the future. Name a time when an answer has to be stable, since a read atnowcan answer differently later, with no new events.