@@ -4,8 +4,10 @@ use std::collections::HashMap;
44use crate :: detection_mask:: DetectionMask ;
55use byteorder:: { LittleEndian , WriteBytesExt } ;
66use 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 ;
911use log:: { error, info, warn} ;
1012use louvre:: triangulate;
1113use notify:: event:: { AccessKind , AccessMode } ;
@@ -17,11 +19,14 @@ use std::io::{Cursor, Write};
1719use std:: ops:: Add ;
1820use std:: path:: Path ;
1921use std:: str:: FromStr ;
22+ use std:: sync:: LazyLock ;
2023use std:: sync:: mpsc:: { Receiver , Sender , TryRecvError } ;
2124use std:: { fs, process} ;
2225use sun_times:: sun_times;
2326use 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
2631fn 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 ) ]
348354pub struct AbsRelTime {
@@ -369,14 +375,15 @@ impl Debug for AbsRelTime {
369375}
370376
371377impl 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