mirror of
https://github.com/chronotope/chrono.git
synced 2025-10-02 15:26:12 +00:00
factor calculations to weeks_from function and add tests
tests for weeks_from and num_days_from fix array iter MSRV issue
This commit is contained in:
parent
8197700ccd
commit
cf2a2f95f7
@ -520,12 +520,8 @@ fn format_inner(
|
||||
Item::Numeric(ref spec, ref pad) => {
|
||||
use self::Numeric::*;
|
||||
|
||||
let week_from_sun = |d: &NaiveDate| {
|
||||
(d.ordinal() as i32 - d.weekday().num_days_from_sunday() as i32 + 6) / 7
|
||||
};
|
||||
let week_from_mon = |d: &NaiveDate| {
|
||||
(d.ordinal() as i32 - d.weekday().num_days_from_monday() as i32 + 6) / 7
|
||||
};
|
||||
let week_from_sun = |d: &NaiveDate| d.weeks_from(Weekday::Sun);
|
||||
let week_from_mon = |d: &NaiveDate| d.weeks_from(Weekday::Mon);
|
||||
|
||||
let (width, v) = match *spec {
|
||||
Year => (4, date.map(|d| i64::from(d.year()))),
|
||||
|
@ -379,9 +379,8 @@ impl Parsed {
|
||||
// verify the ordinal and other (non-ISO) week dates.
|
||||
let verify_ordinal = |date: NaiveDate| {
|
||||
let ordinal = date.ordinal();
|
||||
let weekday = date.weekday();
|
||||
let week_from_sun = (ordinal as i32 - weekday.num_days_from_sunday() as i32 + 6) / 7;
|
||||
let week_from_mon = (ordinal as i32 - weekday.num_days_from_monday() as i32 + 6) / 7;
|
||||
let week_from_sun = date.weeks_from(Weekday::Sun);
|
||||
let week_from_mon = date.weeks_from(Weekday::Mon);
|
||||
self.ordinal.unwrap_or(ordinal) == ordinal
|
||||
&& self.week_from_sun.map_or(week_from_sun, |v| v as i32) == week_from_sun
|
||||
&& self.week_from_mon.map_or(week_from_mon, |v| v as i32) == week_from_mon
|
||||
|
@ -236,6 +236,9 @@ fn test_date_bounds() {
|
||||
}
|
||||
|
||||
impl NaiveDate {
|
||||
pub(crate) fn weeks_from(&self, day: Weekday) -> i32 {
|
||||
(self.ordinal() as i32 - self.weekday().num_days_from(day) as i32 + 6) / 7
|
||||
}
|
||||
/// Makes a new `NaiveDate` from year and packed ordinal-flags, with a verification.
|
||||
fn from_of(year: i32, of: Of) -> Option<NaiveDate> {
|
||||
if (MIN_YEAR..=MAX_YEAR).contains(&year) && of.valid() {
|
||||
@ -2928,4 +2931,67 @@ mod tests {
|
||||
assert!(days.contains(&date));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weeks_from() {
|
||||
// tests per: https://github.com/chronotope/chrono/issues/961
|
||||
// these internally use `weeks_from` via the parsing infrastructure
|
||||
assert_eq!(
|
||||
NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w").ok(),
|
||||
NaiveDate::from_ymd_opt(2020, 1, 12),
|
||||
);
|
||||
assert_eq!(
|
||||
NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w").ok(),
|
||||
NaiveDate::from_ymd_opt(2019, 1, 13),
|
||||
);
|
||||
|
||||
// direct tests
|
||||
for (y, starts_on) in &[
|
||||
(2019, Weekday::Tue),
|
||||
(2020, Weekday::Wed),
|
||||
(2021, Weekday::Fri),
|
||||
(2022, Weekday::Sat),
|
||||
(2023, Weekday::Sun),
|
||||
(2024, Weekday::Mon),
|
||||
(2025, Weekday::Wed),
|
||||
(2026, Weekday::Thu),
|
||||
] {
|
||||
for day in &[
|
||||
Weekday::Mon,
|
||||
Weekday::Tue,
|
||||
Weekday::Wed,
|
||||
Weekday::Thu,
|
||||
Weekday::Fri,
|
||||
Weekday::Sat,
|
||||
Weekday::Sun,
|
||||
] {
|
||||
assert_eq!(
|
||||
NaiveDate::from_ymd_opt(*y, 1, 1).map(|d| d.weeks_from(*day)),
|
||||
Some(if day == starts_on { 1 } else { 0 })
|
||||
);
|
||||
|
||||
// last day must always be in week 52 or 53
|
||||
assert!([52, 53]
|
||||
.contains(&NaiveDate::from_ymd_opt(*y, 12, 31).unwrap().weeks_from(*day)),);
|
||||
}
|
||||
}
|
||||
|
||||
let base = NaiveDate::from_ymd_opt(2019, 1, 1).unwrap();
|
||||
|
||||
// 400 years covers all year types
|
||||
for day in &[
|
||||
Weekday::Mon,
|
||||
Weekday::Tue,
|
||||
Weekday::Wed,
|
||||
Weekday::Thu,
|
||||
Weekday::Fri,
|
||||
Weekday::Sat,
|
||||
Weekday::Sun,
|
||||
] {
|
||||
// must always be below 54
|
||||
for dplus in 1..(400 * 366) {
|
||||
assert!((base + Days::new(dplus)).weeks_from(*day) < 54)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,15 +73,7 @@ impl Weekday {
|
||||
/// `w.number_from_monday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 7
|
||||
#[inline]
|
||||
pub fn number_from_monday(&self) -> u32 {
|
||||
match *self {
|
||||
Weekday::Mon => 1,
|
||||
Weekday::Tue => 2,
|
||||
Weekday::Wed => 3,
|
||||
Weekday::Thu => 4,
|
||||
Weekday::Fri => 5,
|
||||
Weekday::Sat => 6,
|
||||
Weekday::Sun => 7,
|
||||
}
|
||||
self.num_days_from(Weekday::Mon) + 1
|
||||
}
|
||||
|
||||
/// Returns a day-of-week number starting from Sunday = 1.
|
||||
@ -91,15 +83,7 @@ impl Weekday {
|
||||
/// `w.number_from_sunday()`: | 2 | 3 | 4 | 5 | 6 | 7 | 1
|
||||
#[inline]
|
||||
pub fn number_from_sunday(&self) -> u32 {
|
||||
match *self {
|
||||
Weekday::Mon => 2,
|
||||
Weekday::Tue => 3,
|
||||
Weekday::Wed => 4,
|
||||
Weekday::Thu => 5,
|
||||
Weekday::Fri => 6,
|
||||
Weekday::Sat => 7,
|
||||
Weekday::Sun => 1,
|
||||
}
|
||||
self.num_days_from(Weekday::Sun) + 1
|
||||
}
|
||||
|
||||
/// Returns a day-of-week number starting from Monday = 0.
|
||||
@ -109,15 +93,7 @@ impl Weekday {
|
||||
/// `w.num_days_from_monday()`: | 0 | 1 | 2 | 3 | 4 | 5 | 6
|
||||
#[inline]
|
||||
pub fn num_days_from_monday(&self) -> u32 {
|
||||
match *self {
|
||||
Weekday::Mon => 0,
|
||||
Weekday::Tue => 1,
|
||||
Weekday::Wed => 2,
|
||||
Weekday::Thu => 3,
|
||||
Weekday::Fri => 4,
|
||||
Weekday::Sat => 5,
|
||||
Weekday::Sun => 6,
|
||||
}
|
||||
self.num_days_from(Weekday::Mon)
|
||||
}
|
||||
|
||||
/// Returns a day-of-week number starting from Sunday = 0.
|
||||
@ -127,15 +103,17 @@ impl Weekday {
|
||||
/// `w.num_days_from_sunday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 0
|
||||
#[inline]
|
||||
pub fn num_days_from_sunday(&self) -> u32 {
|
||||
match *self {
|
||||
Weekday::Mon => 1,
|
||||
Weekday::Tue => 2,
|
||||
Weekday::Wed => 3,
|
||||
Weekday::Thu => 4,
|
||||
Weekday::Fri => 5,
|
||||
Weekday::Sat => 6,
|
||||
Weekday::Sun => 0,
|
||||
}
|
||||
self.num_days_from(Weekday::Sun)
|
||||
}
|
||||
|
||||
/// Returns a day-of-week number starting from the parameter `day` (D) = 0.
|
||||
///
|
||||
/// `w`: | `D` | `D+1` | `D+2` | `D+3` | `D+4` | `D+5` | `D+6`
|
||||
/// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
|
||||
/// `w.num_days_from(wd)`: | 0 | 1 | 2 | 3 | 4 | 5 | 6
|
||||
#[inline]
|
||||
pub(crate) fn num_days_from(&self, day: Weekday) -> u32 {
|
||||
(*self as u32 + 7 - day as u32) % 7
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,6 +186,45 @@ impl fmt::Debug for ParseWeekdayError {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use super::Weekday;
|
||||
|
||||
#[test]
|
||||
fn test_num_days_from() {
|
||||
for i in 0..7 {
|
||||
let base_day = Weekday::from_u64(i).unwrap();
|
||||
|
||||
assert_eq!(base_day.num_days_from_monday(), base_day.num_days_from(Weekday::Mon));
|
||||
assert_eq!(base_day.num_days_from_sunday(), base_day.num_days_from(Weekday::Sun));
|
||||
|
||||
assert_eq!(base_day.num_days_from(base_day), 0);
|
||||
|
||||
assert_eq!(base_day.num_days_from(base_day.pred()), 1);
|
||||
assert_eq!(base_day.num_days_from(base_day.pred().pred()), 2);
|
||||
assert_eq!(base_day.num_days_from(base_day.pred().pred().pred()), 3);
|
||||
assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred()), 4);
|
||||
assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred().pred()), 5);
|
||||
assert_eq!(
|
||||
base_day.num_days_from(base_day.pred().pred().pred().pred().pred().pred()),
|
||||
6
|
||||
);
|
||||
|
||||
assert_eq!(base_day.num_days_from(base_day.succ()), 6);
|
||||
assert_eq!(base_day.num_days_from(base_day.succ().succ()), 5);
|
||||
assert_eq!(base_day.num_days_from(base_day.succ().succ().succ()), 4);
|
||||
assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ()), 3);
|
||||
assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ().succ()), 2);
|
||||
assert_eq!(
|
||||
base_day.num_days_from(base_day.succ().succ().succ().succ().succ().succ()),
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the actual `FromStr` implementation is in the `format` module to leverage the existing code
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
|
Loading…
x
Reference in New Issue
Block a user