Skip to content

Commit 4074ba9

Browse files
committed
Fix out-of-range panic in NaiveWeek::last_day
1 parent 96449d3 commit 4074ba9

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
@@ -24,7 +24,7 @@ use crate::format::{Item, Numeric, Pad};
2424
use crate::month::Months;
2525
use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime};
2626
use crate::oldtime::Duration as OldDuration;
27-
use crate::{Datelike, Duration, Weekday};
27+
use crate::{Datelike, Weekday};
2828

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

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

103106
/// Returns a [`RangeInclusive<T>`] representing the whole week bounded by
@@ -2965,23 +2968,31 @@ mod tests {
29652968
fn test_naiveweek() {
29662969
let date = NaiveDate::from_ymd_opt(2022, 5, 18).unwrap();
29672970
let asserts = vec![
2968-
(Weekday::Mon, "2022-05-16", "2022-05-22"),
2969-
(Weekday::Tue, "2022-05-17", "2022-05-23"),
2970-
(Weekday::Wed, "2022-05-18", "2022-05-24"),
2971-
(Weekday::Thu, "2022-05-12", "2022-05-18"),
2972-
(Weekday::Fri, "2022-05-13", "2022-05-19"),
2973-
(Weekday::Sat, "2022-05-14", "2022-05-20"),
2974-
(Weekday::Sun, "2022-05-15", "2022-05-21"),
2971+
(Weekday::Mon, "Mon 2022-05-16", "Sun 2022-05-22"),
2972+
(Weekday::Tue, "Tue 2022-05-17", "Mon 2022-05-23"),
2973+
(Weekday::Wed, "Wed 2022-05-18", "Tue 2022-05-24"),
2974+
(Weekday::Thu, "Thu 2022-05-12", "Wed 2022-05-18"),
2975+
(Weekday::Fri, "Fri 2022-05-13", "Thu 2022-05-19"),
2976+
(Weekday::Sat, "Sat 2022-05-14", "Fri 2022-05-20"),
2977+
(Weekday::Sun, "Sun 2022-05-15", "Sat 2022-05-21"),
29752978
];
29762979
for (start, first_day, last_day) in asserts {
29772980
let week = date.week(start);
29782981
let days = week.days();
2979-
assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%Y-%m-%d"));
2980-
assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%Y-%m-%d"));
2982+
assert_eq!(Ok(week.first_day()), NaiveDate::parse_from_str(first_day, "%a %Y-%m-%d"));
2983+
assert_eq!(Ok(week.last_day()), NaiveDate::parse_from_str(last_day, "%a %Y-%m-%d"));
29812984
assert!(days.contains(&date));
29822985
}
29832986
}
29842987

2988+
#[test]
2989+
fn test_naiveweek_min_max() {
2990+
let date_max = NaiveDate::MAX;
2991+
assert!(date_max.week(Weekday::Mon).first_day() <= date_max);
2992+
let date_min = NaiveDate::MIN;
2993+
assert!(date_min.week(Weekday::Mon).last_day() >= date_min);
2994+
}
2995+
29852996
#[test]
29862997
fn test_weeks_from() {
29872998
// tests per: https://github.com/chronotope/chrono/issues/961

0 commit comments

Comments
 (0)