Show event times in Berlin time
`toLocaleString()` was given the German locale but no time zone, so it printed
the time in whatever zone the browser of the visitor is set to. The events
happen in Berlin, so this is only correct for visitors who are in Berlin.
Somebody reading the start page from Sydney was told the Plenum of Tuesday
20:00 takes place on Wednesday at 04:00.
Format in Europe/Berlin explicitly. For an event that names a point in time
only the printing was wrong, picking and sorting work on absolute points in
time and were not affected.
An all day event carries a date, and a date has neither a time nor a zone: its
digits are the day itself. `toJSDate()` reads them as midnight in the zone of
the browser, so the point in time that is then printed in Berlin time is off by
the offset between the two, which puts a bogus time of day on the entry and,
far enough east or west, the wrong day. An event on 30.08. was announced as:
Berlin Sonntag, 30.08., 00:00 Uhr
Los Angeles Sonntag, 30.08., 09:00 Uhr
Tokio Samstag, 29.08., 17:00 Uhr
Keep the digits of the date and read them as UTC, which no browser setting
moves, and print an all day event in UTC and without a time of day. Berlin,
Tokyo, Los Angeles and Kiritimati all say "Sonntag, 30.08." now, while a timed
event keeps saying "Sonntag, 30.08., 19:00 Uhr" everywhere. Sorting improves
with it, an all day event no longer changes its place in the list depending on
where the visitor sits.
The published calendar has no all day events today, they can be created in the
CalDAV calendar the export comes from.
Drop the two replacements around the formatted date while touching it. The
first removes the comma after the weekday and the second puts it back, so they
cancel each other out:
"Samstag, 22.08., 17:00" -> "Samstag 22.08., 17:00" -> "Samstag, 22.08., 17:00"
Fixes: c28f04c6e8 ("switch to ics files; make calendars work; fix some minor issues")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
parent
6d99a39190
commit
cd39842ac0
1 changed files with 40 additions and 16 deletions
|
|
@ -64,6 +64,26 @@ function exceptionsByUid(components) {
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* When an occurrence starts, as a point in time.
|
||||
*
|
||||
* A date has no time and no zone, its digits are the day itself. toJSDate()
|
||||
* reads them as midnight in the zone of the browser, which moves an all day
|
||||
* event by the offset that zone has to Berlin and, far enough east or west,
|
||||
* onto the day before or after. Keep the digits and read them as UTC instead,
|
||||
* the table prints an all day event in UTC as well.
|
||||
*
|
||||
* @param {ICAL.Time} time Start of the occurrence
|
||||
* @returns {Date} The point in time to sort and print by
|
||||
*/
|
||||
function startOf(time) {
|
||||
if (time.isDate) {
|
||||
return new Date(Date.UTC(time.year, time.month - 1, time.day));
|
||||
}
|
||||
|
||||
return time.toJSDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* How far the recurrences of an event have to be iterated.
|
||||
*
|
||||
|
|
@ -98,7 +118,7 @@ function iterationEnd(event, end) {
|
|||
* @param {Date} now Events must still be running at this date
|
||||
* @param {number} maxEvents Maximum number of events to return
|
||||
* @param {number} maxDays Maximum number of days into the future
|
||||
* @returns {{start: Date, name: string, url: string}[]} url is empty when the event has no URL
|
||||
* @returns {{start: Date, allDay: boolean, name: string, url: string}[]} url is empty when the event has no URL
|
||||
*/
|
||||
function getUpcomingEvents(icsText, now, maxEvents, maxDays) {
|
||||
const jcal = ICAL.parse(icsText);
|
||||
|
|
@ -153,22 +173,20 @@ function getUpcomingEvents(icsText, now, maxEvents, maxDays) {
|
|||
// judge it by the time it really takes place at.
|
||||
if (details.startDate.toJSDate() <= end && details.endDate.toJSDate() > now) {
|
||||
events.push({
|
||||
start: details.startDate.toJSDate(),
|
||||
start: startOf(details.startDate),
|
||||
allDay: details.startDate.isDate,
|
||||
name: details.item.summary ?? "",
|
||||
url: eventUrl(details.item),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const start = event.startDate.toJSDate();
|
||||
|
||||
if (start <= end && event.endDate.toJSDate() > now) {
|
||||
events.push({
|
||||
start,
|
||||
name: event.summary ?? "",
|
||||
url: eventUrl(event),
|
||||
});
|
||||
}
|
||||
} else if (event.startDate.toJSDate() <= end && event.endDate.toJSDate() > now) {
|
||||
events.push({
|
||||
start: startOf(event.startDate),
|
||||
allDay: event.startDate.isDate,
|
||||
name: event.summary ?? "",
|
||||
url: eventUrl(event),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,15 +213,21 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
|
||||
const colBegin = document.createElement("td");
|
||||
|
||||
// The events take place in Berlin, so name their time in Berlin time
|
||||
// instead of in the time zone the visitor happens to be in. An all day
|
||||
// event has no time of day and carries its date in UTC, see startOf().
|
||||
const whenFormat = event.allDay
|
||||
? { timeZone: "UTC" }
|
||||
: { timeZone: "Europe/Berlin", hour: "2-digit", minute: "2-digit" };
|
||||
|
||||
const formattedStart = event.start.toLocaleString("de-DE", {
|
||||
weekday: "long",
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
}).replace(",", "");
|
||||
...whenFormat,
|
||||
});
|
||||
|
||||
colBegin.innerText = `${formattedStart.replace(" ", ", ")} Uhr`;
|
||||
colBegin.innerText = event.allDay ? formattedStart : `${formattedStart} Uhr`;
|
||||
row.appendChild(colBegin);
|
||||
|
||||
const colName = document.createElement("td");
|
||||
|
|
|
|||
Loading…
Reference in a new issue