Skip to content

EDTF-TSDates, the Way Humans Mean Them

Because real time is messyβ€”and pretending otherwise loses information

EDTF-TS

Dates Aren't Always Exact β€” and That's OK ​

People don't experience time like computers do.

We remember seasons, eras, and approximate moments. We inherit records that are incomplete, contradictory, or deliberately vague. We say "around," "before," "after," "early," "late," and "sometime between."

Yet most software still insists on rigid ISO 8601 dates, forcing humans to pretend they know more than they do.

EDTF exists because real time is messy β€” and pretending otherwise loses information.

Quick Start ​

Install the package:

bash
pnpm add @edtf-ts/core
bash
npm install @edtf-ts/core
bash
yarn add @edtf-ts/core

Parse your first EDTF date with the FuzzyDate API:

typescript
import { FuzzyDate } from '@edtf-ts/core';

// Parse EDTF strings into FuzzyDate objects
const date = FuzzyDate.parse('1985-04-12');
console.log(date.year);           // 1985
console.log(date.month);          // 4
console.log(date.day);            // 12
console.log(date.format());       // "April 12, 1985"

// Work with uncertainty naturally
const uncertain = FuzzyDate.parse('1984?');
console.log(uncertain.isUncertain);   // true
console.log(uncertain.format());      // "1984 (uncertain)"

// Approximate dates
const circa = FuzzyDate.parse('1950~');
console.log(circa.isApproximate);     // true
console.log(circa.format());          // "circa 1950"

// Unspecified digits
const decade = FuzzyDate.parse('198X');
console.log(decade.hasUnspecified);   // true
console.log(decade.min.getFullYear()); // 1980
console.log(decade.max.getFullYear()); // 1989

// Parse intervals and iterate
const interval = FuzzyDate.parse('1990/2000');
for (const year of interval.by('year')) {
  console.log(year.edtf);  // '1990', '1991', ..., '2000'
}

// Temporal comparison with four-valued logic
const y1980 = FuzzyDate.parse('1980');
const y1990 = FuzzyDate.parse('1990');
y1980.isBefore(y1990);      // 'YES' - definitely before
decade.equals(y1980);       // 'MAYBE' - could be 1980

// These will throw FuzzyDateParseError
FuzzyDate.parse('April 12, 1985'); // ❌ Natural language, not EDTF syntax
FuzzyDate.parse('1985-13-01');     // ❌ Invalid month (13)
FuzzyDate.parse('85-04-12');       // ❌ Two-digit year not allowed

Humans Speak in Time Ranges, Not Timestamps ​

Think about how people actually describe dates:

  • "Shakespeare was born in late April 1564."
  • "The photo was taken sometime in the 1930s."
  • "She moved to New York in the early 2000s."
  • "This letter dates to around the end of the 18th century."

None of these are bugs. They are truthful descriptions of what is known.

ISO 8601 can't express this without lying or guessing. EDTF can.

Natural Language Parsing ​

EDTF-TS includes a powerful natural language parser that converts human-readable dates to EDTF format:

typescript
import { parseNatural } from '@edtf-ts/natural';

// Parse human-readable dates
parseNatural('January 12, 1940');     // β†’ '1940-01-12'
parseNatural('circa 1950');           // β†’ '1950~'
parseNatural('possibly 1984');        // β†’ '1984?'
parseNatural('from 1964 to 2008');    // β†’ '1964/2008'
parseNatural('Spring 2001');          // β†’ '2001-21'
parseNatural('the 1960s');            // β†’ '196X'

// Temporal modifiers for precision
parseNatural('early January 1985');   // β†’ '1985-01-01/1985-01-10'
parseNatural('mid 1990s');            // β†’ '1994/1996'
parseNatural('late 19th century');    // β†’ '1867/1900'

// Handles ambiguous dates with confidence scoring
const results = parseNatural('02/03/2020', { locale: 'en-US' });
// Returns both MM/DD and DD/MM interpretations with confidence scores

// These won't parse - returns empty array []
parseNatural('next Tuesday');     // ❌ Relative dates not supported
parseNatural('in 3 weeks');       // ❌ Relative durations not supported
parseNatural('ASAP');             // ❌ Not a date expression
parseNatural('the distant past'); // ❌ Too vague to map to EDTF

Real History Is Full of Uncertainty ​

William Shakespeare's Birth ​

We do not know Shakespeare's exact birthdate.

What we know:

  • He was baptized on April 26, 1564
  • Infants were typically baptized within a few days of birth

So historians infer: Born circa late April 1564

With EDTF, that uncertainty is preserved:

typescript
import { FuzzyDate } from '@edtf-ts/core';

// Approximate month
const birth = FuzzyDate.parse('1564-04~');
console.log(birth.format());  // "circa April 1564"

// Or as an interval
const interval = FuzzyDate.parse('1564-04-20/1564-04-26');
console.log(interval.format());  // "April 20, 1564 to April 26, 1564"

No false precision. No invented birthday. Just honest data.

Photographs, Letters, and Archives ​

Archivists deal with dates like:

  • "Probably 1918" β†’ 1918?
  • "After the war, but before 1925" β†’ 1919/1924
  • "Mid-19th century" β†’ 1850/1870
  • "No earlier than 1870" β†’ ../1870

Forcing these into YYYY-MM-DD destroys information. EDTF preserves it.

Human-Readable Formatting ​

Convert EDTF dates back to natural language with full i18n support:

typescript
import { FuzzyDate } from '@edtf-ts/core';

FuzzyDate.parse('1985-04-12').format();  // "April 12, 1985"
FuzzyDate.parse('1984?').format();       // "1984 (uncertain)"
FuzzyDate.parse('1950~').format();       // "circa 1950"
FuzzyDate.parse('2001-21').format();     // "Spring 2001"

// Localization support
FuzzyDate.parse('1985-04-12').format({ locale: 'de-DE' });  // "12. April 1985"
FuzzyDate.parse('1985-04-12').format({ locale: 'ja-JP' });  // "1985εΉ΄4月12ζ—₯"

Stop Making People Lie to Databases ​

When software only accepts exact dates, users are forced to:

  • Guess β€” picking a plausible date
  • Invent β€” making something up entirely
  • Default β€” choosing January 1st "just to make it work"
  • Omit β€” leaving fields blank

All four options lose valuable information.

EDTF allows users to say: "This is everything we know β€” no more, no less."

That's better data.

Precision When You Have It. Flexibility When You Don't. ​

EDTF doesn't replace ISO 8601 β€” it extends it.

  • If you know the exact date, use it.
  • If you don't, say what you do know.
  • If something is uncertain, mark it as such.
  • If it's approximate, say so explicitly.

That honesty unlocks:

  • Better historical modeling
  • Better archival metadata
  • Better timelines
  • Better AI reasoning
  • Better user experiences

Why EDTF-TS? ​

  • Full Specification Compliance: Complete implementation of the Library of Congress EDTF specification
  • TypeScript First: Designed for TypeScript with excellent type inference
  • Developer Experience: Rich API, helpful error messages, comprehensive documentation
  • Modern JavaScript: Uses latest ECMAScript features and best practices
  • Small Bundle: Optimized parser keeps the core package under 35KB
  • AI Collaboration: Built with the assistance of advanced AI tools for rapid and reliable development

Packages ​

PackageDescriptionSize
@edtf-ts/coreCore EDTF parsing, comparison, formatting~56 KB ESM
@edtf-ts/naturalNatural language parsing~15 KB ESM

What is EDTF? ​

Extended Date/Time Format (EDTF) is a standard developed by the Library of Congress for representing dates that are uncertain, approximate, or otherwise complex. It's designed to handle real-world date scenarios like:

  • Uncertain dates: 1984? (possibly 1984)
  • Approximate dates: 1950~ (circa 1950)
  • Unspecified dates: 199X (sometime in the 1990s)
  • Date ranges: 1940/1945 (from 1940 to 1945)
  • Seasons: 2001-21 (Spring 2001)
  • Sets: [1667,1668,1670] (one of these years)

Who Is This For? ​

EDTF-TS is for anywhere dates come from people, memory, or history β€” not just sensors and clocks:

  • Libraries, archives, and museums
  • Genealogy and biography software
  • Historical research
  • Content management systems
  • Timelines and visualization tools
  • AI systems that reason about time

Community ​

License ​

MIT License - see LICENSE for details.

Released under the MIT License.