Time expressions → a portable IR → SQL

A ~14 MB model that runs 100% in your browser. It turns phrases like "last 7 days" or "último miércoles de 2027" — in English, Spanish, French and German — into an intermediate representation that renders to a bound SQL predicate or a JS date range.

"last 7 days" ─► last_n(7, day) ─► [ :now-6d 00:00, :now+1d 00:00 ) → SQLite / Postgres predicate "último miércoles de 2027" ─► nth_weekday(last, wed, 2027) ─► [ 2027-12-29, 2027-12-30 ) → half-open range "a fortnight ago" ─► offset(-2, week) ─► { start: Date, end: Date } → JS range

Try the playground → View on GitHub

The idea: the model emits structure, a deterministic layer fills the numbers

The model never generates a digit. It predicts a skeleton — offset(-N, week), named(P), nth_day(last, month, YEAR) — and a small deterministic layer then extracts the exact numbers, months and dates from the input and materializes the full IR. Because the output space is a finite set of skeletons, this is classification, not generation: a 14 M-parameter encoder with a few heads is enough, and it generalizes to years and phrasings it barely saw.

What it maps

expressionIR
en last 7 dayslast_n(7, day)
es último miércoles de 2027nth_weekday(last, wed, 2027)
en first day of the monthnth_day(1, month, this)
fr le premier jeudi de mainth_weekday(1, thu, 2024-05)
en a fortnight agooffset(-2, week)
de nächsten Montag um 12:30at(12:30, dow(next, mon))
en every mondayevery(mon)
en Q3 2024named(2024-Q3)

These are precomputed. The playground runs the real model live and also shows the SQLite / Postgres SQL and the exact resolved dates.

The model

electra-small · ~14 M params
multi-head classifier (op / unit / which / dow / ord / scope / sign / has_at)
Size~14 MB int8 ONNX
Languagesen · es · fr · de
Runtimeonnxruntime-web (WASM), single forward pass
Repoceritium/sundial-encoder-full
Why this vs a date parser?

Duckling / chrono give you a resolved Date. sundial gives a portable IR that renders to bound SQL (SQLite & Postgres, validated by execution), runs client-side with no server, and is multilingual from one model. It ties rule engines on the constructs they support and wins on out-of-distribution phrasing (91.7% vs 38.9% on paraphrases) — the distilled model generalizes the long tail.

Open & experimental

Everything — the IR grammar, the renderers (validated by execution against real SQLite & Postgres), the training and distillation pipeline, and the benchmarks — is on GitHub under MIT. It's as much a template for "natural language → finite IR → executable, tiny + local" as it is a time parser.