Das Symptom
Du importierst via gromox-eml2mt --ical einen all-day Event für Mittwoch und Donnerstag:
DTSTART;VALUE=DATE:20260422
DTEND;VALUE=DATE:20260424
SUMMARY:Kind bei Papa
Laut RFC 5545 ist DTEND bei DATE-Werten exclusive, also sollte der Event am Mittwoch beginnen und Donnerstag zu Ende sein — Mi+Do, zwei Tage. Stattdessen zeigt grommunio-Web (und auch Outlook nach Sync) drei Tage: Mi + Do + Fr-Vormittag.
Ursache
gromox-eml2mt behandelt DATE-Werte als DATETIME in UTC. Aus
DTSTART;VALUE=DATE:20260422 → 2026-04-22T00:00:00Z
DTEND;VALUE=DATE:20260424 → 2026-04-24T00:00:00Z
wird in der Zielzeitzone Europe/Berlin (CEST = UTC+2):
Start: 2026-04-22T02:00:00 CEST (Mi 02:00)
Ende: 2026-04-24T02:00:00 CEST (Fr 02:00)
Das deckt Mi (komplett), Do (komplett) und zieht sich bis Fr 02:00 morgens — in der Wochenansicht erscheint deshalb auch Freitag als belegter Tag. Im Winter mit CET (+1h) wäre der Effekt kleiner, aber immer noch sichtbar.
Überprüfen per gromox-mbop:
gromox-mbop -u user@example.de get-freebusy \
-a 2026-04-20T00:00:00 -b 2026-04-30T00:00:00 | grep "Kind bei Papa"
Output:
{start=2026-04-22T02:00:00, end=2026-04-24T02:00:00, subject="Kind bei Papa"}
Die T02:00:00 beweisen den UTC→Lokalzeit-Shift.
Workaround
Verwende statt DATE-only Werten DATETIME mit expliziter Zeitzone und bette eine VTIMEZONE-Komponente ein. Dann rechnet gromox die Zeiten korrekt in Lokalzeit ohne Offset-Drift.
BEGIN:VCALENDAR
PRODID:-//example//DE
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
UID:12345@example.de
DTSTAMP:20260419T140000Z
DTSTART;TZID=Europe/Berlin:20260422T000000
DTEND;TZID=Europe/Berlin:20260424T000000
SUMMARY:Kind bei Papa
X-MICROSOFT-CDO-ALLDAYEVENT:TRUE
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
Das X-MICROSOFT-CDO-ALLDAYEVENT:TRUE signalisiert Outlook/grommunio-Web zusätzlich, dass es sich um einen ganztägigen Termin handelt — kosmetisch, aber hilfreich für die korrekte Darstellung.
Verifikation nach Re-Import
{start=2026-04-22T00:00:00, end=2026-04-24T00:00:00, subject="Kind bei Papa"}
T00:00:00 ohne Offset — genau das, was wir wollten.
Warum das kein reiner gromox-Bug ist
Microsoft/Outlook und auch einige andere MAPI-Stores haben historisch DATE-Werte intern als UTC-DATETIME repräsentiert. Die Übersetzung DATE ↔ MAPI ist in der Spezifikation nicht eindeutig, und unterschiedliche Implementierungen bewältigen es unterschiedlich. gromox ist hier Exchange-kompatibel — was leider heißt: genauso suboptimal.
Der saubere Weg in iCalendar ist nun mal VALUE=DATE für all-day Events. Aber wenn dein Ziel-Store ein MAPI-basierter ist, kommst du mit expliziter VTIMEZONE besser durch.
Fazit
Wenn du iCal-Dateien programmatisch erzeugst und nach grommunio/gromox importierst:
- All-day Events: immer mit TZID und DATETIME, nie mit
VALUE=DATE. - Nach dem Import: per
gromox-mbop get-freebusydie tatsächlichen Start/End-Zeiten prüfen. Wenn sieT02:00:00stattT00:00:00sind, weißt du Bescheid. - Normale (timed) Events sind nicht betroffen — die haben von Haus aus TZID und rechnen korrekt.
Kostet fünf Minuten mehr beim iCal-Template-Bau, erspart dir aber, dass dein Chef seinen Freitag Vormittag blockiert sieht obwohl er frei hat.