fix: Wochenansicht – ganztägige Termine spannen sich nicht mehr über zwei Tage

Bei der Layout-Berechnung für ganztägige Termine wurden Start/Ende als
UTC-Zeitstempel mit der Lokal-Zeit der Tagesgrenze verglichen — das
führte in Zeitzonen mit positivem UTC-Offset (z.B. CET) dazu, dass
das exklusive DTEND zwei Stunden in den nächsten Tag hineinragte und
die UI den Termin auf zwei Tagen darstellte.

Fix: Für ganztägige Events normalisieren wir auf reine Datumswerte
(setHours(0,0,0,0)) und ziehen einen Tag vom End-Datum ab, sodass die
Vergleiche dieselbe inklusive Semantik wie die Monatsansicht nutzen.
Timed Events behalten die ursprüngliche strict-overlap Logik.

Auch die continues-left/right Marker arbeiten jetzt mit den
normalisierten Daten.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-05-10 11:01:13 +02:00
parent 50c19c7999
commit ba86092cc8

View File

@@ -63,8 +63,19 @@ export function renderWeek(container, currentDate, events, onSlotClick, onEventC
const color = ev.color || ev.calendarColor || '#4285f4';
const pastCls = isPast(ev) ? 'past' : '';
const multiCls = isMultiTimed ? 'multiday-timed' : '';
const cL = new Date(ev.start) < new Date(days[0]) ? 'continues-left' : '';
const cR = new Date(ev.end) > (() => { const d = new Date(days[n-1]); d.setHours(24,0,0,0); return d; })() ? 'continues-right' : '';
// continues-left/right: compute on date-only basis for all-day events
let evStart = new Date(ev.start);
let evEnd = new Date(ev.end);
if (ev.allDay) {
evStart.setHours(0, 0, 0, 0);
evEnd.setHours(0, 0, 0, 0);
if (evEnd > evStart) evEnd.setDate(evEnd.getDate() - 1);
}
const firstDay = new Date(days[0]); firstDay.setHours(0, 0, 0, 0);
const lastDayMidnight = new Date(days[n-1]); lastDayMidnight.setHours(24, 0, 0, 0);
const lastDay = new Date(days[n-1]); lastDay.setHours(0, 0, 0, 0);
const cL = evStart < firstDay ? 'continues-left' : '';
const cR = (ev.allDay ? evEnd > lastDay : evEnd > lastDayMidnight) ? 'continues-right' : '';
const label = isMultiTimed && isSameDay(new Date(ev.start), days[colStart])
? `${fmtTime(new Date(ev.start))} ${ev.title}`
: ev.title;
@@ -236,11 +247,28 @@ function renderNowLine(container, days, hourH = 60) {
function layoutWeekAllDay(evs, days) {
const items = [];
evs.forEach(ev => {
// For all-day events, normalize to date-only with inclusive end-day
// (iCal stores exclusive end → subtract 1). For timed events, keep
// the original strict-overlap logic so events ending exactly at
// midnight don't bleed into the next day.
let ns, ne;
if (ev.allDay) {
ns = new Date(ev.start); ns.setHours(0, 0, 0, 0);
ne = new Date(ev.end); ne.setHours(0, 0, 0, 0);
if (ne > ns) ne.setDate(ne.getDate() - 1);
}
let colStart = -1, colEnd = -1;
days.forEach((day, i) => {
const ds = new Date(day); ds.setHours(0, 0, 0, 0);
const de = new Date(day); de.setHours(24, 0, 0, 0);
if (new Date(ev.start) < de && new Date(ev.end) > ds) {
let matches;
if (ev.allDay) {
matches = ds >= ns && ds <= ne;
} else {
const de = new Date(day); de.setHours(24, 0, 0, 0);
matches = new Date(ev.start) < de && new Date(ev.end) > ds;
}
if (matches) {
if (colStart === -1) colStart = i;
colEnd = i;
}