Get the Start and End of Day in a Timezone
To get the start of a day in a zone, use zonedDateTime.startOfDay(); the end is the next day's start (exclusive). This handles DST days where midnight can shift. Part of Timezone Offset Math Explained.
Why this scenario is tricky
Day boundaries are a favourite source of reporting bugs. "Start of day" is not always 00:00: on a spring-forward day in zones that transition at midnight, 00:00 does not exist and the day begins at 01:00. Setting the time to midnight by hand produces an invalid instant; startOfDay() asks the timezone database for the real first moment.
Minimal working solution
import { Temporal } from '@js-temporal/polyfill';
const day = Temporal.Now.zonedDateTimeISO('America/Sao_Paulo');
const start = day.startOfDay(); // first instant of the day
const end = start.add({ days: 1 }); // exclusive end = next day's start
Full production version
import { Temporal } from '@js-temporal/polyfill';
function dayBounds(date: Temporal.PlainDate, zone: string) {
const start = date.toZonedDateTime(zone).startOfDay();
// Half-open [start, end): use for BETWEEN queries.
return { start, end: start.add({ days: 1 }) };
}
Verification snippet
Common pitfalls
Frequently Asked Questions
How do I get the start of the day in a specific time zone?
Build a ZonedDateTime in that zone and call startOfDay(). It returns the first valid instant of the calendar day, which is 00:00 on normal days but can be 01:00 on a spring-forward day where midnight does not exist.
How should I represent the end of the day for a query?
Use the next day's startOfDay() as an exclusive upper bound and query the half-open range [start, end). That avoids the classic 23:59:59.999 approach, which can miss events in the final fraction of a second.