Format a Date as YYYY-MM-DD in JavaScript
To format a date as YYYY-MM-DD for the user's day, read the calendar fields in the intended zone (or use Temporal.PlainDate.toString()) — toISOString().slice(0,10) gives the UTC day, which can be off by one. Part of UTC vs Local Time.
Why this scenario is tricky
new Date().toISOString().slice(0, 10) is the popular one-liner, but it returns the UTC calendar day. For a user a few hours west of UTC late in the evening, that is tomorrow's date; a few hours east early in the morning, yesterday's. The fix is to format from the fields in the zone you actually mean.
Minimal working solution
import { Temporal } from '@js-temporal/polyfill';
// Today's civil date in the user's zone, already YYYY-MM-DD.
const ymd = Temporal.Now.plainDateISO('America/New_York').toString();
Full production version
// From an existing instant, project into a zone first.
import { Temporal } from '@js-temporal/polyfill';
function toYMD(instant: Temporal.Instant, zone: string): string {
return instant.toZonedDateTimeISO(zone).toPlainDate().toString();
}
Verification snippet
Common pitfalls
Frequently Asked Questions
Why is my YYYY-MM-DD date off by one day?
You formatted with toISOString(), which returns the UTC calendar day. For users not in UTC that can be the previous or next day. Format from the date fields in the user's zone, for example Temporal.Now.plainDateISO(zone).toString().
What is the simplest correct way to get YYYY-MM-DD?
If you want today in a zone, Temporal.Now.plainDateISO(zone).toString() already returns YYYY-MM-DD with zero-padding. From an existing instant, project it into the zone with toZonedDateTimeISO(zone) and call toPlainDate().toString().