Skip to content

Commit 0dd37c2

Browse files
committed
Fix out-of-range panic in NaiveWeek::last_day
1 parent ccbc37b commit 0dd37c2

File tree

1 file changed

+26
-15
lines changed

1 file changed

+26
-15
lines changed

src/naive/date.rs

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::format::{Item, Numeric, Pad};
2323
use crate::month::Months;
2424
use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime};
2525
use crate::oldtime::Duration as OldDuration;
26-
use crate::{Datelike, Duration, Weekday};
26+
use crate::{Datelike, Weekday};
2727

2828
use super::internals::{self, DateImpl, Mdf, Of, YearFlags};
2929
use super::isoweek;
@@ -76,10 +76,10 @@ impl NaiveWeek {
7676
#[inline]
7777
#[must_use]
7878
pub fn first_day(&self) -> NaiveDate {
79-
let start = self.start.num_days_from_monday();
80-
let end = self.date.weekday().num_days_from_monday();
81-
let days = if start > end { 7 - start + end } else { end - start };
82-
self.date - Duration::days(days.into())
79+
let start = self.start.num_days_from_monday() as i32;
80+
let ref_day = self.date.weekday().num_days_from_monday() as i32;
81+
let days = if start > ref_day { start - ref_day - 7 } else { start - ref_day };
82+
self.date.add_days(days, false).unwrap()
8383
}
8484

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

102105
/// Returns a [`RangeInclusive<T>`] representing the whole week bounded by
@@ -3005,23 +3008,31 @@ mod tests {
30053008
fn test_naiveweek() {
30063009
let date = NaiveDate::from_ymd_opt(2022, 5, 18).unwrap();
30073010
let asserts = vec![
3008-
(Weekday::Mon, "2022-05-16", "2022-05-22"),
3009-
(Weekday::Tue, "2022-05-17", "2022-05-23"),
3010-
(Weekday::Wed, "2022-05-18", "2022-05-24"),
3011-
(Weekday::Thu, "2022-05-12", "2022-05-18"),
3012-
(Weekday::Fri, "2022-05-13", "2022-05-19"),
3013-
(Weekday::Sat, "2022-05-14", "2022-05-20"),
3014-
(Weekday::Sun, "2022-05-15", "2022-05-21"),
3011+
(Weekday::Mon, "Mon 2022-05-16", "Sun 2022-05-22"),
3012+
(Weekday::Tue, "Tue 2022-05-17", "Mon 2022-05-23"),
3013+
(Weekday::Wed, "Wed 2022-05-18", "Tue 2022-05-24"),
3014+
(Weekday::Thu, "Thu 2022-05-12", "Wed 2022-05-18"),
3015+
(Weekday::Fri, "Fri 2022-05-13", "Thu 2022-05-19"),
3016+
(Weekday::Sat, "Sat 2022-05-14", "Fri 2022-05-20"),
3017+
(Weekday::Sun, "Sun 2022-05-15", "Sat 2022-05-21"),
30153018
];
30163019
for (start, first_day, last_day) in asserts {
30173020
let week = date.week(start);
30183021
let days = week.days();
3019-
assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%Y-%m-%d"));
3020-
assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%Y-%m-%d"));
3022+
assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%a %Y-%m-%d"));
3023+
assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%a %Y-%m-%d"));
30213024
assert!(days.contains(&date));
30223025
}
30233026
}
30243027

3028+
#[test]
3029+
fn test_naiveweek_min_max() {
3030+
let date_max = NaiveDate::MAX;
3031+
assert!(date_max.week(Weekday::Mon).first_day() <= date_max);
3032+
let date_min = NaiveDate::MIN;
3033+
assert!(date_min.week(Weekday::Mon).last_day() >= date_min);
3034+
}
3035+
30253036
#[test]
30263037
fn test_weeks_from() {
30273038
// tests per: https://github.com/chronotope/chrono/issues/961

0 commit comments

Comments
 (0)