From 4ffd411654a352f013d4cf93a910183d9f2adc5f Mon Sep 17 00:00:00 2001 From: Alex Sayers Date: Fri, 10 Aug 2018 15:08:25 +0900 Subject: [PATCH 1/3] Add NaiveDate::from_ymwd This contructor allows you to make a NaiveDate by specifying eg. "the 2nd Friday of March 2017". It contains a couple of panics, but these are consistent with the behaviour of the other NaiveDate constructors. --- CHANGELOG.md | 6 ++++++ src/naive/date.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4f05ba..f1501b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ Chrono obeys the principle of [Semantic Versioning](http://semver.org/). There were/are numerous minor versions before 1.0 due to the language changes. Versions with only mechnical changes will be omitted from the following list. +## Unreleased + +### Features + +* Added `NaiveDate::from_ymwd` for getting eg. the 2nd Friday of March 2017. + ## 0.4.5 ### Features diff --git a/src/naive/date.rs b/src/naive/date.rs index aad98bc..b6223b3 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -407,6 +407,39 @@ impl NaiveDate { Of::new(ordinal, flags)) } + /// Makes a new `NaiveDate` by counting weeks from the beginning of the given month. For + /// instance, if you want the 2nd Friday of March 2017 you would use + /// `NaiveDate::from_ymwd(2017, 3, WeekDay::Fri, 2)`. This corresponds to March 10th. + /// + /// # Panics + /// + /// The resulting `NaiveDate` is guaranteed to be in `month`. If `n` is larger than the number + /// of `weekday` in `month` (eg. the 6th Friday of March 2017) then this function will panic. + /// + /// `n` is 1-indexed. Passing `n=0` will cause a panic. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Weekday}; + /// + /// let from_ymwd = NaiveDate::from_ymwd; + /// let from_ymd = NaiveDate::from_ymd; + /// + /// assert_eq!(from_ymwd(2018, 8, Weekday::Wed, 1), from_ymd(2018, 8, 1)); + /// assert_eq!(from_ymwd(2018, 8, Weekday::Fri, 1), from_ymd(2018, 8, 3)); + /// assert_eq!(from_ymwd(2018, 8, Weekday::Tue, 2), from_ymd(2018, 8, 14)); + /// assert_eq!(from_ymwd(2018, 8, Weekday::Fri, 4), from_ymd(2018, 8, 24)); + /// assert_eq!(from_ymwd(2018, 8, Weekday::Fri, 5), from_ymd(2018, 8, 31)); + /// ~~~~ + pub fn from_ymwd(year: i32, month: u32, weekday: Weekday, n: u8) -> NaiveDate { + assert!(n > 0, "NaiveDate::from_ymwd is 1-indexed"); + let first = NaiveDate::from_ymd(year, month, 1).weekday(); + let first_to_dow = (7 + weekday.number_from_monday() - first.number_from_monday()) % 7; + let day = (u32::from(n) - 1) * 7 + first_to_dow + 1; + NaiveDate::from_ymd(year, month, day) + } + /// Parses a string with the specified format string and returns a new `NaiveDate`. /// See the [`format::strftime` module](../format/strftime/index.html) /// on the supported escape sequences. @@ -1823,6 +1856,23 @@ mod tests { assert_eq!(from_ndays_from_ce(MAX_DATE.num_days_from_ce() + 1), None); } + #[test] + fn test_date_from_ymwd() { + let ymwd = |y,m,w,n| NaiveDate::from_ymwd(y,m,w,n); + assert_eq!(ymwd(2018, 8, Weekday::Wed, 1), NaiveDate::from_ymd(2018, 8, 1)); + assert_eq!(ymwd(2018, 8, Weekday::Thu, 1), NaiveDate::from_ymd(2018, 8, 2)); + assert_eq!(ymwd(2018, 8, Weekday::Sun, 1), NaiveDate::from_ymd(2018, 8, 5)); + assert_eq!(ymwd(2018, 8, Weekday::Mon, 1), NaiveDate::from_ymd(2018, 8, 6)); + assert_eq!(ymwd(2018, 8, Weekday::Tue, 1), NaiveDate::from_ymd(2018, 8, 7)); + assert_eq!(ymwd(2018, 8, Weekday::Wed, 2), NaiveDate::from_ymd(2018, 8, 8)); + assert_eq!(ymwd(2018, 8, Weekday::Sun, 2), NaiveDate::from_ymd(2018, 8, 12)); + assert_eq!(ymwd(2018, 8, Weekday::Thu, 3), NaiveDate::from_ymd(2018, 8, 16)); + assert_eq!(ymwd(2018, 8, Weekday::Thu, 4), NaiveDate::from_ymd(2018, 8, 23)); + assert_eq!(ymwd(2018, 8, Weekday::Thu, 5), NaiveDate::from_ymd(2018, 8, 30)); + assert_eq!(ymwd(2018, 8, Weekday::Fri, 5), NaiveDate::from_ymd(2018, 8, 31)); + // assert_eq!(ymwd(2018, 8, Weekday::Sat, 5), NaiveDate::from_ymd(2018, 9, 1)); + } + #[test] fn test_date_fields() { fn check(year: i32, month: u32, day: u32, ordinal: u32) { From 892bbf3f3a586d3106301ebb20593d3f16d02008 Mon Sep 17 00:00:00 2001 From: Alex Sayers Date: Mon, 13 Aug 2018 10:58:32 +0900 Subject: [PATCH 2/3] Add NaiveDate::from_ymwd_opt, implement from_ymwd in terms of it --- CHANGELOG.md | 2 +- src/naive/date.rs | 55 +++++++++++++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1501b9..6f22a3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ Versions with only mechnical changes will be omitted from the following list. ### Features -* Added `NaiveDate::from_ymwd` for getting eg. the 2nd Friday of March 2017. +* Added `NaiveDate::from_ymwd{,_opt}` for getting eg. the 2nd Friday of March 2017. ## 0.4.5 diff --git a/src/naive/date.rs b/src/naive/date.rs index b6223b3..a7005fd 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -407,9 +407,9 @@ impl NaiveDate { Of::new(ordinal, flags)) } - /// Makes a new `NaiveDate` by counting weeks from the beginning of the given month. For - /// instance, if you want the 2nd Friday of March 2017 you would use - /// `NaiveDate::from_ymwd(2017, 3, WeekDay::Fri, 2)`. This corresponds to March 10th. + /// Makes a new `NaiveDate` by counting the number of occurances of a particular day-of-week + /// since the beginning of the given month. For instance, if you want the 2nd Friday of March + /// 2017, you would use `NaiveDate::from_ymwd(2017, 3, Weekday::Fri, 2)`. /// /// # Panics /// @@ -433,11 +433,27 @@ impl NaiveDate { /// assert_eq!(from_ymwd(2018, 8, Weekday::Fri, 5), from_ymd(2018, 8, 31)); /// ~~~~ pub fn from_ymwd(year: i32, month: u32, weekday: Weekday, n: u8) -> NaiveDate { - assert!(n > 0, "NaiveDate::from_ymwd is 1-indexed"); + NaiveDate::from_ymwd_opt(year, month, weekday, n).expect("out-of-range date") + } + + /// Makes a new `NaiveDate` by counting the number of occurances of a particular day-of-week + /// since the beginning of the given month. For instance, if you want the 2nd Friday of March + /// 2017, you would use `NaiveDate::from_ymwd(2017, 3, Weekday::Fri, 2)`. `n` is 1-indexed. + /// + /// ~~~~ + /// use chrono::{NaiveDate, Weekday}; + /// assert_eq!(NaiveDate::from_ymwd_opt(2017, 3, Weekday::Fri, 2), + /// NaiveDate::from_ymd_opt(2017, 3, 10)) + /// ~~~~ + /// + /// Returns `None` if `n` out-of-range; ie. if `n` is larger than the number of `weekday` in + /// `month` (eg. the 6th Friday of March 2017), or if `n == 0`. + pub fn from_ymwd_opt(year: i32, month: u32, weekday: Weekday, n: u8) -> Option { + if n == 0 { return None; } let first = NaiveDate::from_ymd(year, month, 1).weekday(); let first_to_dow = (7 + weekday.number_from_monday() - first.number_from_monday()) % 7; let day = (u32::from(n) - 1) * 7 + first_to_dow + 1; - NaiveDate::from_ymd(year, month, day) + NaiveDate::from_ymd_opt(year, month, day) } /// Parses a string with the specified format string and returns a new `NaiveDate`. @@ -1857,20 +1873,21 @@ mod tests { } #[test] - fn test_date_from_ymwd() { - let ymwd = |y,m,w,n| NaiveDate::from_ymwd(y,m,w,n); - assert_eq!(ymwd(2018, 8, Weekday::Wed, 1), NaiveDate::from_ymd(2018, 8, 1)); - assert_eq!(ymwd(2018, 8, Weekday::Thu, 1), NaiveDate::from_ymd(2018, 8, 2)); - assert_eq!(ymwd(2018, 8, Weekday::Sun, 1), NaiveDate::from_ymd(2018, 8, 5)); - assert_eq!(ymwd(2018, 8, Weekday::Mon, 1), NaiveDate::from_ymd(2018, 8, 6)); - assert_eq!(ymwd(2018, 8, Weekday::Tue, 1), NaiveDate::from_ymd(2018, 8, 7)); - assert_eq!(ymwd(2018, 8, Weekday::Wed, 2), NaiveDate::from_ymd(2018, 8, 8)); - assert_eq!(ymwd(2018, 8, Weekday::Sun, 2), NaiveDate::from_ymd(2018, 8, 12)); - assert_eq!(ymwd(2018, 8, Weekday::Thu, 3), NaiveDate::from_ymd(2018, 8, 16)); - assert_eq!(ymwd(2018, 8, Weekday::Thu, 4), NaiveDate::from_ymd(2018, 8, 23)); - assert_eq!(ymwd(2018, 8, Weekday::Thu, 5), NaiveDate::from_ymd(2018, 8, 30)); - assert_eq!(ymwd(2018, 8, Weekday::Fri, 5), NaiveDate::from_ymd(2018, 8, 31)); - // assert_eq!(ymwd(2018, 8, Weekday::Sat, 5), NaiveDate::from_ymd(2018, 9, 1)); + fn test_date_from_ymwd_opt() { + let ymwd = |y,m,w,n| NaiveDate::from_ymwd_opt(y,m,w,n); + assert_eq!(ymwd(2018, 8, Weekday::Tue, 0), None); + assert_eq!(ymwd(2018, 8, Weekday::Wed, 1), Some(NaiveDate::from_ymd(2018, 8, 1))); + assert_eq!(ymwd(2018, 8, Weekday::Thu, 1), Some(NaiveDate::from_ymd(2018, 8, 2))); + assert_eq!(ymwd(2018, 8, Weekday::Sun, 1), Some(NaiveDate::from_ymd(2018, 8, 5))); + assert_eq!(ymwd(2018, 8, Weekday::Mon, 1), Some(NaiveDate::from_ymd(2018, 8, 6))); + assert_eq!(ymwd(2018, 8, Weekday::Tue, 1), Some(NaiveDate::from_ymd(2018, 8, 7))); + assert_eq!(ymwd(2018, 8, Weekday::Wed, 2), Some(NaiveDate::from_ymd(2018, 8, 8))); + assert_eq!(ymwd(2018, 8, Weekday::Sun, 2), Some(NaiveDate::from_ymd(2018, 8, 12))); + assert_eq!(ymwd(2018, 8, Weekday::Thu, 3), Some(NaiveDate::from_ymd(2018, 8, 16))); + assert_eq!(ymwd(2018, 8, Weekday::Thu, 4), Some(NaiveDate::from_ymd(2018, 8, 23))); + assert_eq!(ymwd(2018, 8, Weekday::Thu, 5), Some(NaiveDate::from_ymd(2018, 8, 30))); + assert_eq!(ymwd(2018, 8, Weekday::Fri, 5), Some(NaiveDate::from_ymd(2018, 8, 31))); + assert_eq!(ymwd(2018, 8, Weekday::Sat, 5), None); } #[test] From 5d16648df4a49a3d6cac411a973985b7d5f69ca2 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Mon, 23 Dec 2019 17:33:44 -0500 Subject: [PATCH 3/3] rename from_ymwd -> from_weekday_of_month --- CHANGELOG.md | 2 +- src/naive/date.rs | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f22a3b..41c1e89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ Versions with only mechnical changes will be omitted from the following list. ### Features -* Added `NaiveDate::from_ymwd{,_opt}` for getting eg. the 2nd Friday of March 2017. +* Added `NaiveDate::from_weekday_of_month{,_opt}` for getting eg. the 2nd Friday of March 2017. ## 0.4.5 diff --git a/src/naive/date.rs b/src/naive/date.rs index a7005fd..ecf5f27 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -409,7 +409,7 @@ impl NaiveDate { /// Makes a new `NaiveDate` by counting the number of occurances of a particular day-of-week /// since the beginning of the given month. For instance, if you want the 2nd Friday of March - /// 2017, you would use `NaiveDate::from_ymwd(2017, 3, Weekday::Fri, 2)`. + /// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. /// /// # Panics /// @@ -423,32 +423,32 @@ impl NaiveDate { /// ~~~~ /// use chrono::{NaiveDate, Weekday}; /// - /// let from_ymwd = NaiveDate::from_ymwd; + /// let from_weekday_of_month = NaiveDate::from_weekday_of_month; /// let from_ymd = NaiveDate::from_ymd; /// - /// assert_eq!(from_ymwd(2018, 8, Weekday::Wed, 1), from_ymd(2018, 8, 1)); - /// assert_eq!(from_ymwd(2018, 8, Weekday::Fri, 1), from_ymd(2018, 8, 3)); - /// assert_eq!(from_ymwd(2018, 8, Weekday::Tue, 2), from_ymd(2018, 8, 14)); - /// assert_eq!(from_ymwd(2018, 8, Weekday::Fri, 4), from_ymd(2018, 8, 24)); - /// assert_eq!(from_ymwd(2018, 8, Weekday::Fri, 5), from_ymd(2018, 8, 31)); + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Wed, 1), from_ymd(2018, 8, 1)); + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 1), from_ymd(2018, 8, 3)); + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Tue, 2), from_ymd(2018, 8, 14)); + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 4), from_ymd(2018, 8, 24)); + /// assert_eq!(from_weekday_of_month(2018, 8, Weekday::Fri, 5), from_ymd(2018, 8, 31)); /// ~~~~ - pub fn from_ymwd(year: i32, month: u32, weekday: Weekday, n: u8) -> NaiveDate { - NaiveDate::from_ymwd_opt(year, month, weekday, n).expect("out-of-range date") + pub fn from_weekday_of_month(year: i32, month: u32, weekday: Weekday, n: u8) -> NaiveDate { + NaiveDate::from_weekday_of_month_opt(year, month, weekday, n).expect("out-of-range date") } /// Makes a new `NaiveDate` by counting the number of occurances of a particular day-of-week /// since the beginning of the given month. For instance, if you want the 2nd Friday of March - /// 2017, you would use `NaiveDate::from_ymwd(2017, 3, Weekday::Fri, 2)`. `n` is 1-indexed. + /// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. `n` is 1-indexed. /// /// ~~~~ /// use chrono::{NaiveDate, Weekday}; - /// assert_eq!(NaiveDate::from_ymwd_opt(2017, 3, Weekday::Fri, 2), + /// assert_eq!(NaiveDate::from_weekday_of_month_opt(2017, 3, Weekday::Fri, 2), /// NaiveDate::from_ymd_opt(2017, 3, 10)) /// ~~~~ /// /// Returns `None` if `n` out-of-range; ie. if `n` is larger than the number of `weekday` in /// `month` (eg. the 6th Friday of March 2017), or if `n == 0`. - pub fn from_ymwd_opt(year: i32, month: u32, weekday: Weekday, n: u8) -> Option { + pub fn from_weekday_of_month_opt(year: i32, month: u32, weekday: Weekday, n: u8) -> Option { if n == 0 { return None; } let first = NaiveDate::from_ymd(year, month, 1).weekday(); let first_to_dow = (7 + weekday.number_from_monday() - first.number_from_monday()) % 7; @@ -1873,8 +1873,8 @@ mod tests { } #[test] - fn test_date_from_ymwd_opt() { - let ymwd = |y,m,w,n| NaiveDate::from_ymwd_opt(y,m,w,n); + fn test_date_from_weekday_of_month_opt() { + let ymwd = |y,m,w,n| NaiveDate::from_weekday_of_month_opt(y,m,w,n); assert_eq!(ymwd(2018, 8, Weekday::Tue, 0), None); assert_eq!(ymwd(2018, 8, Weekday::Wed, 1), Some(NaiveDate::from_ymd(2018, 8, 1))); assert_eq!(ymwd(2018, 8, Weekday::Thu, 1), Some(NaiveDate::from_ymd(2018, 8, 2)));