···11+---
22+"@clack/prompts": patch
33+"@clack/core": patch
44+---
55+66+Fix timezone issues in DatePrompt causing dates to be off by one day in non-UTC timezones
+24-10
packages/core/src/prompts/date.ts
···3131 return { year: '____', month: '__', day: '__' };
3232 }
3333 return {
3434- year: String(date.getFullYear()).padStart(4, '0'),
3535- month: String(date.getMonth() + 1).padStart(2, '0'),
3636- day: String(date.getDate()).padStart(2, '0'),
3434+ year: String(date.getUTCFullYear()).padStart(4, '0'),
3535+ month: String(date.getUTCMonth() + 1).padStart(2, '0'),
3636+ day: String(date.getUTCDate()).padStart(2, '0'),
3737 };
3838}
39394040-function segmentValuesToParsed(parts: DateParts): { year: number; month: number; day: number } {
4040+function segmentValuesToParsed(parts: DateParts): {
4141+ year: number;
4242+ month: number;
4343+ day: number;
4444+} {
4145 const val = (s: string) => Number.parseInt((s || '0').replace(/_/g, '0'), 10) || 0;
4246 return {
4347 year: val(parts.year),
···119123 if (!year || year < 1000 || year > 9999) return undefined;
120124 if (!month || month < 1 || month > 12) return undefined;
121125 if (!day || day < 1) return undefined;
122122- const date = new Date(year, month - 1, day);
123123- if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
126126+ const date = new Date(Date.UTC(year, month - 1, day));
127127+ if (
128128+ date.getUTCFullYear() !== year ||
129129+ date.getUTCMonth() !== month - 1 ||
130130+ date.getUTCDate() !== day
131131+ ) {
124132 return undefined;
125133 }
126134 return { year, month, day };
127135}
128136129129-/** Build a Date from segment values using local midnight so getFullYear/getMonth/getDate are timezone-stable. */
137137+/** Build a Date from segment values using UTC midnight so getFullYear/getMonth/getDate are timezone-stable. */
130138function segmentValuesToDate(parts: DateParts): Date | undefined {
131139 const parsed = segmentValuesToParts(parts);
132140 if (!parsed) return undefined;
133133- return new Date(parsed.year, parsed.month - 1, parsed.day);
141141+ return new Date(Date.UTC(parsed.year, parsed.month - 1, parsed.day));
134142}
135143136144function segmentValuesToISOString(parts: DateParts): string | undefined {
···278286 : clamp(bounds.min, num + direction, bounds.max);
279287280288 const newSegmentValue = String(newNum).padStart(segment.len, '0');
281281- this.#segmentValues = { ...this.#segmentValues, [segment.type]: newSegmentValue };
289289+ this.#segmentValues = {
290290+ ...this.#segmentValues,
291291+ [segment.type]: newSegmentValue,
292292+ };
282293 this.#refreshFromSegmentValues();
283294 }
284295···331342 const newSegmentVal = segmentDisplay.slice(0, pos) + char + segmentDisplay.slice(pos + 1);
332343333344 if (!newSegmentVal.includes('_')) {
334334- const newParts = { ...this.#segmentValues, [segment.type]: newSegmentVal };
345345+ const newParts = {
346346+ ...this.#segmentValues,
347347+ [segment.type]: newSegmentVal,
348348+ };
335349 const validationMsg = getSegmentValidationMessage(newParts, segment);
336350 if (validationMsg) {
337351 this.inlineError = validationMsg;