Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checked NaiveWeek methods #1600

Merged
merged 4 commits into from
Aug 19, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 101 additions & 3 deletions src/naive/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,37 @@
#[inline]
#[must_use]
pub const fn first_day(&self) -> NaiveDate {
expect(self.checked_first_day(), "first weekday out of range for `NaiveDate`")
}

/// Returns a date representing the first day of the week or
/// `None` if the date is out of `NaiveDate`'s range
/// (more than ca. 262,000 years away from common era).
///
/// # Examples
///
/// ```
/// use chrono::{NaiveDate, Weekday};
///
/// let date = NaiveDate::MIN;
/// let week = date.week(Weekday::Mon);
/// if let Some(first_day) = week.checked_first_day() {
/// assert!(first_day == date);
/// } else {

Check warning on line 79 in src/naive/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/naive/mod.rs#L79

Added line #L79 was not covered by tests
/// // error handling code
/// return;
/// };
/// ```
#[inline]
#[must_use]
pub const fn checked_first_day(&self) -> Option<NaiveDate> {
let start = self.start.num_days_from_monday() as i32;
let ref_day = self.date.weekday().num_days_from_monday() as i32;
// Calculate the number of days to subtract from `self.date`.
// Do not construct an intermediate date beyond `self.date`, because that may be out of
// range if `date` is close to `NaiveDate::MAX`.
let days = start - ref_day - if start > ref_day { 7 } else { 0 };
expect(self.date.add_days(days), "first weekday out of range for `NaiveDate`")
self.date.add_days(days)
}

/// Returns a date representing the last day of the week.
Expand All @@ -88,13 +112,37 @@
#[inline]
#[must_use]
pub const fn last_day(&self) -> NaiveDate {
expect(self.checked_last_day(), "last weekday out of range for `NaiveDate`")
}

/// Returns a date representing the last day of the week or
/// `None` if the date is out of `NaiveDate`'s range
/// (more than ca. 262,000 years away from common era).
///
/// # Examples
///
/// ```
/// use chrono::{NaiveDate, Weekday};
///
/// let date = NaiveDate::MAX;
/// let week = date.week(Weekday::Mon);
/// if let Some(last_day) = week.checked_last_day() {
/// assert!(last_day == date);
/// } else {

Check warning on line 131 in src/naive/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/naive/mod.rs#L131

Added line #L131 was not covered by tests
/// // error handling code
/// return;
/// };
/// ```
#[inline]
#[must_use]
pub const fn checked_last_day(&self) -> Option<NaiveDate> {
let end = self.start.pred().num_days_from_monday() as i32;
let ref_day = self.date.weekday().num_days_from_monday() as i32;
// Calculate the number of days to add to `self.date`.
// Do not construct an intermediate date before `self.date` (like with `first_day()`),
// because that may be out of range if `date` is close to `NaiveDate::MIN`.
let days = end - ref_day + if end < ref_day { 7 } else { 0 };
expect(self.date.add_days(days), "last weekday out of range for `NaiveDate`")
self.date.add_days(days)
}

/// Returns a [`RangeInclusive<T>`] representing the whole week bounded by
Expand All @@ -118,7 +166,43 @@
#[inline]
#[must_use]
pub const fn days(&self) -> RangeInclusive<NaiveDate> {
self.first_day()..=self.last_day()
// `expect` doesn't work because `RangeInclusive` is not `Copy`
match self.checked_days() {
Some(val) => val,
None => panic!("{}", "first or last weekday is out of range for `NaiveDate`"),

Check warning on line 172 in src/naive/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/naive/mod.rs#L172

Added line #L172 was not covered by tests
}
}

/// Returns an [`Option<RangeInclusive<T>>`] representing the whole week bounded by
/// [checked_first_day](NaiveWeek::checked_first_day) and
/// [checked_last_day](NaiveWeek::checked_last_day) functions.
///
/// Returns `None` if either of the boundaries are out of `NaiveDate`'s range
/// (more than ca. 262,000 years away from common era).
///
///
/// # Examples
///
/// ```
/// use chrono::{NaiveDate, Weekday};
///
/// let date = NaiveDate::MAX;
/// let week = date.week(Weekday::Mon);
/// let _days = match week.checked_days() {
/// Some(d) => d,
/// None => {

Check warning on line 193 in src/naive/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/naive/mod.rs#L193

Added line #L193 was not covered by tests
/// // error handling code
/// return;
/// }
/// };
/// ```
#[inline]
#[must_use]
pub const fn checked_days(&self) -> Option<RangeInclusive<NaiveDate>> {
match (self.checked_first_day(), self.checked_last_day()) {
(Some(first), Some(last)) => Some(first..=last),
(_, _) => None,
}
}
}

Expand Down Expand Up @@ -180,4 +264,18 @@
let date_min = NaiveDate::MIN;
assert!(date_min.week(Weekday::Mon).last_day() >= date_min);
}

#[test]
fn test_naiveweek_checked_no_panic() {
let date_max = NaiveDate::MAX;
if let Some(last) = date_max.week(Weekday::Mon).checked_last_day() {
assert!(last == date_max);

Check warning on line 272 in src/naive/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/naive/mod.rs#L272

Added line #L272 was not covered by tests
}
let date_min = NaiveDate::MIN;
if let Some(first) = date_min.week(Weekday::Mon).checked_first_day() {
assert!(first == date_min);

Check warning on line 276 in src/naive/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/naive/mod.rs#L276

Added line #L276 was not covered by tests
}
let _ = date_min.week(Weekday::Mon).checked_days();
let _ = date_max.week(Weekday::Mon).checked_days();
}
}
Loading