From 96e026ff36eeaf3ab9fc0542b3eaccdf78deddda Mon Sep 17 00:00:00 2001 From: Abdelkader Boudih Date: Mon, 22 Jun 2026 14:24:12 +0100 Subject: [PATCH] refactor!: replace chrono/chrono-tz with jiff behind newtypes BREAKING CHANGE: Value/QueryParam date variants now use rsmgclient-owned Date/LocalTime/LocalDateTime/Duration newtypes instead of chrono::Naive*/ Duration. jiff is a private implementation detail, so future datetime-backend swaps stay non-breaking. - drop chrono + chrono-tz deps; add jiff (bundles tzdb, no separate tz crate) - mg_value_datetime_zone_id now resolves the instant in its IANA zone via jiff TimeZone instead of manual chrono-tz offset math - Duration wraps jiff SignedDuration (flat duration, matching prior semantics) - Display output preserved (LocalDateTime space separator, Duration PT..S) Note: zoned DateTime now reports zone-local wall-clock fields (previously UTC fields + separate offset); identical for UTC, corrected for other zones. --- Cargo.toml | 3 +- src/value.rs | 380 ++++++++++++++++++++++++++++++--------------- src/value/tests.rs | 69 +++----- 3 files changed, 278 insertions(+), 174 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 92e9b42..abe3213 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,7 @@ exclude = [ [dependencies] maplit = "1.0" -chrono = "0.4" -chrono-tz = "0.10" +jiff = "0.2" thiserror = "2.0" [dev-dependencies] diff --git a/src/value.rs b/src/value.rs index a525c32..414776c 100644 --- a/src/value.rs +++ b/src/value.rs @@ -13,19 +13,194 @@ // limitations under the License. use super::bindings; -use chrono::{ - Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone, Timelike, Utc, -}; -use chrono_tz::Tz; +use crate::error::MgError; +use jiff::civil; +use jiff::tz::{Offset, TimeZone}; +use jiff::{SignedDuration, Span, Timestamp}; use std::collections::HashMap; -use std::convert::TryFrom; use std::ffi::{CStr, CString}; use std::fmt; use std::fmt::Formatter; -use std::num::TryFromIntError; use std::os::raw::c_char; use std::slice; +/// A calendar date (year-month-day) with no time zone. Backed by `jiff`. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct Date(civil::Date); + +impl Date { + /// Creates a date from its calendar components, erroring on an invalid date. + pub fn new(year: i16, month: i8, day: i8) -> Result { + civil::Date::new(year, month, day) + .map(Date) + .map_err(|e| MgError::invalid_parameter("date", e.to_string())) + } + + pub fn year(&self) -> i16 { + self.0.year() + } + pub fn month(&self) -> i8 { + self.0.month() + } + pub fn day(&self) -> i8 { + self.0.day() + } +} + +impl fmt::Display for Date { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +/// A wall-clock time of day (no date, no time zone). Backed by `jiff`. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct LocalTime(civil::Time); + +impl LocalTime { + /// Creates a time from its components, erroring on an invalid time. + pub fn new(hour: i8, minute: i8, second: i8, nanosecond: i32) -> Result { + civil::Time::new(hour, minute, second, nanosecond) + .map(LocalTime) + .map_err(|e| MgError::invalid_parameter("local_time", e.to_string())) + } + + pub fn hour(&self) -> i8 { + self.0.hour() + } + pub fn minute(&self) -> i8 { + self.0.minute() + } + pub fn second(&self) -> i8 { + self.0.second() + } + /// Sub-second component, in nanoseconds (0..=999_999_999). + pub fn nanosecond(&self) -> i32 { + self.0.subsec_nanosecond() + } +} + +impl fmt::Display for LocalTime { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +/// A date and wall-clock time with no time zone. Backed by `jiff`. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct LocalDateTime(civil::DateTime); + +impl LocalDateTime { + /// Creates a datetime from its components, erroring on invalid input. + #[allow(clippy::too_many_arguments)] + pub fn new( + year: i16, + month: i8, + day: i8, + hour: i8, + minute: i8, + second: i8, + nanosecond: i32, + ) -> Result { + let date = civil::Date::new(year, month, day) + .map_err(|e| MgError::invalid_parameter("local_date_time", e.to_string()))?; + let time = civil::Time::new(hour, minute, second, nanosecond) + .map_err(|e| MgError::invalid_parameter("local_date_time", e.to_string()))?; + Ok(LocalDateTime(civil::DateTime::from_parts(date, time))) + } + + pub fn year(&self) -> i16 { + self.0.year() + } + pub fn month(&self) -> i8 { + self.0.month() + } + pub fn day(&self) -> i8 { + self.0.day() + } + pub fn hour(&self) -> i8 { + self.0.hour() + } + pub fn minute(&self) -> i8 { + self.0.minute() + } + pub fn second(&self) -> i8 { + self.0.second() + } + /// Sub-second component, in nanoseconds (0..=999_999_999). + pub fn nanosecond(&self) -> i32 { + self.0.subsec_nanosecond() + } +} + +impl fmt::Display for LocalDateTime { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + // Space-separated date and time (kept stable across the chrono -> jiff move). + write!(f, "{} {}", self.0.date(), self.0.time()) + } +} + +/// A signed, calendar-free duration (a fixed amount of time). Backed by `jiff`. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct Duration(SignedDuration); + +impl Duration { + /// A duration of `days` whole days (each treated as 86 400 seconds). + pub fn days(days: i64) -> Self { + Duration(SignedDuration::from_secs(days * 86_400)) + } + /// A duration of `seconds` whole seconds. + pub fn seconds(seconds: i64) -> Self { + Duration(SignedDuration::from_secs(seconds)) + } + /// A duration of `nanoseconds` nanoseconds. + pub fn nanoseconds(nanoseconds: i64) -> Self { + Duration(SignedDuration::from_nanos(nanoseconds)) + } + + /// Total number of whole weeks in the duration. + pub fn num_weeks(&self) -> i64 { + self.num_seconds() / (7 * 86_400) + } + /// Total number of whole days in the duration. + pub fn num_days(&self) -> i64 { + self.num_seconds() / 86_400 + } + /// Total number of whole hours in the duration. + pub fn num_hours(&self) -> i64 { + self.num_seconds() / 3_600 + } + /// Total number of whole seconds in the duration. + pub fn num_seconds(&self) -> i64 { + self.0.as_secs() + } + /// Total number of nanoseconds in the duration. + pub fn num_nanoseconds(&self) -> i64 { + self.0.as_nanos() as i64 + } +} + +impl std::ops::Add for Duration { + type Output = Duration; + fn add(self, other: Duration) -> Duration { + Duration(self.0 + other.0) + } +} + +impl fmt::Display for Duration { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + // ISO 8601 `PTS` form (kept stable across the chrono -> jiff move). + let secs = self.0.as_secs(); + let nanos = self.0.subsec_nanos().unsigned_abs(); + if nanos == 0 { + write!(f, "PT{secs}S") + } else { + let frac = format!("{nanos:09}"); + write!(f, "PT{}.{}S", secs, frac.trim_end_matches('0')) + } + } +} + /// Representation of Point2D spatial data type. #[derive(Debug, PartialEq, Clone)] pub struct Point2D { @@ -70,9 +245,9 @@ pub enum QueryParam { Int(i64), Float(f64), String(String), - Date(NaiveDate), - LocalTime(NaiveTime), - LocalDateTime(NaiveDateTime), + Date(Date), + LocalTime(LocalTime), + LocalDateTime(LocalDateTime), Duration(Duration), Point2D(Point2D), Point3D(Point3D), @@ -129,17 +304,17 @@ impl QueryParam { value_or_null(bindings::mg_value_make_string(c_string.as_ptr())) } QueryParam::Date(x) => wrap_or_null!( - naive_date_to_mg_date(x), + date_to_mg_date(x), bindings::mg_value_make_date, bindings::mg_date_destroy ), QueryParam::LocalTime(x) => wrap_or_null!( - naive_local_time_to_mg_local_time(x), + local_time_to_mg_local_time(x), bindings::mg_value_make_local_time, bindings::mg_local_time_destroy ), QueryParam::LocalDateTime(x) => wrap_or_null!( - naive_local_date_time_to_mg_local_date_time(x), + local_date_time_to_mg_local_date_time(x), bindings::mg_value_make_local_date_time, bindings::mg_local_date_time_destroy ), @@ -253,9 +428,9 @@ pub enum Value { Float(f64), String(String), List(Vec), - Date(NaiveDate), - LocalTime(NaiveTime), - LocalDateTime(NaiveDateTime), + Date(Date), + LocalTime(LocalTime), + LocalDateTime(LocalDateTime), DateTime(DateTime), Duration(Duration), Point2D(Point2D), @@ -316,103 +491,74 @@ pub(crate) fn mg_value_string(mg_value: *const bindings::mg_value) -> String { mg_string_to_string(c_str) } -fn days_as_seconds(days: i64) -> i64 { - hours_as_seconds(days * 24) -} - -fn hours_as_seconds(hours: i64) -> i64 { - minutes_as_seconds(hours * 60) -} - -fn minutes_as_seconds(minutes: i64) -> i64 { - minutes * 60 -} - const NSEC_IN_SEC: i64 = 1_000_000_000; -pub(crate) fn mg_value_naive_date(mg_value: *const bindings::mg_value) -> Result { +pub(crate) fn mg_value_date(mg_value: *const bindings::mg_value) -> Result { let c_date = unsafe { bindings::mg_value_date(mg_value) }; let c_delta_days = unsafe { bindings::mg_date_days(c_date) }; - // Unix epoch date is a known valid date - let epoch_date = NaiveDate::from_ymd_opt(1970, 1, 1).expect("Unix epoch is a valid date"); - let delta_days = Duration::days(c_delta_days); - epoch_date.checked_add_signed(delta_days).ok_or(()) + // mgclient stores dates as a signed day offset from the Unix epoch. + civil::date(1970, 1, 1) + .checked_add(Span::new().days(c_delta_days)) + .map(Date) + .map_err(|e| MgError::invalid_parameter("date", e.to_string())) } -pub(crate) fn mg_value_naive_local_time( +pub(crate) fn mg_value_local_time( mg_value: *const bindings::mg_value, -) -> Result { +) -> Result { let c_local_time = unsafe { bindings::mg_value_local_time(mg_value) }; - let c_nanoseconds = unsafe { bindings::mg_local_time_nanoseconds(c_local_time) }; - let seconds = u32::try_from(c_nanoseconds / NSEC_IN_SEC)?; - let nanoseconds = u32::try_from(c_nanoseconds % NSEC_IN_SEC)?; - NaiveTime::from_num_seconds_from_midnight_opt(seconds, nanoseconds) - .ok_or_else(|| u32::try_from(-1).unwrap_err()) + let total_ns = unsafe { bindings::mg_local_time_nanoseconds(c_local_time) }; + let hour = (total_ns / NSEC_IN_SEC / 3_600) as i8; + let minute = (total_ns / NSEC_IN_SEC / 60 % 60) as i8; + let second = (total_ns / NSEC_IN_SEC % 60) as i8; + let subsec = (total_ns % NSEC_IN_SEC) as i32; + LocalTime::new(hour, minute, second, subsec) } -pub(crate) fn mg_value_naive_local_date_time( +pub(crate) fn mg_value_local_date_time( mg_value: *const bindings::mg_value, -) -> Result { +) -> Result { let c_local_date_time = unsafe { bindings::mg_value_local_date_time(mg_value) }; let c_seconds = unsafe { bindings::mg_local_date_time_seconds(c_local_date_time) }; let c_nanoseconds = unsafe { bindings::mg_local_date_time_nanoseconds(c_local_date_time) }; - let nanoseconds = u32::try_from(c_nanoseconds)?; - Utc.timestamp_opt(c_seconds, nanoseconds) - .single() - .map(|dt| dt.naive_utc()) - .ok_or_else(|| u32::try_from(-1).unwrap_err()) + // mgclient stores a civil datetime as seconds + nanos since the epoch (interpreted as UTC). + let ts = + Timestamp::new(c_seconds, c_nanoseconds as i32).map_err(|_| MgError::InvalidTimestamp)?; + Ok(LocalDateTime(Offset::UTC.to_datetime(ts))) } fn mg_value_datetime_zone_id( c_datetime_zone_id: *const bindings::mg_date_time_zone_id, -) -> Result { +) -> 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) }; - // Create NaiveDateTime from timestamp - let naive_datetime = match Utc.timestamp_opt(c_seconds, c_nanoseconds as u32) { - chrono::LocalResult::Single(dt) => dt.naive_utc(), - _ => { - return Err(crate::error::MgError::InvalidTimestamp); - } - }; + let ts = + Timestamp::new(c_seconds, c_nanoseconds as i32).map_err(|_| MgError::InvalidTimestamp)?; - // Extract timezone name from mg_string + // Extract timezone name from mg_string, defaulting to UTC. let timezone_name = if c_timezone_name_ptr.is_null() { "UTC".to_string() } else { mg_string_to_string(c_timezone_name_ptr) }; - // Compute timezone offset from timezone name and timestamp - let time_zone_offset_seconds = timezone_name - .parse::() - .ok() - .and_then(|tz| { - // Convert UTC timestamp to the specified timezone - let utc_datetime = Utc - .timestamp_opt(c_seconds, c_nanoseconds as u32) - .single()?; - let zoned_datetime = utc_datetime.with_timezone(&tz); - Some(zoned_datetime.offset().fix().local_minus_utc()) - }) - .unwrap_or(0); // Default to 0 if timezone parsing fails - - // Extract individual date/time fields - let date = naive_datetime.date(); - let time = naive_datetime.time(); + // Resolve the instant in the named zone; fall back to UTC if the name is unknown. + let tz = TimeZone::get(&timezone_name).unwrap_or(TimeZone::UTC); + let zoned = ts.to_zoned(tz); + let dt = zoned.datetime(); Ok(DateTime { - 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, + year: dt.year() as i32, + month: dt.month() as u32, + day: dt.day() as u32, + hour: dt.hour() as u32, + minute: dt.minute() as u32, + second: dt.second() as u32, + nanosecond: dt.subsec_nanosecond() as u32, + time_zone_offset_seconds: zoned.offset().seconds(), time_zone_id: Some(timezone_name), }) } @@ -422,7 +568,10 @@ pub(crate) fn mg_value_duration(mg_value: *const bindings::mg_value) -> Duration let days = unsafe { bindings::mg_duration_days(c_duration) }; let seconds = unsafe { bindings::mg_duration_seconds(c_duration) }; let nanoseconds = unsafe { bindings::mg_duration_nanoseconds(c_duration) }; - Duration::days(days) + Duration::seconds(seconds) + Duration::nanoseconds(nanoseconds) + Duration(SignedDuration::new( + days * 86_400 + seconds, + nanoseconds as i32, + )) } pub(crate) fn mg_value_point2d(mg_value: *const bindings::mg_value) -> Point2D { @@ -608,54 +757,43 @@ pub(crate) fn hash_map_to_mg_map(hash_map: &HashMap) -> *mut mg_map } -pub(crate) fn naive_date_to_mg_date(input: &NaiveDate) -> *mut bindings::mg_date { - // Unix epoch date is a known valid date - let unix_epoch = NaiveDate::from_ymd_opt(1970, 1, 1) - .expect("Unix epoch is a valid date") - .num_days_from_ce(); +pub(crate) fn date_to_mg_date(input: &Date) -> *mut bindings::mg_date { + // mgclient stores dates as a signed day offset from the Unix epoch. + let days = input + .0 + .since(civil::date(1970, 1, 1)) + .map(|span| span.get_days() as i64) + .unwrap_or(0); // mg_date_make returns NULL on OOM, which we propagate to the caller as-is. - unsafe { bindings::mg_date_make((input.num_days_from_ce() - unix_epoch) as i64) } + unsafe { bindings::mg_date_make(days) } } -pub(crate) fn naive_local_time_to_mg_local_time(input: &NaiveTime) -> *mut bindings::mg_local_time { - let hours_ns = hours_as_seconds(input.hour() as i64) * NSEC_IN_SEC; - let minutes_ns = minutes_as_seconds(input.minute() as i64) * NSEC_IN_SEC; - let seconds_ns = (input.second() as i64) * NSEC_IN_SEC; - let nanoseconds = input.nanosecond() as i64; +pub(crate) fn local_time_to_mg_local_time(input: &LocalTime) -> *mut bindings::mg_local_time { + let t = input.0; + let total_ns = (t.hour() as i64 * 3_600 + t.minute() as i64 * 60 + t.second() as i64) + * NSEC_IN_SEC + + t.subsec_nanosecond() as i64; // mg_local_time_make returns NULL on OOM, which we propagate to the caller as-is. - unsafe { bindings::mg_local_time_make(hours_ns + minutes_ns + seconds_ns + nanoseconds) } + unsafe { bindings::mg_local_time_make(total_ns) } } -pub(crate) fn naive_local_date_time_to_mg_local_date_time( - input: &NaiveDateTime, +pub(crate) fn local_date_time_to_mg_local_date_time( + input: &LocalDateTime, ) -> *mut bindings::mg_local_date_time { - // Unix epoch date is a known valid date - let unix_epoch = NaiveDate::from_ymd_opt(1970, 1, 1) - .expect("Unix epoch is a valid date") - .num_days_from_ce(); - let days_s = days_as_seconds((input.num_days_from_ce() - unix_epoch) as i64); - let hours_s = hours_as_seconds(input.hour() as i64); - let minutes_s = minutes_as_seconds(input.minute() as i64); - let seconds_s = input.second() as i64; - let nanoseconds = input.nanosecond() as i64; + // Interpret the civil datetime as a UTC instant: seconds + nanos since the epoch. + let ts = Offset::UTC + .to_timestamp(input.0) + .unwrap_or(Timestamp::UNIX_EPOCH); // mg_local_date_time_make returns NULL on OOM, which we propagate to the caller as-is. - unsafe { - bindings::mg_local_date_time_make(days_s + hours_s + minutes_s + seconds_s, nanoseconds) - } + unsafe { bindings::mg_local_date_time_make(ts.as_second(), ts.subsec_nanosecond() as i64) } } pub(crate) fn duration_to_mg_duration(input: &Duration) -> *mut bindings::mg_duration { - // Duration returns total number of nanoseconds, in order to create a valid mg_duration object, - // days and seconds have to be reducted from the total duration. In addition, one can get numer - // of nanoseconds and then substract days and seconds, but since nanoseconds can overflow quite - // quicky (with 292 years), it's better to use Duration and first reduce days and seconds. - let mut duration = *input; - let days = input.num_days(); - duration -= Duration::days(days); - let seconds = input.num_seconds(); - duration -= Duration::seconds(seconds); - // After subtracting days and seconds, remaining nanoseconds should always fit in i64 - let nanoseconds = duration.num_nanoseconds().unwrap_or(0); + // mgclient stores durations as months/days/seconds/nanos; we only ever produce days+below. + let total_secs = input.0.as_secs(); + let days = total_secs / 86_400; + let seconds = total_secs % 86_400; + let nanoseconds = input.0.subsec_nanos() as i64; // mg_duration_make returns NULL on OOM, which we propagate to the caller as-is. unsafe { bindings::mg_duration_make(0, days, seconds, nanoseconds) } } @@ -709,19 +847,19 @@ impl Value { } bindings::mg_value_type_MG_VALUE_TYPE_DATE => { // If date conversion fails, return Null instead of panicking - mg_value_naive_date(c_mg_value) + mg_value_date(c_mg_value) .map(Value::Date) .unwrap_or(Value::Null) } bindings::mg_value_type_MG_VALUE_TYPE_LOCAL_TIME => { // If time conversion fails, return Null instead of panicking - mg_value_naive_local_time(c_mg_value) + mg_value_local_time(c_mg_value) .map(Value::LocalTime) .unwrap_or(Value::Null) } bindings::mg_value_type_MG_VALUE_TYPE_LOCAL_DATE_TIME => { // If datetime conversion fails, return Null instead of panicking - mg_value_naive_local_date_time(c_mg_value) + mg_value_local_date_time(c_mg_value) .map(Value::LocalDateTime) .unwrap_or(Value::Null) } diff --git a/src/value/tests.rs b/src/value/tests.rs index c374a01..3d1b2ea 100644 --- a/src/value/tests.rs +++ b/src/value/tests.rs @@ -72,13 +72,13 @@ fn mg_value_to_c_mg_value(mg_value: &Value) -> *mut bindings::mg_value { let c_str = CString::new(x.as_str()).unwrap(); bindings::mg_value_make_string(c_str.as_ptr()) } - Value::Date(x) => bindings::mg_value_make_date(naive_date_to_mg_date(x)), + Value::Date(x) => bindings::mg_value_make_date(date_to_mg_date(x)), Value::LocalTime(x) => { - bindings::mg_value_make_local_time(naive_local_time_to_mg_local_time(x)) + bindings::mg_value_make_local_time(local_time_to_mg_local_time(x)) + } + Value::LocalDateTime(x) => { + bindings::mg_value_make_local_date_time(local_date_time_to_mg_local_date_time(x)) } - Value::LocalDateTime(x) => bindings::mg_value_make_local_date_time( - naive_local_date_time_to_mg_local_date_time(x), - ), Value::DateTime(_x) => { // TODO: Implement conversion from DateTime to mg_value // For now, we'll create a null value as placeholder @@ -277,15 +277,7 @@ fn from_c_mg_value_date1() { let c_date = bindings::mg_date { days: 100 }; let c_mg_value = unsafe { bindings::mg_value_make_date(bindings::mg_date_copy(&c_date)) }; let mg_value = unsafe { Value::from_mg_value(c_mg_value) }; - assert_eq!( - Value::Date( - NaiveDate::from_ymd_opt(1970, 1, 1) - .unwrap() - .checked_add_signed(Duration::days(100)) - .unwrap() - ), - mg_value - ); + assert_eq!(Value::Date(Date::new(1970, 4, 11).unwrap()), mg_value); assert_eq!(format!("{}", mg_value), "'1970-04-11'"); } @@ -294,10 +286,7 @@ fn from_c_mg_value_date2() { let c_date = bindings::mg_date { days: 365 }; let c_mg_value = unsafe { bindings::mg_value_make_date(bindings::mg_date_copy(&c_date)) }; let mg_value = unsafe { Value::from_mg_value(c_mg_value) }; - assert_eq!( - Value::Date(NaiveDate::from_ymd_opt(1971, 1, 1).unwrap()), - mg_value - ); + assert_eq!(Value::Date(Date::new(1971, 1, 1).unwrap()), mg_value); assert_eq!(format!("{}", mg_value), "'1971-01-01'"); } @@ -306,10 +295,7 @@ fn from_c_mg_value_date3() { let c_date = bindings::mg_date { days: -365 }; let c_mg_value = unsafe { bindings::mg_value_make_date(bindings::mg_date_copy(&c_date)) }; let mg_value = unsafe { Value::from_mg_value(c_mg_value) }; - assert_eq!( - Value::Date(NaiveDate::from_ymd_opt(1969, 1, 1).unwrap()), - mg_value - ); + assert_eq!(Value::Date(Date::new(1969, 1, 1).unwrap()), mg_value); assert_eq!(format!("{}", mg_value), "'1969-01-01'"); } @@ -322,7 +308,7 @@ fn from_c_mg_value_local_time() { unsafe { bindings::mg_value_make_local_time(bindings::mg_local_time_copy(&c_local_time)) }; let mg_value = unsafe { Value::from_mg_value(c_mg_value) }; assert_eq!( - Value::LocalTime(NaiveTime::from_hms_micro_opt(14, 40, 35, 851241).unwrap()), + Value::LocalTime(LocalTime::new(14, 40, 35, 851_241_000).unwrap()), mg_value ); assert_eq!(format!("{}", mg_value), "'14:40:35.851241'"); @@ -341,12 +327,7 @@ fn from_c_mg_value_local_date_time1() { }; let mg_value = unsafe { Value::from_mg_value(c_mg_value) }; assert_eq!( - Value::LocalDateTime( - NaiveDate::from_ymd_opt(1971, 5, 16) - .unwrap() - .and_hms_micro_opt(14, 40, 35, 851241) - .unwrap() - ), + Value::LocalDateTime(LocalDateTime::new(1971, 5, 16, 14, 40, 35, 851_241_000).unwrap()), mg_value ); assert_eq!(format!("{}", mg_value), "'1971-05-16 14:40:35.851241'"); @@ -365,12 +346,7 @@ fn from_c_mg_value_local_date_time2() { }; let mg_value = unsafe { Value::from_mg_value(c_mg_value) }; assert_eq!( - Value::LocalDateTime( - NaiveDate::from_ymd_opt(1968, 8, 19) - .unwrap() - .and_hms_micro_opt(14, 40, 35, 851241) - .unwrap() - ), + Value::LocalDateTime(LocalDateTime::new(1968, 8, 19, 14, 40, 35, 851_241_000).unwrap()), mg_value ); assert_eq!(format!("{}", mg_value), "'1968-08-19 14:40:35.851241'"); @@ -389,12 +365,7 @@ fn from_c_mg_value_local_date_time3() { }; let mg_value = unsafe { Value::from_mg_value(c_mg_value) }; assert_eq!( - Value::LocalDateTime( - NaiveDate::from_ymd_opt(1969, 12, 31) - .unwrap() - .and_hms_micro_opt(23, 59, 59, 0) - .unwrap() - ), + Value::LocalDateTime(LocalDateTime::new(1969, 12, 31, 23, 59, 59, 0).unwrap()), mg_value ); assert_eq!(format!("{}", mg_value), "'1969-12-31 23:59:59'"); @@ -852,7 +823,7 @@ fn from_to_c_mg_value_string() { #[test] fn from_naive_date_param_to_mg_value() { - let query_param = QueryParam::Date(NaiveDate::from_ymd_opt(1971, 1, 1).unwrap()); + let query_param = QueryParam::Date(Date::new(1971, 1, 1).unwrap()); let c_mg_value = unsafe { *(query_param.to_c_mg_value()) }; assert_eq!(c_mg_value.type_, bindings::mg_value_type_MG_VALUE_TYPE_DATE); let mg_value = unsafe { Value::from_mg_value(&c_mg_value) }; @@ -871,7 +842,7 @@ fn from_naive_date_param_to_mg_value() { #[test] fn from_naive_local_time_param_to_mg_value() { - let query_param = QueryParam::LocalTime(NaiveTime::from_hms_nano_opt(2, 3, 4, 1234).unwrap()); + let query_param = QueryParam::LocalTime(LocalTime::new(2, 3, 4, 1234).unwrap()); let c_mg_value = unsafe { *(query_param.to_c_mg_value()) }; assert_eq!( c_mg_value.type_, @@ -894,12 +865,8 @@ fn from_naive_local_time_param_to_mg_value() { #[test] fn from_naive_local_date_time_param_to_mg_value() { - let query_param = QueryParam::LocalDateTime( - NaiveDate::from_ymd_opt(1960, 1, 1) - .unwrap() - .and_hms_nano_opt(2, 3, 4, 1234) - .unwrap(), - ); + let query_param = + QueryParam::LocalDateTime(LocalDateTime::new(1960, 1, 1, 2, 3, 4, 1234).unwrap()); let c_mg_value = unsafe { *(query_param.to_c_mg_value()) }; assert_eq!( c_mg_value.type_, @@ -939,7 +906,7 @@ fn from_duration_to_mg_value_1() { assert_eq!(x.num_hours(), 24); assert_eq!(x.num_days(), 1); assert_eq!(x.num_seconds(), 86403); - assert_eq!(x.num_nanoseconds().unwrap(), 86403000000000); + assert_eq!(x.num_nanoseconds(), 86403000000000); } _ => { panic!("QueryParam::Duration converted into a wrong Value type!"); @@ -963,7 +930,7 @@ fn from_duration_to_mg_value_2() { assert_eq!(x.num_hours(), 0); assert_eq!(x.num_days(), 0); assert_eq!(x.num_seconds(), 0); - assert_eq!(x.num_nanoseconds().unwrap(), 123456789); + assert_eq!(x.num_nanoseconds(), 123456789); } _ => { panic!("QueryParam::Duration converted into a wrong Value type!");