π Live site
When am I?
Imagine you're a time traveler who ends up in a random place and time in history. What does a local say when you ask, "When am I?" This project is a fun and educational React app that lets you explore different calendar systems around the world by selecting a location on an interactive map and choosing any year in history. It then shows you the local calendar year and system for that place and time.

Pin a spot and a date, and see every valid answer a local could give β including when more than one calendar applies at once:

Features
- Interactive world map for selecting a location
- A year timeline showing the picked spot's calendar eras as color-coded bands (colors stay consistent across the map, timeline, and answers). Its scale breaks at the region's key dates β the calendar changeovers β so they're evenly spaced and labelled (e.g. 1954 for Vietnam) instead of crammed into recent centuries; dashed lines mark where the calendar actually changes, and each year label is clickable to jump straight to that date
- A day-of-year track color-coded the same way for the selected year, so a changeover that falls mid-year shows up as a color boundary within the year β e.g. for Boston in 1752 it switches from Julian to Gregorian in mid-September (the British calendar reform), with a dashed line on the exact day
- Shuffle button that drops you at a random place and date on a non-default (non-Gregorian) calendar β e.g. Chinese, Japanese, Saka, Buddhist, Ethiopian, Islamic, Persian, Julian, or a lunar reckoning
- Displays the local calendar year and system for the chosen place and time, plus the modern geography of the spot β the country and nearest large city (offline lookup, no network)
- A two-column layout (map + controls beside the answers) on wide screens that stacks on mobile, and a shareable URL that captures the pinned spot, date, and zoom so you can link someone to the exact view
- Shows all valid answers at once β different people at the same place and time reckoned dates differently (e.g. colonial Julian alongside an Indigenous lunar calendar)
- Each answer notes when that calendar was in use at the spot (e.g. "in use here since 1954"), so a changeover is called out plainly rather than buried
- For calendars with no numbered year, gives the kind of answer a local would β the moon and night ("a full moon, about night 15"), and, where the data records a documented event, "about N winters since <event>"
- A global modern Gregorian default for dates from 1927 on, so most recent dates resolve anywhere β shown alongside any local calendar (e.g. modern Iran β Persian and Gregorian), with one deliberate exception: North Sentinel Island, where the uncontacted Sentinelese have never adopted any outside calendar
- Educational and fun way to explore world calendars and history
Supported calendars
The engine returns every valid answer for a place and date. A calendar is convertible when a deterministic rule yields a numbered local year, or descriptive-only when it has no continuous numbered year (we still place you in time β the moon/season, the named year, and "winters since" a recorded event β and show the Gregorian year for reference).
- Convertible: Gregorian, Julian, Islamic (Umm al-Qura), Hebrew, Persian (Solar Hijri), Indian (Saka), Buddhist, Japanese (nengΕ, Meiji onward), Ethiopian, Maya Long Count, French Republican calendar (year only, from a sourced table of each year's actual equinox-based start date), Dangi (Dangun era, South Korea), Juche (North Korea, 1997β2024), ab urbe condita (AUC, from Rome's founding, 753 BC) and the Seleucid era (Anno Graecorum, 312/311 BC) β both year-only arithmetic offsets.
- Descriptive-only: the Chinese sexagenary cycle (the named 60-year stem-branch / zodiac-animal year), the Korean, Vietnamese, and Japanese pre-modern lunisolar calendars, the Tzolk'in/Haab' Calendar Round, the Aztec/Mexica year-bearer (52-year cycle) and TΕnalpΕhualli (260-day ritual cycle), the Ottoman Rumi fiscal calendar, the MΔori maramataka, and observational lunar calendars such as the Algonquian (Massachusett) reckoning.
Tech Stack
- React (SPA)
- Vite (modern, fast bundler)
- TypeScript
- Open-source map library (e.g., Leaflet or MapLibre)
Getting Started
- Install dependencies:
bash
npm install
- Start the development server:
bash
npm run dev
- Build for production:
bash
npm run build
Development
Quality checks (also run in CI before any deploy):
npm run lint # ESLint (flat config)
npm run typecheck # tsc --noEmit
npm test # Vitest unit tests
npm run test:watch # Vitest in watch mode
npm run validate:data # Validate every calendar data file against the schema
validate:data also runs automatically before every build (prebuild) and in
CI, so malformed calendar data can never be deployed. See
Contributing Calendar Data.
Badges
The README badge block (between the badges:start/badges:end markers above) is
generated, not hand-edited. It pulls the app version from package.json and counts
the calendar data files, so the badges never drift. Run it before opening a PR:
npm run gen:badges # rewrite the badge block in README.md
npm run gen:badges -- --check # fail if the block is stale (no write) β for CI
Screenshots
Screenshots are generated with Playwright, which forces deterministic app state
via URL params (?lat=&lng=&zoom=&year=&month=&day=&era=). The scripts reuse a
running dev server on port 5173 or start one automatically. Set
SCREENSHOT_PORT to use a different port β handy when another checkout (e.g. a
parallel workspace) already holds 5173, so you capture this code, not theirs.
npm run screenshot # app states β screenshots/app/
npm run screenshot:calendar -- src/data/calendars/massachusett.json # one calendar β screenshots/calendars/<file>/
npm run screenshot:calendars # regenerate ALL calendars β screenshots/calendars/
npm run screenshot:readme # the two README images β screenshots/readme/
screenshot:calendar pins a point inside the region and a representative date
in each era, capturing the answer panel and shaded map per era.
screenshot:calendars does the same for every calendar data file at once
(reusing one dev server + browser) β run it after adding or editing calendar
data so the checked-in screenshots stay current.
screenshot:readme regenerates the two images embedded above: a full-viewport
landing shot, and an example state cropped to just the map+answers column
(skipping the header/intro, which a README image doesn't need) β narrower and
more deliberately cropped than the full-page shots above, since a hero image
needs to read at a glance.
Reporting issues
The app footer links to the source repository and a Report an issue link. The latter opens a pre-addressed email to the project's bug-report address (no account needed) prefilled with context β build version/commit, browser, URL, and the current selection. If the app crashes, the error report additionally includes the error message and stack.
Project Structure
src/components/β React componentssrc/utils/β Utility functionssrc/types/β Shared TypeScript typessrc/hooks/β Custom React hookssrc/data/β Data filessrc/assets/β App images and static assetspublic/β Static files served at root
Contributing Calendar Data
Calendar region and era data is stored as flat JSON files in src/data/calendars/.
Each file describes a region (using GeoJSON geometry) and its calendar eras over time.
Example (abbreviated): based on src/data/calendars/massachusett.json
Note how answers can overlap β both in time and in space. A click in 1650s
Boston returns the Massachusett reckoning (from massachusett.json, a tight
homeland polygon around Massachusetts Bay) and the colonial Julian calendar
(from colonial-america.json, a broad "British North America" polygon that also
covers the same spot). The Julian β Gregorian cutover was empire-wide, so it
lives in the larger region rather than being duplicated into every town;
overlapping regions are expected, not an error.
{
"region": {
"name": "Massachusett homeland",
"geo": {
"type": "Polygon",
"coordinates": [
[
[-71.30, 42.25],
[-71.05, 42.50],
[-70.92, 42.41],
[-71.12, 42.22],
[-71.30, 42.25]
]
]
}
},
"eras": [
{
"name": "Massachusett reckoning",
"start": null,
"end": null,
"calendar": "Algonquian lunar calendar",
"usedBy": "the Massachusett people",
"description": "Lunar and seasonal reckoning of the Massachusett, the Algonquian people of the Massachusetts Bay area.",
"sources": ["https://en.wikipedia.org/wiki/Massachusett"]
}
]
}
The colonial Julian and Gregorian eras live in colonial-america.json, whose
larger polygon overlaps this one β so a Boston click resolves against both files.
An era for a calendar with no numbered year may also carry anchorEvents β a
list of documented, dated, sourced events a local reckons time from. The app
reports the most recent one at or before the date as "about N winters since
<event>" (e.g. the Massachusett reckoning counts winters since the
1616β1619 epidemic). Anchor events must be real and cited β the engine only
counts the winters, it never invents the event.
Schema
See src/data/calendars/SCHEMA.md (human-readable field docs) and
scripts/validate-data.mts (the authoritative, machine-checkable schema run by
validate:data).
How to contribute
Contributions arrive by email: share a branch from any git host, or send a
git format-patch, to contrib-68uq+when-am-i@fuzzyworld.net. Details:
how to contribute.
- Add or edit files in
src/data/calendars/, on a branch or as a patch. - Use geojson.io or similar tools to draw and export region polygons.
- Include sources/references for each era (and for every anchor event).
- Working in Claude Code? The repo ships a
new-calendarskill (.claude/skills/new-calendar/) that walks the whole flow β researching a place/people's calendar with citations, drafting the polygon and eras, picking the right converter (or descriptive-only), then validating and screenshotting. - Run
npm run screenshot:calendar -- src/data/calendars/<your-file>.jsonand attach the images to your email, so the region, eras, and conversions can be reviewed visually. - Run
npm run gen:badgesso the README's calendar-data count reflects your addition, and commit the updated README. - Run
npm run validate:datato check your file against the schema (required fields, valid geometry, parseable dates). This runs automatically before every build and in CI, so a malformed file will fail the pipeline rather than deploy.
Calendars we'd like to add
Ranked by rough "years in use Γ area/population reached" β the systems that
would let the most human-years of history resolve to a real local answer.
Contributions for any of these (or anything else, sourced) are very welcome β
see How to contribute above, and check
src/utils/calendars.ts for whether a system needs new converter work or can
ship as descriptive-only.
- Tibetan calendar (Bod rtsis) β a lunisolar calendar in continuous use across the Tibetan Plateau for over a thousand years, with its own 60-year cycle and year names.
- Mongolian calendar β the Mongol Empire and successor states' lunisolar calendar (related to but distinct from the Chinese and Tibetan systems), spanning a vast historical territory.
- Coptic calendar β Egypt's calendar since antiquity (descended from the
ancient Egyptian civil calendar), still used liturgically by the Coptic
Orthodox Church; distinct from but related to the Ethiopian calendar already
supported. (Note: the Temporal
copticcalendar id is broken in our polyfill version, same class of bug aschinese/ethiopicβ would likely need a hand-rolled converter like Ethiopian's.) - Ancient Egyptian civil calendar β a 365-day calendar used for roughly three millennia along the Nile; descriptive-only (no continuous numbered year survives in common use), but enormous time depth.
- Armenian calendar β in continuous use since antiquity, with its own epoch and a fixed 365-day year (no leap day), giving it a slow drift against the Gregorian year worth surfacing.
- Coast Salish / Puget Sound calendar β a sourced, people-specific lunar reckoning for the Pacific Northwest, paralleling the Massachusett entry; the place/people this skill's original brainstorm named as an example.
- Inca calendar β a lunisolar/solar calendar used across the Inca Empire's considerable territory in the Andes; mostly descriptive (reconstructions of its exact rules are debated, so sourcing needs care).
- Balinese Pawukon and Saka calendars β Bali's parallel 210-day ritual cycle and a Saka-derived solar count, both still in everyday use.
- BahΓ‘'Γ calendar β a 19-month, 19-day solar calendar in worldwide use since the mid-19th century; smaller area than the others here but a long enough span and clean enough arithmetic to be a good convertible candidate.
- Sikh Nanakshahi calendar β a solar calendar adopted by the SGPC in 2003 for Sikh religious dates, with a clear epoch (Guru Nanak's birth year) β likely a simple convertible offset like Dangi/Juche.
- A dedicated South Korea region β
korea.json's polygon covers the whole peninsula, so it can't host South-only eras without colliding withnorth-korea.json(both would fire on the same point). South Korea's own 1948β1962 official use of the Dangi (Dangun) era was removed fromkorea.jsonfor this reason and isn't documented anywhere yet; a South-Korea-only polygon could restore it.
License
MIT Β© Pavel Safronov
Attributions
- Map tiles and data: OpenStreetMap
- Map library: Leaflet
- City data (for the country / nearest-city readout): GeoNames, licensed CC BY 4.0. Regenerate the bundled
src/data/cities.jsonwithnpm run gen:cities. - Calendar icon: Calendar icons created by Icongeek26 - Flaticon
Implementation
This entire app was written by Claude. Pavel supplied the ideas, Claude did all the heavy lifting. Pavel wrote this paragraph. In part, this is a continuation of my exploration of agentic coding. See my other similarly-developed projects: https://fuzzyworld.net/projects/.