From 2208ce77b66f74579f4ed968d6814009b8731109 Mon Sep 17 00:00:00 2001 From: Honey Date: Fri, 21 Aug 2026 19:59:26 +0200 Subject: [PATCH] fix(events): show the venue-local concert time consistently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend sent the UTC `dateTime` (a 20:00 local show read as 08:00Z), and Android's ZonedDateTime.parse choked on zone-less values → some rows had a wrong time, others none at all. - Backend: prefer localDate+localTime (venue-local, naive) over the UTC instant. - Android: parse a naive LocalDateTime first, fall back to ZonedDateTime for older "…Z" values. Web already renders the naive string as-is. Co-Authored-By: Claude Opus 4.8 --- .../novasonic/app/ui/component/ConcertsSheet.kt | 14 ++++++++++---- backend/novasonic-server.js | 7 +++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/android/app/src/main/kotlin/com/novasonic/app/ui/component/ConcertsSheet.kt b/android/app/src/main/kotlin/com/novasonic/app/ui/component/ConcertsSheet.kt index 11e616b..3d822fb 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/ui/component/ConcertsSheet.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/ui/component/ConcertsSheet.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.novasonic.app.api.model.ConcertEvent import com.novasonic.app.ui.theme.* +import java.time.LocalDateTime import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.util.Locale @@ -165,12 +166,17 @@ private fun EventRow(event: ConcertEvent, onTicketClick: (String) -> Unit) { } } +private val DATE_FMT = DateTimeFormatter.ofPattern("dd. MMM yyyy", Locale.GERMAN) +private val TIME_FMT = DateTimeFormatter.ofPattern("HH:mm") + private fun formatEventDateTime(datetime: String): Pair { return try { - val zdt = ZonedDateTime.parse(datetime) - val date = zdt.format(DateTimeFormatter.ofPattern("dd. MMM yyyy", Locale.GERMAN)) - val time = if (zdt.hour == 0 && zdt.minute == 0) "" - else zdt.format(DateTimeFormatter.ofPattern("HH:mm")) + // Backend now sends a naive venue-local datetime ("2026-09-16T20:00:00"); older/zoned + // values ("…Z") still parse via the ZonedDateTime fallback. + val ldt = runCatching { LocalDateTime.parse(datetime) } + .getOrElse { ZonedDateTime.parse(datetime).toLocalDateTime() } + val date = ldt.format(DATE_FMT) + val time = if (ldt.hour == 0 && ldt.minute == 0) "" else ldt.format(TIME_FMT) date to time } catch (_: Exception) { datetime.take(10) to "" diff --git a/backend/novasonic-server.js b/backend/novasonic-server.js index d8ca480..3eb563e 100644 --- a/backend/novasonic-server.js +++ b/backend/novasonic-server.js @@ -393,9 +393,12 @@ app.get('/api/events/:artist', (req, res) => { const events = raw.map(e => { const venue = e._embedded?.venues?.[0] || {}; const start = e.dates?.start || {}; - const dt = start.dateTime || (start.localDate + // Prefer the venue-LOCAL date/time (localDate + localTime) over the UTC `dateTime` — + // otherwise a 20:00 local show is shown as its 08:00Z UTC instant. Sent as a naive local + // datetime string (no zone); the clients render it as-is. + const dt = (start.localDate ? `${start.localDate}T${start.localTime || '00:00:00'}` - : null); + : start.dateTime) || null; const soldOut = e.dates?.status?.code === 'offsale' || e.dates?.status?.code === 'cancelled'; return {