Skip to content

Commit

Permalink
Make NaiveDate::and_hms* return Result
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Feb 11, 2024
1 parent c7e0ade commit fe8a655
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 60 deletions.
14 changes: 7 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,20 +129,20 @@
//! # fn doctest() -> Option<()> {
//!
//! let dt = Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap(); // `2014-07-08T09:10:11Z`
//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_opt(9, 10, 11)?.and_local_timezone(Utc).unwrap());
//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_opt(9, 10, 11).unwrap().and_local_timezone(Utc).unwrap());
//!
//! // July 8 is 188th day of the year 2014 (`o` for "ordinal")
//! assert_eq!(dt, NaiveDate::from_yo_opt(2014, 189)?.and_hms_opt(9, 10, 11)?.and_utc());
//! assert_eq!(dt, NaiveDate::from_yo_opt(2014, 189)?.and_hms_opt(9, 10, 11).unwrap().and_utc());
//! // July 8 is Tuesday in ISO week 28 of the year 2014.
//! assert_eq!(dt, NaiveDate::from_isoywd_opt(2014, 28, Weekday::Tue)?.and_hms_opt(9, 10, 11)?.and_utc());
//! assert_eq!(dt, NaiveDate::from_isoywd_opt(2014, 28, Weekday::Tue)?.and_hms_opt(9, 10, 11).unwrap().and_utc());
//!
//! let dt = NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_milli_opt(9, 10, 11, 12)?.and_local_timezone(Utc).unwrap(); // `2014-07-08T09:10:11.012Z`
//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_micro_opt(9, 10, 11, 12_000)?.and_local_timezone(Utc).unwrap());
//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_nano_opt(9, 10, 11, 12_000_000)?.and_local_timezone(Utc).unwrap());
//! let dt = NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_milli_opt(9, 10, 11, 12).unwrap().and_local_timezone(Utc).unwrap(); // `2014-07-08T09:10:11.012Z`
//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_micro_opt(9, 10, 11, 12_000).unwrap().and_local_timezone(Utc).unwrap());
//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_nano_opt(9, 10, 11, 12_000_000).unwrap().and_local_timezone(Utc).unwrap());
//!
//! // dynamic verification
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33),
//! LocalResult::Single(NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_opt(21, 15, 33)?.and_utc()));
//! LocalResult::Single(NaiveDate::from_ymd_opt(2014, 7, 8)?.and_hms_opt(21, 15, 33).unwrap().and_utc()));
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 80, 15, 33), LocalResult::None);
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 38, 21, 15, 33), LocalResult::None);
//!
Expand Down
101 changes: 53 additions & 48 deletions src/naive/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use crate::format::{
};
use crate::month::Months;
use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime};
use crate::{expect, ok, try_opt};
use crate::{Datelike, TimeDelta, Weekday};
use crate::{expect, try_err, try_opt};
use crate::{Datelike, Error, TimeDelta, Weekday};

use super::internals::{self, DateImpl, Mdf, Of, YearFlags};
use super::isoweek;
Expand Down Expand Up @@ -752,24 +752,23 @@ impl NaiveDate {
///
/// # Errors
///
/// Returns `None` on invalid hour, minute and/or second.
/// Returns [`Error::InvalidArgument`] on invalid hour, minute and/or second.
///
/// # Example
///
/// ```
/// use chrono::NaiveDate;
/// use chrono::{Error, NaiveDate};
///
/// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
/// assert!(d.and_hms_opt(12, 34, 56).is_some());
/// assert!(d.and_hms_opt(12, 34, 60).is_none()); // use `and_hms_milli_opt` instead
/// assert!(d.and_hms_opt(12, 60, 56).is_none());
/// assert!(d.and_hms_opt(24, 34, 56).is_none());
/// assert!(d.and_hms_opt(12, 34, 56).is_ok());
/// assert_eq!(d.and_hms_opt(12, 34, 60), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_opt(12, 60, 56), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_opt(24, 34, 56), Err(Error::InvalidArgument));
/// ```
#[inline]
#[must_use]
pub const fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<NaiveDateTime> {
let time = try_opt!(ok!(NaiveTime::from_hms(hour, min, sec)));
Some(self.and_time(time))
pub const fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Result<NaiveDateTime, Error> {
let time = try_err!(NaiveTime::from_hms(hour, min, sec));
Ok(self.and_time(time))
}

/// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond.
Expand All @@ -779,32 +778,34 @@ impl NaiveDate {
///
/// # Errors
///
/// Returns `None` on invalid hour, minute, second and/or millisecond.
/// Returns [`Error::InvalidArgument`] on invalid hour, minute, second and/or millisecond.
///
/// Returns [`Error::DoesNotExist`] if the millisecond part to represent a leap second is not on
/// a minute boundary.
///
/// # Example
///
/// ```
/// use chrono::NaiveDate;
/// use chrono::{Error, NaiveDate};
///
/// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
/// assert!(d.and_hms_milli_opt(12, 34, 56, 789).is_some());
/// assert!(d.and_hms_milli_opt(12, 34, 59, 1_789).is_some()); // leap second
/// assert!(d.and_hms_milli_opt(12, 34, 59, 2_789).is_none());
/// assert!(d.and_hms_milli_opt(12, 34, 60, 789).is_none());
/// assert!(d.and_hms_milli_opt(12, 60, 56, 789).is_none());
/// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none());
/// assert!(d.and_hms_milli_opt(12, 34, 56, 789).is_ok());
/// assert!(d.and_hms_milli_opt(12, 34, 59, 1_789).is_ok()); // leap second
/// assert_eq!(d.and_hms_milli_opt(12, 34, 59, 2_789), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_milli_opt(12, 34, 60, 789), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_milli_opt(12, 60, 56, 789), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_milli_opt(24, 34, 56, 789), Err(Error::InvalidArgument));
/// ```
#[inline]
#[must_use]
pub const fn and_hms_milli_opt(
&self,
hour: u32,
min: u32,
sec: u32,
milli: u32,
) -> Option<NaiveDateTime> {
let time = try_opt!(ok!(NaiveTime::from_hms_milli(hour, min, sec, milli)));
Some(self.and_time(time))
) -> Result<NaiveDateTime, Error> {
let time = try_err!(NaiveTime::from_hms_milli(hour, min, sec, milli));
Ok(self.and_time(time))
}

/// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond.
Expand All @@ -814,32 +815,34 @@ impl NaiveDate {
///
/// # Errors
///
/// Returns `None` on invalid hour, minute, second and/or microsecond.
/// Returns [`Error::InvalidArgument`] on invalid hour, minute, second and/or microsecond.
///
/// Returns [`Error::DoesNotExist`] if the microsecond part to represent a leap second is not on
/// a minute boundary.
///
/// # Example
///
/// ```
/// use chrono::NaiveDate;
/// use chrono::{Error, NaiveDate};
///
/// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
/// assert!(d.and_hms_micro_opt(12, 34, 56, 789_012).is_some());
/// assert!(d.and_hms_micro_opt(12, 34, 59, 1_789_012).is_some()); // leap second
/// assert!(d.and_hms_micro_opt(12, 34, 59, 2_789_012).is_none());
/// assert!(d.and_hms_micro_opt(12, 34, 60, 789_012).is_none());
/// assert!(d.and_hms_micro_opt(12, 60, 56, 789_012).is_none());
/// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none());
/// assert!(d.and_hms_micro_opt(12, 34, 56, 789_012).is_ok());
/// assert!(d.and_hms_micro_opt(12, 34, 59, 1_789_012).is_ok()); // leap second
/// assert_eq!(d.and_hms_micro_opt(12, 34, 59, 2_789_012), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_micro_opt(12, 34, 60, 789_012), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_micro_opt(12, 60, 56, 789_012), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_micro_opt(24, 34, 56, 789_012), Err(Error::InvalidArgument));
/// ```
#[inline]
#[must_use]
pub const fn and_hms_micro_opt(
&self,
hour: u32,
min: u32,
sec: u32,
micro: u32,
) -> Option<NaiveDateTime> {
let time = try_opt!(ok!(NaiveTime::from_hms_micro(hour, min, sec, micro)));
Some(self.and_time(time))
) -> Result<NaiveDateTime, Error> {
let time = try_err!(NaiveTime::from_hms_micro(hour, min, sec, micro));
Ok(self.and_time(time))
}

/// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond.
Expand All @@ -849,32 +852,34 @@ impl NaiveDate {
///
/// # Errors
///
/// Returns `None` on invalid hour, minute, second and/or nanosecond.
/// Returns [`Error::InvalidArgument`] on invalid hour, minute, second and/or nanosecond.
///
/// Returns [`Error::DoesNotExist`] if the nanosecond part to represent a leap second is not on
/// a minute boundary.
///
/// # Example
///
/// ```
/// use chrono::NaiveDate;
/// use chrono::{Error, NaiveDate};
///
/// let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap();
/// assert!(d.and_hms_nano_opt(12, 34, 56, 789_012_345).is_some());
/// assert!(d.and_hms_nano_opt(12, 34, 59, 1_789_012_345).is_some()); // leap second
/// assert!(d.and_hms_nano_opt(12, 34, 59, 2_789_012_345).is_none());
/// assert!(d.and_hms_nano_opt(12, 34, 60, 789_012_345).is_none());
/// assert!(d.and_hms_nano_opt(12, 60, 56, 789_012_345).is_none());
/// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none());
/// assert!(d.and_hms_nano_opt(12, 34, 56, 789_012_345).is_ok());
/// assert!(d.and_hms_nano_opt(12, 34, 59, 1_789_012_345).is_ok()); // leap second
/// assert_eq!(d.and_hms_nano_opt(12, 34, 59, 2_789_012_345), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_nano_opt(12, 34, 60, 789_012_345), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_nano_opt(12, 60, 56, 789_012_345), Err(Error::InvalidArgument));
/// assert_eq!(d.and_hms_nano_opt(24, 34, 56, 789_012_345), Err(Error::InvalidArgument));
/// ```
#[inline]
#[must_use]
pub const fn and_hms_nano_opt(
&self,
hour: u32,
min: u32,
sec: u32,
nano: u32,
) -> Option<NaiveDateTime> {
let time = try_opt!(ok!(NaiveTime::from_hms_nano(hour, min, sec, nano)));
Some(self.and_time(time))
) -> Result<NaiveDateTime, Error> {
let time = try_err!(NaiveTime::from_hms_nano(hour, min, sec, nano));
Ok(self.and_time(time))
}

/// Returns the packed month-day-flags.
Expand Down
4 changes: 2 additions & 2 deletions src/naive/datetime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ fn test_and_utc() {
#[test]
fn test_checked_add_offset() {
let ymdhmsm = |y, m, d, h, mn, s, mi| {
NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_milli_opt(h, mn, s, mi)
Some(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_milli_opt(h, mn, s, mi).unwrap())
};

let positive_offset = FixedOffset::east(2 * 60 * 60).unwrap();
Expand All @@ -534,7 +534,7 @@ fn test_checked_add_offset() {
#[test]
fn test_checked_sub_offset() {
let ymdhmsm = |y, m, d, h, mn, s, mi| {
NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_milli_opt(h, mn, s, mi)
Some(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_milli_opt(h, mn, s, mi).unwrap())
};

let positive_offset = FixedOffset::east(2 * 60 * 60).unwrap();
Expand Down
4 changes: 2 additions & 2 deletions src/offset/local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ mod tests {
// issue #123
let today = Utc::now().date_naive();

if let Some(dt) = today.and_hms_milli_opt(15, 2, 59, 1000) {
if let Ok(dt) = today.and_hms_milli_opt(15, 2, 59, 1000) {
let timestr = dt.time().to_string();
// the OS API may or may not support the leap second,
// but there are only two sensible options.
Expand All @@ -231,7 +231,7 @@ mod tests {
);
}

if let Some(dt) = today.and_hms_milli_opt(15, 2, 3, 1234) {
if let Ok(dt) = today.and_hms_milli_opt(15, 2, 3, 1234) {
let timestr = dt.time().to_string();
assert!(
timestr == "15:02:03.234" || timestr == "15:02:04.234",
Expand Down
3 changes: 2 additions & 1 deletion src/offset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ pub trait TimeZone: Sized + Clone {
min: u32,
sec: u32,
) -> LocalResult<DateTime<Self>> {
match NaiveDate::from_ymd_opt(year, month, day).and_then(|d| d.and_hms_opt(hour, min, sec))
match NaiveDate::from_ymd_opt(year, month, day)
.and_then(|d| d.and_hms_opt(hour, min, sec).ok())
{
Some(dt) => self.from_local_datetime(&dt),
None => LocalResult::None,
Expand Down

0 comments on commit fe8a655

Please sign in to comment.