diff --git a/frontend/src/components/EventSlideOver.vue b/frontend/src/components/EventSlideOver.vue index 5c5a776..0eb2c39 100644 --- a/frontend/src/components/EventSlideOver.vue +++ b/frontend/src/components/EventSlideOver.vue @@ -68,9 +68,11 @@ function resetForm() { if (props.event) { title.value = props.event.title; allDay.value = props.event.all_day; - startDate.value = dateFromIso(props.event.start_dt); + // All-day events: use UTC date string directly to avoid timezone shifting + // (UTC midnight parsed through new Date() becomes the previous day in UTC-X zones) + startDate.value = props.event.all_day ? props.event.start_dt.slice(0, 10) : dateFromIso(props.event.start_dt); startTime.value = props.event.all_day ? "" : timeFromIso(props.event.start_dt); - endDate.value = props.event.end_dt ? dateFromIso(props.event.end_dt) : ""; + endDate.value = props.event.end_dt ? (props.event.all_day ? props.event.end_dt.slice(0, 10) : dateFromIso(props.event.end_dt)) : ""; endTime.value = props.event.end_dt && !props.event.all_day ? timeFromIso(props.event.end_dt) : ""; description.value = props.event.description || ""; location.value = props.event.location || ""; diff --git a/frontend/src/views/CalendarView.vue b/frontend/src/views/CalendarView.vue index a6ac12e..590ac3f 100644 --- a/frontend/src/views/CalendarView.vue +++ b/frontend/src/views/CalendarView.vue @@ -39,11 +39,13 @@ function closeSlideOver() { const eventCache = new Map(); function toFcEvent(e: EventEntry) { + // For all-day events pass date-only strings so FullCalendar never shifts + // the date through timezone conversion (UTC midnight → previous day in UTC-X). return { id: String(e.id), title: e.title, - start: e.start_dt, - end: e.end_dt ?? undefined, + start: e.all_day ? e.start_dt.slice(0, 10) : e.start_dt, + end: e.all_day ? (e.end_dt?.slice(0, 10) ?? undefined) : (e.end_dt ?? undefined), allDay: e.all_day, backgroundColor: e.color || undefined, borderColor: e.color || undefined,