From db65ae15047f960931b0e616ae20089583f2ccb5 Mon Sep 17 00:00:00 2001 From: antejavor Date: Wed, 27 Aug 2025 15:58:36 +0200 Subject: [PATCH 1/3] Update mg client and time zone api. --- mgclient | 2 +- src/value/mod.rs | 90 ++++++++++++++++-------------------------------- 2 files changed, 31 insertions(+), 61 deletions(-) diff --git a/mgclient b/mgclient index d57df8a..55cc7f5 160000 --- a/mgclient +++ b/mgclient @@ -1 +1 @@ -Subproject commit d57df8aba5d62074c56aced591147e2b2616c4dc +Subproject commit 55cc7f5fa291d649e4965a08751a4e05ed75696a diff --git a/src/value/mod.rs b/src/value/mod.rs index bd92a5b..c220946 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -250,76 +250,45 @@ pub(crate) fn mg_value_naive_local_date_time( Ok(NaiveDateTime::from_timestamp(c_seconds, nanoseconds)) } -pub(crate) fn mg_value_datetime_zone_id( - mg_value: *const bindings::mg_value, -) -> Result { - let c_datetime_zone_id = unsafe { bindings::mg_value_date_time_zone_id(mg_value) }; +fn mg_value_datetime_zone_id( + c_datetime_zone_id: *const bindings::mg_date_time_zone_id, +) -> Result { let c_seconds = unsafe { bindings::mg_date_time_zone_id_seconds(c_datetime_zone_id) }; let c_nanoseconds = unsafe { bindings::mg_date_time_zone_id_nanoseconds(c_datetime_zone_id) }; - let c_tz_id = unsafe { bindings::mg_date_time_zone_id_tz_id(c_datetime_zone_id) }; + let c_timezone_name_ptr = unsafe { bindings::mg_date_time_zone_id_timezone_name(c_datetime_zone_id) }; + + // Create NaiveDateTime from timestamp + let naive_datetime = match NaiveDateTime::from_timestamp_opt(c_seconds, c_nanoseconds as u32) { + Some(dt) => dt, + None => return Err(crate::error::MgError::new("Invalid timestamp values".to_string())), + }; - // Convert seconds since epoch to date/time components - let naive_datetime = NaiveDateTime::from_timestamp(c_seconds, c_nanoseconds as u32); + // Extract timezone name from mg_string + let timezone_name = if c_timezone_name_ptr.is_null() { + "UTC".to_string() + } else { + unsafe { mg_string_to_string(c_timezone_name_ptr) } + }; - // Systematic timezone ID resolution using hybrid approach - let (time_zone_id, time_zone_offset_seconds) = resolve_timezone_info(c_tz_id, c_seconds); + // Extract individual date/time fields + let date = naive_datetime.date(); + let time = naive_datetime.time(); Ok(DateTime { - year: naive_datetime.year(), - month: naive_datetime.month(), - day: naive_datetime.day(), - hour: naive_datetime.hour(), - minute: naive_datetime.minute(), - second: naive_datetime.second(), - nanosecond: naive_datetime.nanosecond(), - time_zone_offset_seconds, - time_zone_id, + year: date.year(), + month: date.month(), + day: date.day(), + hour: time.hour(), + minute: time.minute(), + second: time.second(), + nanosecond: time.nanosecond(), + time_zone_offset_seconds: 0, // For now, use 0 offset + time_zone_id: Some(timezone_name), }) } /// Resolves timezone information from the numeric timezone ID using a hybrid approach /// -/// This function implements a systematic approach to timezone resolution: -/// 1. Check for known exact timezone ID mappings -/// 2. Use heuristics to detect UTC-like timezones -/// 3. Fall back to a descriptive format that preserves the numeric ID -fn resolve_timezone_info(c_tz_id: i64, timestamp_seconds: i64) -> (Option, i32) { - // Phase 1: Known exact mappings - match c_tz_id { - 0 => return (Some("Etc/UTC".to_string()), 0), - 4294967302 | 139637976727558 => return (Some("Etc/UTC".to_string()), 0), - _ => {} - } - - // Phase 2: Heuristic detection for UTC-like timezones - if is_likely_utc_timezone(c_tz_id, timestamp_seconds) { - return (Some("Etc/UTC".to_string()), 0); - } - - // Phase 3: Preserve unknown timezone IDs with metadata - (Some(format!("TZ_{}", c_tz_id)), 0) -} - -/// Determines if a timezone ID likely represents UTC using heuristic analysis -/// -/// This function uses patterns observed from different environments to detect -/// UTC timezones that may have system-specific numeric representations. -fn is_likely_utc_timezone(tz_id: i64, _timestamp_seconds: i64) -> bool { - // Pattern observed: large positive numbers often represent UTC in various systems - // This heuristic successfully identified UTC in both local and CI environments - if tz_id > 1000000000 { - return true; - } - - // Additional heuristics can be added here: - // - Check against known UTC ranges from different systems - // - Validate timezone behavior for known timestamps - // - Pattern matching based on collected data from various environments - - // Conservative fallback - false -} - pub(crate) fn mg_value_duration(mg_value: *const bindings::mg_value) -> Duration { let c_duration = unsafe { bindings::mg_value_duration(mg_value) }; let days = unsafe { bindings::mg_duration_days(c_duration) }; @@ -551,7 +520,8 @@ impl Value { Value::LocalDateTime(mg_value_naive_local_date_time(c_mg_value).unwrap()) } bindings::mg_value_type_MG_VALUE_TYPE_DATE_TIME_ZONE_ID => { - Value::DateTime(mg_value_datetime_zone_id(c_mg_value).unwrap()) + let c_datetime_zone_id = unsafe { bindings::mg_value_date_time_zone_id(c_mg_value) }; + Value::DateTime(mg_value_datetime_zone_id(c_datetime_zone_id).unwrap()) } bindings::mg_value_type_MG_VALUE_TYPE_DURATION => { Value::Duration(mg_value_duration(c_mg_value)) From 73f7ab350a2284cc9e2a68ff21a7ec7aef6877b0 Mon Sep 17 00:00:00 2001 From: antejavor Date: Wed, 27 Aug 2025 16:00:21 +0200 Subject: [PATCH 2/3] Delete comment. --- src/value/mod.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/value/mod.rs b/src/value/mod.rs index c220946..95c8e37 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -255,12 +255,17 @@ fn mg_value_datetime_zone_id( ) -> Result { let c_seconds = unsafe { bindings::mg_date_time_zone_id_seconds(c_datetime_zone_id) }; let c_nanoseconds = unsafe { bindings::mg_date_time_zone_id_nanoseconds(c_datetime_zone_id) }; - let c_timezone_name_ptr = unsafe { bindings::mg_date_time_zone_id_timezone_name(c_datetime_zone_id) }; + let c_timezone_name_ptr = + unsafe { bindings::mg_date_time_zone_id_timezone_name(c_datetime_zone_id) }; // Create NaiveDateTime from timestamp let naive_datetime = match NaiveDateTime::from_timestamp_opt(c_seconds, c_nanoseconds as u32) { Some(dt) => dt, - None => return Err(crate::error::MgError::new("Invalid timestamp values".to_string())), + None => { + return Err(crate::error::MgError::new( + "Invalid timestamp values".to_string(), + )) + } }; // Extract timezone name from mg_string @@ -287,8 +292,7 @@ fn mg_value_datetime_zone_id( }) } -/// Resolves timezone information from the numeric timezone ID using a hybrid approach -/// + pub(crate) fn mg_value_duration(mg_value: *const bindings::mg_value) -> Duration { let c_duration = unsafe { bindings::mg_value_duration(mg_value) }; let days = unsafe { bindings::mg_duration_days(c_duration) }; @@ -520,7 +524,8 @@ impl Value { Value::LocalDateTime(mg_value_naive_local_date_time(c_mg_value).unwrap()) } bindings::mg_value_type_MG_VALUE_TYPE_DATE_TIME_ZONE_ID => { - let c_datetime_zone_id = unsafe { bindings::mg_value_date_time_zone_id(c_mg_value) }; + let c_datetime_zone_id = + unsafe { bindings::mg_value_date_time_zone_id(c_mg_value) }; Value::DateTime(mg_value_datetime_zone_id(c_datetime_zone_id).unwrap()) } bindings::mg_value_type_MG_VALUE_TYPE_DURATION => { From 13829bf3e27f431f51e0d9d13707d888daf83bd5 Mon Sep 17 00:00:00 2001 From: antejavor Date: Wed, 27 Aug 2025 16:00:27 +0200 Subject: [PATCH 3/3] Format. --- src/value/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/value/mod.rs b/src/value/mod.rs index 95c8e37..d016822 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -292,7 +292,6 @@ fn mg_value_datetime_zone_id( }) } - pub(crate) fn mg_value_duration(mg_value: *const bindings::mg_value) -> Duration { let c_duration = unsafe { bindings::mg_value_duration(mg_value) }; let days = unsafe { bindings::mg_duration_days(c_duration) };