Date Macros
Date Macros protocol schemas
Date Macro Tokens — the declarative placeholders the UI substitutes
into filter values before sending a query to the data engine.
Why this lives in spec
Filter values in dashboards, views, reports and pages travel as JSON.
Because JSON cannot evaluate code, callers cannot write daysAgo(30)
inline; they use a tiny placeholder grammar instead:
{ published_at: { $gte: '{last_quarter_start}' } }
{ signal_at: { $gte: '{30_days_ago}' } }
The placeholders are expanded client-side by
resolveDateMacros() in @object-ui/core immediately before the
filter is handed to the data source. The data engine itself only
sees ISO date / timestamp strings, never \{tokens\}.
AI agents and template authors author these placeholders directly,
so the set of recognised tokens is part of the platform contract
and must live here next to the rest of the JSON-DSL schemas, not
inside any single UI implementation.
Two flavours of token
- Fixed tokens — small, finite list (
\{today\},
\{current_quarter_start\}, \{last_year_end\}, …). Enumerated by
DATE_MACRO_TOKENS below.
- Parameterised tokens —
\{N_days_ago\},\{N_weeks_from_now\},
etc., where N is any non-negative integer. Matched by
DATE_MACRO_PARAM_RE. Units: minute(s), hour(s), day(s),
week(s), month(s), year(s). Directions: ago, from_now.
Out of scope
- CEL expressions (
cel\daysAgo(30)``) run server-side in the
formula engine. They are unrelated to these placeholders; see
@objectstack/formula.
- Token resolution semantics (week-start day, timezone, fiscal
calendars) are defined by the resolver implementation; spec only
freezes the vocabulary.
Source: packages/spec/src/data/date-macros.zod.ts
TypeScript Usage
import { DateMacroPlaceholder, DateMacroToken } from '@objectstack/spec/data';
import type { DateMacroPlaceholder, DateMacroToken } from '@objectstack/spec/data';
// Validate data
const result = DateMacroPlaceholder.parse(data);