Skip to content

Commit 8644931

Browse files
committed
- Calculate the timezone from the device config lat/lng coordinates.
1 parent 4a71fe7 commit 8644931

File tree

2 files changed

+31
-24
lines changed

2 files changed

+31
-24
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ louvre = "0.2.1"
3030
rustbus = "0.19.3"
3131
sha256 = "1.5.0"
3232
sysinfo = "0.35.2"
33+
tzf-rs = { version = "1.1.3", default-features = false }
3334

3435
[target.'cfg(target_env = "musl")'.dependencies]
3536
mimalloc = "0.1.43"

src/device_config.rs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ use std::collections::HashMap;
44
use crate::detection_mask::DetectionMask;
55
use byteorder::{LittleEndian, WriteBytesExt};
66
use chrono::{
7-
DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc,
7+
DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone,
8+
Utc,
89
};
10+
use chrono_tz::Tz;
911
use log::{error, info, warn};
1012
use louvre::triangulate;
1113
use notify::event::{AccessKind, AccessMode};
@@ -17,11 +19,14 @@ use std::io::{Cursor, Write};
1719
use std::ops::Add;
1820
use std::path::Path;
1921
use std::str::FromStr;
22+
use std::sync::LazyLock;
2023
use std::sync::mpsc::{Receiver, Sender, TryRecvError};
2124
use std::{fs, process};
2225
use sun_times::sun_times;
2326
use toml::Value;
24-
use toml::value::Offset;
27+
use toml::value::Offset as TomlDateTimeOffset;
28+
29+
static TZ_FINDER: LazyLock<tzf_rs::DefaultFinder> = LazyLock::new(|| tzf_rs::DefaultFinder::new());
2530

2631
fn default_constant_recorder() -> bool {
2732
false
@@ -284,8 +289,8 @@ where
284289
let time = date_time.time.expect("should have time");
285290
let offset = date_time.offset.expect("should have offset");
286291
let offset_minutes = match offset {
287-
Offset::Z => 0,
288-
Offset::Custom { minutes } => minutes,
292+
TomlDateTimeOffset::Z => 0,
293+
TomlDateTimeOffset::Custom { minutes } => minutes,
289294
} as i32;
290295
let fixed_offset = if offset_minutes < 0 {
291296
FixedOffset::east_opt(offset_minutes * 60)
@@ -337,12 +342,13 @@ struct HourMin {
337342
min: u8,
338343
}
339344

340-
fn timezone_offset_seconds() -> i32 {
341-
// IMPORTANT: This relies on the system timezone being set correctly to the same locale as the
342-
// devices' GPS coordinates to work out correct absolute start/end recording window times.
343-
let now = Local::now();
344-
let local_tz = now.timezone();
345-
local_tz.offset_from_utc_datetime(&now.naive_utc()).local_minus_utc()
345+
fn timezone_offset_seconds(lat: f32, lng: f32) -> i32 {
346+
let tz_from_lat_lng = TZ_FINDER.get_tz_name(lat as f64, lng as f64);
347+
let tz = Tz::from_str(tz_from_lat_lng)
348+
.expect(&format!("Failed to parse timezone from lat lng {tz_from_lat_lng}"));
349+
let now_utc = Local::now().naive_utc();
350+
let offset = tz.offset_from_utc_datetime(&now_utc);
351+
offset.fix().local_minus_utc()
346352
}
347353
#[derive(PartialEq, Clone)]
348354
pub struct AbsRelTime {
@@ -369,14 +375,15 @@ impl Debug for AbsRelTime {
369375
}
370376

371377
impl AbsRelTime {
372-
pub fn time_offset(&self) -> (bool, i32) {
378+
pub fn time_offset(&self, lat: f32, lng: f32) -> (bool, i32) {
373379
// Absolute or relative time in seconds in the day
374380
if let Some(abs_time) = &self.absolute_time {
375381
// NOTE: We need to convert this to UTC offsets, since that's what our timestamp is.
376382
let seconds_past_midnight =
377383
(abs_time.hour as i32 * 60 * 60) + (abs_time.min as i32 * 60);
378384
//info!("Seconds past midnight local {}", seconds_past_midnight);
379-
let tz_offset = timezone_offset_seconds();
385+
386+
let tz_offset = timezone_offset_seconds(lat, lng);
380387
// info!(
381388
// "TZ offset {}, seconds past UTC midnight {}",
382389
// tz_offset,
@@ -582,9 +589,10 @@ impl DeviceConfig {
582589
}
583590

584591
pub fn lat_lng(&self) -> (f32, f32) {
592+
let location = self.location.as_ref().expect("A device location is required");
585593
(
586-
self.location.as_ref().unwrap().latitude.unwrap(),
587-
self.location.as_ref().unwrap().longitude.unwrap(),
594+
location.latitude.expect("A valid latitude is required"),
595+
location.longitude.expect("A valid longitude is required"),
588596
)
589597
}
590598
pub fn location_timestamp(&self) -> Option<u64> {
@@ -675,22 +683,20 @@ impl DeviceConfig {
675683
}
676684

677685
pub fn next_recording_window(&self, now_utc: &NaiveDateTime) -> (NaiveDateTime, NaiveDateTime) {
686+
let location =
687+
self.location.as_ref().expect("Relative recording windows require a location");
688+
let (lat, lng) = self.lat_lng();
678689
let (is_absolute_start, mut start_offset) =
679-
self.recording_window.start_recording.time_offset();
680-
let (is_absolute_end, mut end_offset) = self.recording_window.stop_recording.time_offset();
690+
self.recording_window.start_recording.time_offset(lat, lng);
691+
let (is_absolute_end, mut end_offset) =
692+
self.recording_window.stop_recording.time_offset(lat, lng);
681693
if is_absolute_end && end_offset < 0 {
682694
end_offset += 86_400;
683695
}
684696
if is_absolute_start && start_offset < 0 {
685697
start_offset += 86_400;
686698
}
687699
let (window_start, window_end) = if !is_absolute_start || !is_absolute_end {
688-
let location =
689-
self.location.as_ref().expect("Relative recording windows require a location");
690-
let (lat, lng) = (
691-
location.latitude.expect("Relative recording windows require a valid latitude"),
692-
location.longitude.expect("Relative recording windows require a valid longitude"),
693-
);
694700
let altitude = location.altitude;
695701
let yesterday_utc = *now_utc - Duration::days(1);
696702
let (_, yesterday_sunset) = sun_times(
@@ -871,8 +877,8 @@ impl DeviceConfig {
871877
buf.write_u8(has_loc_accuracy).unwrap();
872878
buf.write_f32::<LittleEndian>(accuracy).unwrap();
873879
let (abs_rel_start, abs_rel_end) = self.recording_window();
874-
let (start_is_abs, start_seconds_offset) = abs_rel_start.time_offset();
875-
let (end_is_abs, end_seconds_offset) = abs_rel_end.time_offset();
880+
let (start_is_abs, start_seconds_offset) = abs_rel_start.time_offset(latitude, longitude);
881+
let (end_is_abs, end_seconds_offset) = abs_rel_end.time_offset(latitude, longitude);
876882
buf.write_u8(if start_is_abs { 1 } else { 0 }).unwrap();
877883
buf.write_i32::<LittleEndian>(start_seconds_offset).unwrap();
878884
buf.write_u8(if end_is_abs { 1 } else { 0 }).unwrap();

0 commit comments

Comments
 (0)