A Java library for parsing, comparing, and rendering Extended Date/Time Format (EDTF) strings, per ISO 8601-2:2019 (with Amendment 1, 2025) and the Library of Congress EDTF specification.
This is a port of the JavaScript library edtf.js to the JVM, targeting Java 17+ with zero runtime dependencies.
Status: Latest release
0.3.0. Available on Maven Central (since0.2.0).
import io.github.openhistoricalmap.edtf.Edtf;
import io.github.openhistoricalmap.edtf.EdtfTemporal;
EdtfTemporal t = Edtf.parse("2020-XX");
System.out.println(t.toEdtfString()); // "2020-XX"
System.out.println(t.min()); // epoch ms for 2020-01-01T00:00:00Z
System.out.println(t.max()); // epoch ms for 2020-12-31T23:59:59.999ZAvailable on Maven Central as of 0.2.0.
<dependency>
<groupId>io.github.openhistoricalmap</groupId>
<artifactId>edtf</artifactId>
<version>0.3.0</version>
</dependency>implementation 'io.github.openhistoricalmap:edtf:0.3.0'For Ant projects that resolve dependencies via Apache Ivy.
Drop this into the <dependencies> block of your ivy.xml:
<dependency org="io.github.openhistoricalmap" name="edtf" rev="0.3.0"/>The default Ivy resolver chain pulls from Maven Central
(repo1.maven.org), so no additional ivysettings.xml is needed
in most cases. If you maintain a custom resolver chain, ensure
Maven Central is reachable.
A complete worked example lives at smoke/ in this
repository: a self-contained Ant project (build.xml + ivy.xml +
src/Smoke.java) that resolves the published artefact, compiles
against it, runs a tiny program, and asserts on the output.
.github/workflows/smoke.yml runs
it daily as a regression check — the same setup any
downstream Ant consumer can crib from.
| Level | Description | Status |
|---|---|---|
| 0 | ISO 8601-1 dates, datetimes, centuries | v0.1 — done |
| 1 | Uncertain / approximate / unspecified, Y-notation, | v0.1 — done |
| seasons, open / unknown intervals | ||
| 2 | Sets, lists, consecutive ranges, partial masking, | v0.2 — done |
| extended seasons (25-41), decades, Y exponential, | ||
| significant-digits, positional UA markers | ||
| 3 | Season-to-season intervals (via L1/L2 endpoints); | v0.2 — partial |
| further L3-specific forms | (planned v0.3) |
Locale-aware formatting ships in v0.3.0 via
io.github.openhistoricalmap.edtf.format.EdtfFormatter:
import io.github.openhistoricalmap.edtf.format.EdtfFormatter;
import java.util.Locale;
EdtfFormatter f = EdtfFormatter.forLocale(Locale.US);
f.format(Edtf.parse("2020-05")); // "May 2020"
f.format(Edtf.parse("199")); // "the 1990s"
f.format(Edtf.parse("2020/2021")); // "2020 to 2021"
f.format(Edtf.parse("2020-21")); // "Q1 2020"Translations are managed via Transifex;
contributors don't hand-edit messages_<locale>.properties files.
Comparison (compareTo, covers) and epoch-millisecond bounds
(min / max) are implemented for every supported type. Canonical
string rendering matches edtf.js for parity; see
CHANGELOG.md for the four documented deviations.
Requires JDK 17 or newer and Maven 3.9+.
mvn -B verify # compile + run tests
mvn -B verify -DskipTests # compile only
mvn -B package # build jarThe -Prelease profile adds source + Javadoc jars, GPG signing, and
Maven Central publishing. Reserved for release automation.
BSD 2-Clause. See LICENSE. Portions derive from
edtf.js (BSD 2-Clause, © 2016–2025 EDTF.js Authors and
Contributors). See ATTRIBUTION.md for details and
LICENSE-edtf.js.txt for the upstream license.
This project was developed with substantial assistance from Claude
(Anthropic). See ATTRIBUTION.md for scope and
rationale. Commits with AI involvement carry a Co-Authored-By: Claude
trailer; contributors are asked to disclose AI involvement in their own
contributions (CONTRIBUTING.md).
See ROADMAP.md for forward-looking plans
(near-term issues, the path to 1.0, and maintenance reminders
like token / key rotations). CHANGELOG.md
covers backward-looking version history.
- ISO 8601-2:2019 — the authoritative standard
- Library of Congress EDTF specification — free reference
- edtf.js — the upstream JS library this ports
REFERENCES.md— pinned versions and local spec paths