From 7038b149044843f94e8ef40befca5e372cf3ee24 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Wed, 13 May 2026 21:47:55 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BD=91=E9=A1=B5=E7=89=88=E5=8D=A1=E7=89=87?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E6=94=B9=E7=94=A8=20obs=5Ftime=EF=BC=88?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90=E6=97=B6=E9=97=B4=E6=88=B3=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=20ISO/epoch/Naive=20=E5=A4=9A?= =?UTF-8?q?=E7=A7=8D=E6=A0=BC=E5=BC=8F=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- monitoring-web/src/main.rs | 44 +++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/monitoring-web/src/main.rs b/monitoring-web/src/main.rs index 157790df..3586609d 100644 --- a/monitoring-web/src/main.rs +++ b/monitoring-web/src/main.rs @@ -53,6 +53,34 @@ struct MonitorTemplate { generated_at: String, } +// ── obs_time parsing ── + +fn parse_obs_time(raw: &str) -> Option> { + let s = raw.trim(); + // ISO with timezone: "2026-05-13T14:30:00+08:00" or "2026-05-13T14:30:00Z" + if let Ok(dt) = chrono::DateTime::parse_from_rfc3339(s) { + return Some(dt.into()); + } + // ISO naive: "2026-05-13T14:30:00" + if let Ok(dt) = chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S") { + return Some(dt.and_utc()); + } + // ISO with microseconds: "2026-05-13T14:30:00.123456" + if let Ok(dt) = chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S%.f") { + return Some(dt.and_utc()); + } + // Epoch seconds (METAR cluster) + if let Ok(secs) = s.parse::() { + if (1_000_000_000.0..3_000_000_000.0).contains(&secs) { + return chrono::DateTime::from_timestamp(secs as i64, 0); + } + if (100_000.0..1_000_000_000.0).contains(&secs) { + return chrono::DateTime::from_timestamp(secs as i64, 0); + } + } + None +} + // ── data loading ── fn load_city_snapshot(db_path: &str, idx: usize, (key, _zh, en, icao, airport, tz, thresh, tz_abbr, rw_count): &(&str, &str, &str, &str, &str, i32, f64, &str, usize)) -> CitySnapshot { @@ -64,14 +92,20 @@ fn load_city_snapshot(db_path: &str, idx: usize, (key, _zh, en, icao, airport, t let temps: Vec = obs.iter().filter_map(|o| o.temp_c).collect(); let current_temp = temps.first().copied(); - // Observation time from the most recent record + // Observation time from the most recent record's obs_time field let local_time = obs.first().and_then(|o| { - o.created_at.as_ref().and_then(|ts| { - chrono::NaiveDateTime::parse_from_str(ts, "%Y-%m-%d %H:%M:%S").ok() + o.obs_time.as_ref().and_then(|raw| parse_obs_time(raw)) + }) + .or_else(|| { + // Fallback: parse created_at + obs.first().and_then(|o| { + o.created_at.as_ref().and_then(|ts| { + chrono::NaiveDateTime::parse_from_str(ts, "%Y-%m-%d %H:%M:%S").ok() + .map(|dt| dt.and_utc()) + }) }) }) - .map(|dt| { - let obs_utc = dt.and_utc(); + .map(|obs_utc| { let local = obs_utc.with_timezone(&offset); format!("{} {}", local.format("%H:%M"), tz_abbr) })