Speak Human. Parse Human.
Parse dates the way people thinkβ"circa 1950", "early January 1985", "the 1960s"βinstead of forcing rigid timestamps.
Because real time is messyβand pretending otherwise loses information
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.
Install the package:
pnpm add @edtf-ts/corenpm install @edtf-ts/coreyarn add @edtf-ts/coreParse your first EDTF date with the FuzzyDate API:
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 allowedThink about how people actually describe dates:
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.
EDTF-TS includes a powerful natural language parser that converts human-readable dates to EDTF format:
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 EDTFWe do not know Shakespeare's exact birthdate.
What we know:
So historians infer: Born circa late April 1564
With EDTF, that uncertainty is preserved:
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.
Archivists deal with dates like:
1918?1919/19241850/1870../1870Forcing these into YYYY-MM-DD destroys information. EDTF preserves it.
Convert EDTF dates back to natural language with full i18n support:
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ζ₯"When software only accepts exact dates, users are forced to:
All four options lose valuable information.
EDTF allows users to say: "This is everything we know β no more, no less."
That's better data.
EDTF doesn't replace ISO 8601 β it extends it.
That honesty unlocks:
| Package | Description | Size |
|---|---|---|
| @edtf-ts/core | Core EDTF parsing, comparison, formatting | ~56 KB ESM |
| @edtf-ts/natural | Natural language parsing | ~15 KB ESM |
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:
1984? (possibly 1984)1950~ (circa 1950)199X (sometime in the 1990s)1940/1945 (from 1940 to 1945)2001-21 (Spring 2001)[1667,1668,1670] (one of these years)EDTF-TS is for anywhere dates come from people, memory, or history β not just sensors and clocks:
MIT License - see LICENSE for details.