Skip to content

Fuzzy date — uncertain chronological dating

The fuzzy-date plugin adds a structured chronology section to any table. It stores uncertain, approximate, or range-based dates in five dedicated columns directly in the core table — making them searchable, filterable, and usable by other plugins such as the GeoFace temporal filter and the Harris Matrix absolute timeline.

When to use it

Use this plugin when your records have a dating that is:

  • Approximate — "probably 4th century BC"
  • A range — "between 350 and 300 BCE"
  • One-sided — "not later than 300 BCE" (ante quem) or "not earlier than the late 4th century BCE" (post quem)
  • Uncertain — "possibly Hellenistic"

Enabling the plugin for a table

Go to Config → Tables, select the table, scroll to the System plugins section and toggle Chronology (fuzzy date) on. The system immediately adds five columns to the table and confirms with a toast message. No other configuration is required.

To disable, toggle the switch off. The columns — and any data already entered — are preserved; the panel simply disappears from RecordView. Toggle it back on at any time to restore the panel without data loss.

The chronology panel

Once enabled, a Chronology section appears in RecordView below the regular fields.

Read mode

Displays the stored chronology as a formatted label, a certainty badge, and an optional period name. Examples:

Late 4th cent. BCE Probable · Hellenistic

Ante quem: 4th cent. BCE

350 BCE – 300 BCE Certain

Edit mode

The panel shows three inputs:

InputPurpose
Chronology stringPrimary input — see grammar below
CertaintyCertain / Probable / Possible
PeriodFree text or vocabulary term (qualitative label only)

Typing in the chronology string field triggers live parsing. A preview shows the generated label and the numeric range (from – to) so you can verify the result before saving.

Chronology string grammar

The chronology string is the primary input method. It supports two token types: century and year. The general structure is:

input = token             → single date or century range
      | token / token     → explicit range
      | ? / token         → ante quem
      | token / ?         → post quem
      | ?                 → undated

Century tokens

A century token starts with c (mandatory), followed by the century number, an optional qualifier, and the era:

c{N}{qualifier} {BCE|CE}
QualifierMeaningExampleRange
(none)Full centuryc4 BCE400–301 BCE
eEarly (~first 25%)c4e BCE400–376 BCE
mMid (~middle 50%)c4m BCE375–326 BCE
lLate (~last 25%)c4l BCE325–301 BCE
h1First halfc4h1 BCE400–351 BCE
h2Second halfc4h2 BCE350–301 BCE
q1q4Quarter 1–4c4q3 BCE350–326 BCE

Year tokens

FormatExampleMeaning
-N-350Year 350 BCE
N BCE350 BCEYear 350 BCE
N or N CE300 or 300 CEYear 300 CE

Disambiguation

4 BCE means year 4 BCE (not the 4th century). To express the 4th century BCE, write c4 BCE. The c prefix is what identifies a century token.

Range and one-sided dates

InputMeaningStored as
c4l BCE / c3m CELate 4th BCE to mid 3rd CEfrom=–325, to=275
-350 / -300Years 350–300 BCEfrom=–350, to=–300
? / c4q3 BCEAnte quem: before 3rd quarter 4th BCEfrom=null, to=–326
c4l BCE / ?Post quem: after late 4th BCEfrom=–325, to=null
?Undatedfrom=null, to=null

Data model

Five columns are added to the core table when the plugin is activated:

ColumnTypeMeaning
chrono_fromINTEGERStart year (negative = BCE). NULL for ante quem or undated.
chrono_toINTEGEREnd year. NULL for post quem or undated.
chrono_labelVARCHAR(200)Human-readable label (auto-generated or free text).
chrono_certaintyVARCHAR(10)certain / probable / possible
chrono_periodVARCHAR(200)Qualitative period name (e.g. "Hellenistic"). No numeric mapping.

The dating type is implicit — no separate type column is needed:

chrono_fromchrono_toType
nullnullUndated
XXPoint date (exact year)
XY (X < Y)Range / circa
nullYAnte quem
XnullPost quem

Searching by chronology

_chrono_overlap — the primary operator

Use _chrono_overlap on chrono_from to find all records whose dating intersects a given range. It correctly handles the NULL semantics of ante quem and post quem records:

filter[chrono_from][_chrono_overlap][]=-400&filter[chrono_from][_chrono_overlap][]=-300

Or as a JSON body:

json
{ "chrono_from": { "_chrono_overlap": [-400, -300] } }

The operator generates a three-branch condition:

Record typeIncluded if
Normal range (from and to set)range overlaps [low, high]
Ante quem (from is null)to >= low
Post quem (to is null)from <= high
Undated (both null)never

WARNING

Use _chrono_overlap on chrono_from only. Applying it to any other field returns an error.

Filtering by other chrono fields

The remaining chrono columns support all standard operators:

# Records with probable certainty
filter[chrono_certainty][_eq]=probable

# Records in the Hellenistic period
filter[chrono_period][_icontains]=hellenistic

# Records with a label containing "BCE"
filter[chrono_label][_icontains]=BCE

# Records that have any chrono data (not undated)
filter[chrono_to][_nnull]=true

Integration with other plugins

PluginIntegration
GeoFaceWhen the fuzzy-date plugin is active on a table, GeofaceView shows a Temporal filter bar with a dual-handle year slider (range −3000 to 2000, step 25 years). Dragging the handles filters map markers in real time using _chrono_overlap, correctly including ante quem and post quem records that intersect the selected window.
Harris MatrixAn absolute chronological layout positions stratigraphic units on a vertical timeline using their fuzzy date (coming soon).