Skip to content

Commit

Permalink
Fix out-of-range panic in NaiveWeek::last_day
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed May 7, 2023
1 parent 96449d3 commit 4074ba9
Showing 1 changed file with 26 additions and 15 deletions.
41 changes: 26 additions & 15 deletions src/naive/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::format::{Item, Numeric, Pad};
use crate::month::Months;
use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime};
use crate::oldtime::Duration as OldDuration;
use crate::{Datelike, Duration, Weekday};
use crate::{Datelike, Weekday};

use super::internals::{self, DateImpl, Mdf, Of, YearFlags};
use super::isoweek;
Expand Down Expand Up @@ -77,10 +77,10 @@ impl NaiveWeek {
#[inline]
#[must_use]
pub fn first_day(&self) -> NaiveDate {
let start = self.start.num_days_from_monday();
let end = self.date.weekday().num_days_from_monday();
let days = if start > end { 7 - start + end } else { end - start };
self.date - Duration::days(days.into())
let start = self.start.num_days_from_monday() as i32;
let ref_day = self.date.weekday().num_days_from_monday() as i32;
let days = if start > ref_day { start - ref_day - 7 } else { start - ref_day };
self.date.add_days(days, false).unwrap()
}

/// Returns a date representing the last day of the week.
Expand All @@ -97,7 +97,10 @@ impl NaiveWeek {
#[inline]
#[must_use]
pub fn last_day(&self) -> NaiveDate {
self.first_day() + Duration::days(6)
let end = self.start.pred().num_days_from_monday() as i32;
let ref_day = self.date.weekday().num_days_from_monday() as i32;
let days = if end < ref_day { end - ref_day + 7 } else { end - ref_day };
self.date.add_days(days, false).unwrap()
}

/// Returns a [`RangeInclusive<T>`] representing the whole week bounded by
Expand Down Expand Up @@ -2965,23 +2968,31 @@ mod tests {
fn test_naiveweek() {
let date = NaiveDate::from_ymd_opt(2022, 5, 18).unwrap();
let asserts = vec![
(Weekday::Mon, "2022-05-16", "2022-05-22"),
(Weekday::Tue, "2022-05-17", "2022-05-23"),
(Weekday::Wed, "2022-05-18", "2022-05-24"),
(Weekday::Thu, "2022-05-12", "2022-05-18"),
(Weekday::Fri, "2022-05-13", "2022-05-19"),
(Weekday::Sat, "2022-05-14", "2022-05-20"),
(Weekday::Sun, "2022-05-15", "2022-05-21"),
(Weekday::Mon, "Mon 2022-05-16", "Sun 2022-05-22"),
(Weekday::Tue, "Tue 2022-05-17", "Mon 2022-05-23"),
(Weekday::Wed, "Wed 2022-05-18", "Tue 2022-05-24"),
(Weekday::Thu, "Thu 2022-05-12", "Wed 2022-05-18"),
(Weekday::Fri, "Fri 2022-05-13", "Thu 2022-05-19"),
(Weekday::Sat, "Sat 2022-05-14", "Fri 2022-05-20"),
(Weekday::Sun, "Sun 2022-05-15", "Sat 2022-05-21"),
];
for (start, first_day, last_day) in asserts {
let week = date.week(start);
let days = week.days();
assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%Y-%m-%d"));
assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%Y-%m-%d"));
assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%a %Y-%m-%d"));
assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%a %Y-%m-%d"));
assert!(days.contains(&date));
}
}

#[test]
fn test_naiveweek_min_max() {
let date_max = NaiveDate::MAX;
assert!(date_max.week(Weekday::Mon).first_day() <= date_max);
let date_min = NaiveDate::MIN;
assert!(date_min.week(Weekday::Mon).last_day() >= date_min);
}

#[test]
fn test_weeks_from() {
// tests per: https://github.com/chronotope/chrono/issues/961
Expand Down

0 comments on commit 4074ba9

Please sign in to comment.