Serialize Temporal Values to JSON in JavaScript
To round-trip Temporal values through JSON, write with toString()/toJSON and read with a reviver that calls Temporal.*.from(). Part of Serializing and Storing Temporal Values.
Why this scenario is tricky
JSON.stringify has built-in special handling for Date (it calls toISOString), but no knowledge of Temporal types. Left alone, a ZonedDateTime serializes via its toJSON to a string on the way out — good — but JSON.parse has no idea it should become a Temporal value again, so it silently stays a string and the next .add() call throws.
Minimal working solution
import { Temporal } from '@js-temporal/polyfill';
const json = JSON.stringify({ at: zdt }); // zdt.toJSON() → ISO string
const obj = JSON.parse(json, (k, v) =>
k === 'at' ? Temporal.ZonedDateTime.from(v) : v); // reviver rehydrates
Full production version
Tag values with their type so one reviver handles a whole payload.
import { Temporal } from '@js-temporal/polyfill';
const REVIVE: Record<string, (s: string) => unknown> = {
Instant: (s) => Temporal.Instant.from(s),
ZonedDateTime: (s) => Temporal.ZonedDateTime.from(s),
PlainDate: (s) => Temporal.PlainDate.from(s),
};
function reviver(_k: string, v: any) {
return v && typeof v === 'object' && v.__t in REVIVE ? REVIVE[v.__t](v.value) : v;
}
Verification snippet
Common pitfalls
Frequently Asked Questions
Does JSON.stringify work on Temporal values?
Yes on the way out — most Temporal types implement toJSON, so they serialize to their canonical ISO string. The gap is on the way in: JSON.parse returns those as plain strings, so you must pass a reviver that calls Temporal.*.from() to rebuild the typed values.
How do I revive many different Temporal types from one payload?
Tag each serialized value with its type name and value, then use a single reviver that looks up the tag and calls the matching from(). This handles Instant, ZonedDateTime, and PlainDate in the same object without per-key special cases.