Fix the same UTC-vs-local mismatch in Ūdens's observedAt display

Same root cause as the station-observation fix (this uses the same
open-data portal, same UTC DATETIME field): the raw UTC string was
passed straight through to the frontend as a display label, which
JS's Date parser then reads as local time for a string with no
timezone suffix — silently showing observation times 2-3h behind
the newsroom's actual clock. Internal recency filtering (isRecent)
was already self-consistent either way; this only affects display.
This commit is contained in:
b0txec
2026-08-23 21:26:14 +03:00
parent cab94d097c
commit 3315f00fb1
@@ -9,7 +9,7 @@ import org.http4s.ember.client.EmberClientBuilder
import org.typelevel.log4cats.Logger
import org.typelevel.log4cats.slf4j.Slf4jLogger
import java.time.{Duration, Instant, LocalDateTime}
import java.time.{Duration, Instant, LocalDateTime, ZoneId, ZoneOffset}
import scala.util.Try
final case class WaterTemperatureReading(area: String, observedAt: String, min: Option[Double], max: Option[Double])
@@ -43,6 +43,15 @@ final class WaterTemperatureService private (logger: Logger[IO], cache: Ref[IO,
private val areaOrder: Vector[String] = Vector("Jūra", "Līcis", "Kurzeme", "Zemgale", "Vidzeme", "Latgale")
// This dataset's DATETIME field is UTC (same source/portal as the station
// observations feed, same verified offset); converted to local so the
// observedAt label shown on Ūdens matches the newsroom's own clock instead
// of reading 2-3h behind.
private val rigaZone = ZoneId.of("Europe/Riga")
private def toLocal(utcDatetime: String): Option[String] =
Try(LocalDateTime.parse(utcDatetime).atZone(ZoneOffset.UTC).withZoneSameInstant(rigaZone).toLocalDateTime.toString).toOption
// Every LVĢMC hydrological station that reports water temperature (WTEMD
// inland/river stations, SEDUT coastal stations), grouped into the six
// named Ūdens zones. Boundaries follow Latvia's historical regions
@@ -177,7 +186,8 @@ final class WaterTemperatureService private (logger: Logger[IO], cache: Ref[IO,
val cursor = row.hcursor
for {
stationId <- cursor.downField("STATION_ID").as[String].toOption
datetime <- cursor.downField("DATETIME").as[String].toOption
rawDatetime <- cursor.downField("DATETIME").as[String].toOption
datetime <- toLocal(rawDatetime)
value <- cursor.downField("VALUE").as[Double].toOption
} yield StationReading(stationId, datetime, value)
}