Catch multi-day events that do not end on a day boundary

Requiring both ends to sit exactly on midnight was too strict. A holiday stored
as the 16th at 00:00 through the 21st at 01:00 slipped through and rendered as
a one-hour slot. Starting on a day boundary and running into a later day is
enough to call it all-day.

The agenda row now names the weekday on both sides when an event crosses a day.
Showing only "00:00 – 01:00" for something that runs from Wednesday to Monday
is true and useless.

The timezone handling above this is deliberately untouched: timed events show
the right time, so the UTC assumption for timestamps without an offset is not
what produced the odd hour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-12 14:52:52 +02:00
co-authored by Claude Opus 5
parent 465c465af2
commit e5b3e549e8
2 changed files with 24 additions and 7 deletions
+5 -1
View File
@@ -108,9 +108,13 @@ struct CalEvent: Identifiable, Hashable {
// holiday sent without the flag renders as "00:00 – 00:00" — a time
// range that is technically true and tells the reader nothing.
let cal = Calendar.current
// Requiring the end to land exactly on midnight too was too strict: a
// holiday stored as 16th 00:00 to 21st 01:00 slipped through and showed
// up as a one-hour slot. Starting on a day boundary and running into a
// later day is enough.
let spansWholeDays = e > s
&& cal.startOfDay(for: s) == s
&& cal.startOfDay(for: e) == e
&& cal.startOfDay(for: e) > cal.startOfDay(for: s)
let isAllDay = declaredAllDay || spansWholeDays
return CalEvent(
+19 -6
View File
@@ -41,14 +41,27 @@ extension Color {
}
enum WatchEventFormat {
static func timeRange(_ event: SnapshotEvent, language: String) -> String {
static func timeRange(_ event: SnapshotEvent, language: String,
calendar: Calendar = Calendar(identifier: .gregorian)) -> String {
if event.isAllDay { return WatchL10n.t("watch.allday", language) }
let formatter = DateFormatter()
formatter.locale = WatchL10n.locale(language)
formatter.dateFormat = "HH:mm"
let start = formatter.string(from: event.start)
let time = DateFormatter()
time.locale = WatchL10n.locale(language)
time.dateFormat = "HH:mm"
let start = time.string(from: event.start)
guard event.end > event.start else { return start }
return "\(start) – \(formatter.string(from: event.end))"
// Without the weekday, an event running from Wednesday to Monday reads
// as a one-hour slot: "00:00 – 01:00" is true and useless.
if calendar.startOfDay(for: event.end) > calendar.startOfDay(for: event.start) {
let day = DateFormatter()
day.locale = WatchL10n.locale(language)
day.setLocalizedDateFormatFromTemplate("EEE")
return "\(day.string(from: event.start)) \(start) – "
+ "\(day.string(from: event.end)) \(time.string(from: event.end))"
}
return "\(start) – \(time.string(from: event.end))"
}
static func time(_ date: Date, language: String) -> String {