gstreamer/datetime: Check invariants on the bindings side instead of asserting in the C code

Newer versions of GStreamer (1.20 and above) will not assert any longer
but handle it more gracefully, so let's do the same here for all
versions.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/297
This commit is contained in:
Sebastian Dröge 2020-12-06 12:29:12 +02:00
parent 584a87163f
commit 15722ec5d2
4 changed files with 437 additions and 156 deletions

View file

@ -1654,9 +1654,63 @@ status = "generate"
[[object.function]] [[object.function]]
name = "new" name = "new"
[object.function.return] # Needs manual checking of invariants
nullable = true manual = true
nullable_return_is_error = "Can't create DateTime"
[[object.function]]
name = "new_local_time"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "new_y"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "new_ym"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "new_ymd"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "get_month"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "get_day"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "get_hour"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "get_minute"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "get_second"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "get_microsecond"
# Needs manual checking of invariants
manual = true
[[object.function]]
name = "get_time_zone_offset"
# Needs manual checking of invariants
manual = true
[[object.function]] [[object.function]]
name = "new_y" name = "new_y"
@ -1696,6 +1750,26 @@ status = "generate"
[object.function.return] [object.function.return]
nullable_return_is_error = "Failed to create ISO-8601 string from DateTime" nullable_return_is_error = "Failed to create ISO-8601 string from DateTime"
[[object.function]]
name = "new_from_unix_epoch_local_time"
[object.function.return]
nullable_return_is_error = "Can't create DateTime from UNIX epoch"
[[object.function]]
name = "new_from_unix_epoch_local_time_usecs"
[object.function.return]
nullable_return_is_error = "Can't create DateTime from UNIX epoch"
[[object.function]]
name = "new_from_unix_epoch_utc"
[object.function.return]
nullable_return_is_error = "Can't create DateTime from UNIX epoch"
[[object.function]]
name = "new_from_unix_epoch_utc_usecs"
[object.function.return]
nullable_return_is_error = "Can't create DateTime from UNIX epoch"
[[object]] [[object]]
name = "Gst.ControlSource" name = "Gst.ControlSource"
status = "generate" status = "generate"

View file

@ -16,24 +16,6 @@ glib::glib_wrapper! {
} }
impl DateTime { impl DateTime {
pub fn new(
tzoffset: f32,
year: i32,
month: i32,
day: i32,
hour: i32,
minute: i32,
seconds: f64,
) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new(
tzoffset, year, month, day, hour, minute, seconds,
))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime"))
}
}
pub fn from_g_date_time(dt: &glib::DateTime) -> Result<DateTime, glib::BoolError> { pub fn from_g_date_time(dt: &glib::DateTime) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!(); assert_initialized_main_thread!();
unsafe { unsafe {
@ -52,47 +34,41 @@ impl DateTime {
} }
} }
pub fn from_unix_epoch_local_time(secs: i64) -> Option<DateTime> { pub fn from_unix_epoch_local_time(secs: i64) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
unsafe { from_glib_full(ffi::gst_date_time_new_from_unix_epoch_local_time(secs)) }
}
#[cfg(any(feature = "v1_18", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))]
pub fn from_unix_epoch_local_time_usecs(usecs: i64) -> Option<DateTime> {
assert_initialized_main_thread!(); assert_initialized_main_thread!();
unsafe { unsafe {
from_glib_full(ffi::gst_date_time_new_from_unix_epoch_local_time_usecs( Option::<_>::from_glib_full(ffi::gst_date_time_new_from_unix_epoch_local_time(secs))
usecs, .ok_or_else(|| glib::glib_bool_error!("Can't create DateTime from UNIX epoch"))
))
} }
} }
pub fn from_unix_epoch_utc(secs: i64) -> Option<DateTime> { #[cfg(any(feature = "v1_18", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))]
pub fn from_unix_epoch_local_time_usecs(usecs: i64) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!(); assert_initialized_main_thread!();
unsafe { from_glib_full(ffi::gst_date_time_new_from_unix_epoch_utc(secs)) } unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new_from_unix_epoch_local_time_usecs(
usecs,
))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime from UNIX epoch"))
}
}
pub fn from_unix_epoch_utc(secs: i64) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new_from_unix_epoch_utc(secs))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime from UNIX epoch"))
}
} }
#[cfg(any(feature = "v1_18", feature = "dox"))] #[cfg(any(feature = "v1_18", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))]
pub fn from_unix_epoch_utc_usecs(usecs: i64) -> Option<DateTime> { pub fn from_unix_epoch_utc_usecs(usecs: i64) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
unsafe { from_glib_full(ffi::gst_date_time_new_from_unix_epoch_utc_usecs(usecs)) }
}
pub fn new_local_time(
year: i32,
month: i32,
day: i32,
hour: i32,
minute: i32,
seconds: f64,
) -> Option<DateTime> {
assert_initialized_main_thread!(); assert_initialized_main_thread!();
unsafe { unsafe {
from_glib_full(ffi::gst_date_time_new_local_time( Option::<_>::from_glib_full(ffi::gst_date_time_new_from_unix_epoch_utc_usecs(usecs))
year, month, day, hour, minute, seconds, .ok_or_else(|| glib::glib_bool_error!("Can't create DateTime from UNIX epoch"))
))
} }
} }
@ -106,58 +82,6 @@ impl DateTime {
unsafe { from_glib_full(ffi::gst_date_time_new_now_utc()) } unsafe { from_glib_full(ffi::gst_date_time_new_now_utc()) }
} }
pub fn new_y(year: i32) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new_y(year))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime"))
}
}
pub fn new_ym(year: i32, month: i32) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new_ym(year, month))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime"))
}
}
pub fn new_ymd(year: i32, month: i32, day: i32) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new_ymd(year, month, day))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime"))
}
}
pub fn get_day(&self) -> i32 {
unsafe { ffi::gst_date_time_get_day(self.to_glib_none().0) }
}
pub fn get_hour(&self) -> i32 {
unsafe { ffi::gst_date_time_get_hour(self.to_glib_none().0) }
}
pub fn get_microsecond(&self) -> i32 {
unsafe { ffi::gst_date_time_get_microsecond(self.to_glib_none().0) }
}
pub fn get_minute(&self) -> i32 {
unsafe { ffi::gst_date_time_get_minute(self.to_glib_none().0) }
}
pub fn get_month(&self) -> i32 {
unsafe { ffi::gst_date_time_get_month(self.to_glib_none().0) }
}
pub fn get_second(&self) -> i32 {
unsafe { ffi::gst_date_time_get_second(self.to_glib_none().0) }
}
pub fn get_time_zone_offset(&self) -> f32 {
unsafe { ffi::gst_date_time_get_time_zone_offset(self.to_glib_none().0) }
}
pub fn get_year(&self) -> i32 { pub fn get_year(&self) -> i32 {
unsafe { ffi::gst_date_time_get_year(self.to_glib_none().0) } unsafe { ffi::gst_date_time_get_year(self.to_glib_none().0) }
} }

View file

@ -6,13 +6,291 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use glib::translate::*;
use std::cmp; use std::cmp;
use std::convert; use std::convert;
use std::fmt; use std::fmt;
use crate::DateTime; use crate::DateTime;
// Validate that the given values result in a valid DateTime
fn validate(
tzoffset: Option<f32>,
year: i32,
month: Option<i32>,
day: Option<i32>,
hour: Option<i32>,
minute: Option<i32>,
seconds: Option<f64>,
) -> Result<(), glib::BoolError> {
skip_assert_initialized!();
// Check for valid ranges
if year <= 0 || year > 9999 {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Year out of range"
));
}
if let Some(month) = month {
if month <= 0 || month > 12 {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Month out of range"
));
}
}
if let Some(day) = day {
if day <= 0 || day > 31 {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Day out of range"
));
}
}
if let Some(hour) = hour {
if hour < 0 || hour >= 24 {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Hour out of range"
));
}
}
if let Some(minute) = minute {
if minute < 0 || minute >= 60 {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Minute out of range"
));
}
}
if let Some(seconds) = seconds {
if seconds < 0.0 || seconds >= 60.0 {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Seconds out of range"
));
}
}
if let Some(tzoffset) = tzoffset {
if tzoffset < -12.0 || tzoffset > 12.0 {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Timezone offset out of range"
));
}
}
// If day is provided, month also has to be provided
if day.is_some() && month.is_none() {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Need to provide month if providing day"
));
}
// If hour is provided, day also has to be provided
if hour.is_some() && day.is_none() {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Need to provide day if providing hour"
));
}
// If minutes are provided, hours also need to be provided and the other way around
if hour.is_none() && minute.is_some() {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Need to provide both hour and minute or neither"
));
}
if minute.is_some() && hour.is_none() {
return Err(glib::glib_bool_error!(
"Can't create DateTime: Need to provide both hour and minute or neither"
));
}
// If seconds or tzoffset are provided then also hours and minutes must be provided
if (seconds.is_some() || tzoffset.is_some()) && (hour.is_none() || minute.is_none()) {
return Err(glib::glib_bool_error!("Can't create DateTime: Need to provide hour and minute if providing seconds or timezone offset"));
}
Ok(())
}
impl DateTime { impl DateTime {
pub fn new<
TZ: Into<Option<f32>>,
Y: Into<i32>,
MO: Into<Option<i32>>,
D: Into<Option<i32>>,
H: Into<Option<i32>>,
MI: Into<Option<i32>>,
S: Into<Option<f64>>,
>(
tzoffset: TZ,
year: Y,
month: MO,
day: D,
hour: H,
minute: MI,
seconds: S,
) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
let tzoffset = tzoffset.into();
let year = year.into();
let month = month.into();
let day = day.into();
let hour = hour.into();
let minute = minute.into();
let seconds = seconds.into();
validate(tzoffset, year, month, day, hour, minute, seconds)?;
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new(
tzoffset.unwrap_or(0.0),
year,
month.unwrap_or(-1),
day.unwrap_or(-1),
hour.unwrap_or(-1),
minute.unwrap_or(-1),
seconds.unwrap_or(-1.0),
))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime"))
}
}
pub fn new_local_time<
Y: Into<i32>,
MO: Into<Option<i32>>,
D: Into<Option<i32>>,
H: Into<Option<i32>>,
MI: Into<Option<i32>>,
S: Into<Option<f64>>,
>(
year: Y,
month: MO,
day: D,
hour: H,
minute: MI,
seconds: S,
) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
let year = year.into();
let month = month.into();
let day = day.into();
let hour = hour.into();
let minute = minute.into();
let seconds = seconds.into();
validate(None, year, month, day, hour, minute, seconds)?;
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new_local_time(
year,
month.unwrap_or(-1),
day.unwrap_or(-1),
hour.unwrap_or(-1),
minute.unwrap_or(-1),
seconds.unwrap_or(-1.0),
))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime"))
}
}
pub fn new_y(year: i32) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
validate(None, year, None, None, None, None, None)?;
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new_y(year))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime"))
}
}
pub fn new_ym(year: i32, month: i32) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
validate(None, year, Some(month), None, None, None, None)?;
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new_ym(year, month))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime"))
}
}
pub fn new_ymd(year: i32, month: i32, day: i32) -> Result<DateTime, glib::BoolError> {
assert_initialized_main_thread!();
validate(None, year, Some(month), Some(day), None, None, None)?;
unsafe {
Option::<_>::from_glib_full(ffi::gst_date_time_new_ymd(year, month, day))
.ok_or_else(|| glib::glib_bool_error!("Can't create DateTime"))
}
}
pub fn get_day(&self) -> Option<i32> {
if !self.has_day() {
return None;
}
unsafe { Some(ffi::gst_date_time_get_day(self.to_glib_none().0)) }
}
pub fn get_hour(&self) -> Option<i32> {
if !self.has_time() {
return None;
}
unsafe { Some(ffi::gst_date_time_get_hour(self.to_glib_none().0)) }
}
pub fn get_microsecond(&self) -> Option<i32> {
if !self.has_second() {
return None;
}
unsafe { Some(ffi::gst_date_time_get_microsecond(self.to_glib_none().0)) }
}
pub fn get_minute(&self) -> Option<i32> {
if !self.has_time() {
return None;
}
unsafe { Some(ffi::gst_date_time_get_minute(self.to_glib_none().0)) }
}
pub fn get_month(&self) -> Option<i32> {
if !self.has_month() {
return None;
}
unsafe { Some(ffi::gst_date_time_get_month(self.to_glib_none().0)) }
}
pub fn get_second(&self) -> Option<i32> {
if !self.has_second() {
return None;
}
unsafe { Some(ffi::gst_date_time_get_second(self.to_glib_none().0)) }
}
pub fn get_time_zone_offset(&self) -> Option<f32> {
if !self.has_time() {
return None;
}
unsafe {
Some(ffi::gst_date_time_get_time_zone_offset(
self.to_glib_none().0,
))
}
}
pub fn to_utc(&self) -> Result<DateTime, glib::BoolError> { pub fn to_utc(&self) -> Result<DateTime, glib::BoolError> {
if !self.has_time() { if !self.has_time() {
// No time => no TZ offset // No time => no TZ offset
@ -43,7 +321,7 @@ impl DateTime {
self.get_day(), self.get_day(),
self.get_hour(), self.get_hour(),
self.get_minute(), self.get_minute(),
0f64, Some(0.0),
) )
.and_then(|d| d.to_g_date_time()) .and_then(|d| d.to_g_date_time())
.and_then(|d| { .and_then(|d| {
@ -52,13 +330,13 @@ impl DateTime {
}) })
.and_then(|d| { .and_then(|d| {
DateTime::new( DateTime::new(
0f32, // UTC TZ offset None, // UTC TZ offset
d.get_year(), d.get_year(),
d.get_month(), Some(d.get_month()),
d.get_day_of_month(), Some(d.get_day_of_month()),
d.get_hour(), Some(d.get_hour()),
d.get_minute(), Some(d.get_minute()),
-1f64, // No second None, // No second
) )
}) })
} }
@ -121,7 +399,7 @@ impl cmp::PartialOrd for DateTime {
return None; return None;
} }
let month_delta = self_norm.get_month() - other_norm.get_month(); let month_delta = self_norm.get_month().unwrap() - other_norm.get_month().unwrap();
if month_delta != 0 { if month_delta != 0 {
return get_cmp(month_delta); return get_cmp(month_delta);
} }
@ -138,7 +416,7 @@ impl cmp::PartialOrd for DateTime {
return None; return None;
} }
let day_delta = self_norm.get_day() - other_norm.get_day(); let day_delta = self_norm.get_day().unwrap() - other_norm.get_day().unwrap();
if day_delta != 0 { if day_delta != 0 {
return get_cmp(day_delta); return get_cmp(day_delta);
} }
@ -155,12 +433,12 @@ impl cmp::PartialOrd for DateTime {
return None; return None;
} }
let hour_delta = self_norm.get_hour() - other_norm.get_hour(); let hour_delta = self_norm.get_hour().unwrap() - other_norm.get_hour().unwrap();
if hour_delta != 0 { if hour_delta != 0 {
return get_cmp(hour_delta); return get_cmp(hour_delta);
} }
let minute_delta = self_norm.get_minute() - other_norm.get_minute(); let minute_delta = self_norm.get_minute().unwrap() - other_norm.get_minute().unwrap();
if minute_delta != 0 { if minute_delta != 0 {
return get_cmp(minute_delta); return get_cmp(minute_delta);
} }
@ -176,12 +454,12 @@ impl cmp::PartialOrd for DateTime {
// One has second, the other doesn't => can't compare (note 1) // One has second, the other doesn't => can't compare (note 1)
return None; return None;
} }
let second_delta = self_norm.get_second() - other_norm.get_second(); let second_delta = self_norm.get_second().unwrap() - other_norm.get_second().unwrap();
if second_delta != 0 { if second_delta != 0 {
return get_cmp(second_delta); return get_cmp(second_delta);
} }
get_cmp(self_norm.get_microsecond() - other_norm.get_microsecond()) get_cmp(self_norm.get_microsecond().unwrap() - other_norm.get_microsecond().unwrap())
} }
} }
@ -281,12 +559,12 @@ mod tests {
.to_utc() .to_utc()
.unwrap(); .unwrap();
assert_eq!(utc_date_time.get_year(), 2019); assert_eq!(utc_date_time.get_year(), 2019);
assert_eq!(utc_date_time.get_month(), 8); assert_eq!(utc_date_time.get_month().unwrap(), 8);
assert_eq!(utc_date_time.get_day(), 20); assert_eq!(utc_date_time.get_day().unwrap(), 20);
assert_eq!(utc_date_time.get_hour(), 18); assert_eq!(utc_date_time.get_hour().unwrap(), 18);
assert_eq!(utc_date_time.get_minute(), 9); assert_eq!(utc_date_time.get_minute().unwrap(), 9);
assert_eq!(utc_date_time.get_second(), 42); assert_eq!(utc_date_time.get_second().unwrap(), 42);
assert_eq!(utc_date_time.get_microsecond(), 123_456); assert_eq!(utc_date_time.get_microsecond().unwrap(), 123_456);
// Year, month, day and hour offset // Year, month, day and hour offset
let utc_date_time = DateTime::new(2f32, 2019, 1, 1, 0, 0, 42.123_456f64) let utc_date_time = DateTime::new(2f32, 2019, 1, 1, 0, 0, 42.123_456f64)
@ -294,31 +572,31 @@ mod tests {
.to_utc() .to_utc()
.unwrap(); .unwrap();
assert_eq!(utc_date_time.get_year(), 2018); assert_eq!(utc_date_time.get_year(), 2018);
assert_eq!(utc_date_time.get_month(), 12); assert_eq!(utc_date_time.get_month().unwrap(), 12);
assert_eq!(utc_date_time.get_day(), 31); assert_eq!(utc_date_time.get_day().unwrap(), 31);
assert_eq!(utc_date_time.get_hour(), 22); assert_eq!(utc_date_time.get_hour().unwrap(), 22);
assert_eq!(utc_date_time.get_minute(), 0); assert_eq!(utc_date_time.get_minute().unwrap(), 0);
assert_eq!(utc_date_time.get_second(), 42); assert_eq!(utc_date_time.get_second().unwrap(), 42);
assert_eq!(utc_date_time.get_microsecond(), 123_456); assert_eq!(utc_date_time.get_microsecond().unwrap(), 123_456);
// Date without an hour (which implies no TZ) // Date without an hour (which implies no TZ)
let utc_date_time = DateTime::new_ymd(2019, 1, 1).unwrap().to_utc().unwrap(); let utc_date_time = DateTime::new_ymd(2019, 1, 1).unwrap().to_utc().unwrap();
assert_eq!(utc_date_time.get_year(), 2019); assert_eq!(utc_date_time.get_year(), 2019);
assert_eq!(utc_date_time.get_month(), 1); assert_eq!(utc_date_time.get_month().unwrap(), 1);
assert_eq!(utc_date_time.get_day(), 1); assert_eq!(utc_date_time.get_day().unwrap(), 1);
assert!(!utc_date_time.has_time()); assert!(!utc_date_time.has_time());
assert!(!utc_date_time.has_second()); assert!(!utc_date_time.has_second());
// Date without seconds // Date without seconds
let utc_date_time = DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64) let utc_date_time = DateTime::new(2f32, 2018, 5, 28, 16, 6, None)
.unwrap() .unwrap()
.to_utc() .to_utc()
.unwrap(); .unwrap();
assert_eq!(utc_date_time.get_year(), 2018); assert_eq!(utc_date_time.get_year(), 2018);
assert_eq!(utc_date_time.get_month(), 5); assert_eq!(utc_date_time.get_month().unwrap(), 5);
assert_eq!(utc_date_time.get_day(), 28); assert_eq!(utc_date_time.get_day().unwrap(), 28);
assert_eq!(utc_date_time.get_hour(), 14); assert_eq!(utc_date_time.get_hour().unwrap(), 14);
assert_eq!(utc_date_time.get_minute(), 6); assert_eq!(utc_date_time.get_minute().unwrap(), 6);
assert!(!utc_date_time.has_second()); assert!(!utc_date_time.has_second());
} }
@ -442,8 +720,8 @@ mod tests {
); );
assert_eq!( assert_eq!(
DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64).unwrap(), DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap(),
DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64).unwrap() DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap()
); );
assert_eq!( assert_eq!(
@ -456,16 +734,16 @@ mod tests {
// but they are not equal (note 1) // but they are not equal (note 1)
assert_ne!( assert_ne!(
DateTime::new_ymd(2018, 5, 28).unwrap(), DateTime::new_ymd(2018, 5, 28).unwrap(),
DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64).unwrap() DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap()
); );
assert_ne!( assert_ne!(
DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64).unwrap(), DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap(),
DateTime::new_ym(2018, 5).unwrap() DateTime::new_ym(2018, 5).unwrap()
); );
assert_ne!( assert_ne!(
DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64).unwrap(), DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap(),
DateTime::new_y(2018).unwrap() DateTime::new_y(2018).unwrap()
); );
} }

View file

@ -73,26 +73,31 @@ impl<'a> Serialize for DateTime {
let variant = if self.has_second() { let variant = if self.has_second() {
DateTimeVariants::YMDhmsTz( DateTimeVariants::YMDhmsTz(
self.get_year(), self.get_year(),
self.get_month(), self.get_month().unwrap(),
self.get_day(), self.get_day().unwrap(),
self.get_hour(), self.get_hour().unwrap(),
self.get_minute(), self.get_minute().unwrap(),
f64::from(self.get_second()) + f64::from(self.get_microsecond()) / 1_000_000f64, f64::from(self.get_second().unwrap())
self.get_time_zone_offset(), + f64::from(self.get_microsecond().unwrap()) / 1_000_000f64,
self.get_time_zone_offset().unwrap(),
) )
} else if self.has_time() { } else if self.has_time() {
DateTimeVariants::YMDhmTz( DateTimeVariants::YMDhmTz(
self.get_year(), self.get_year(),
self.get_month(), self.get_month().unwrap(),
self.get_day(), self.get_day().unwrap(),
self.get_hour(), self.get_hour().unwrap(),
self.get_minute(), self.get_minute().unwrap(),
self.get_time_zone_offset(), self.get_time_zone_offset().unwrap(),
) )
} else if self.has_day() { } else if self.has_day() {
DateTimeVariants::YMD(self.get_year(), self.get_month(), self.get_day()) DateTimeVariants::YMD(
self.get_year(),
self.get_month().unwrap(),
self.get_day().unwrap(),
)
} else if self.has_month() { } else if self.has_month() {
DateTimeVariants::YM(self.get_year(), self.get_month()) DateTimeVariants::YM(self.get_year(), self.get_month().unwrap())
} else if self.has_year() { } else if self.has_year() {
DateTimeVariants::Y(self.get_year()) DateTimeVariants::Y(self.get_year())
} else { } else {
@ -152,7 +157,7 @@ impl TryFrom<DateTimeVariants> for DateTime {
DateTimeVariants::YM(y, m) => DateTime::new_ym(y, m), DateTimeVariants::YM(y, m) => DateTime::new_ym(y, m),
DateTimeVariants::YMD(y, m, d) => DateTime::new_ymd(y, m, d), DateTimeVariants::YMD(y, m, d) => DateTime::new_ymd(y, m, d),
DateTimeVariants::YMDhmTz(y, m, d, h, mn, tz) => { DateTimeVariants::YMDhmTz(y, m, d, h, mn, tz) => {
DateTime::new(tz, y, m, d, h, mn, -1f64) DateTime::new(tz, y, m, d, h, mn, None)
} }
DateTimeVariants::YMDhmsTz(y, m, d, h, mn, s, tz) => { DateTimeVariants::YMDhmsTz(y, m, d, h, mn, s, tz) => {
DateTime::new(tz, y, m, d, h, mn, s) DateTime::new(tz, y, m, d, h, mn, s)
@ -193,7 +198,7 @@ mod tests {
res res
); );
let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64).unwrap(); let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap();
let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone()); let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone());
assert_eq!(Ok("YMDhmTz(2018, 5, 28, 16, 6, 2)".to_owned()), res,); assert_eq!(Ok("YMDhmTz(2018, 5, 28, 16, 6, 2)".to_owned()), res,);
@ -232,7 +237,7 @@ mod tests {
let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap();
assert_eq!( assert_eq!(
datetime_de, datetime_de,
DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64).unwrap() DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap()
); );
let datetime_ron = "YMD(2018, 5, 28)"; let datetime_ron = "YMD(2018, 5, 28)";
@ -257,7 +262,7 @@ mod tests {
let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap();
assert_eq!(datetime_de, datetime); assert_eq!(datetime_de, datetime);
let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64).unwrap(); let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap();
let datetime_ser = ron::ser::to_string(&datetime).unwrap(); let datetime_ser = ron::ser::to_string(&datetime).unwrap();
let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap();
assert_eq!(datetime_de, datetime); assert_eq!(datetime_de, datetime);