Skip to content

Commit

Permalink
Add support for double ended days+weeks iterators
Browse files Browse the repository at this point in the history
This allows users to use `.rev()` on `.iter_days()` and `.iter_weeks()`,
in order to iterate on dates backwards.
  • Loading branch information
teobouvard authored and djc committed May 24, 2022
1 parent 8f9b08a commit 5bf8016
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -25,6 +25,7 @@ Versions with only mechanical changes will be omitted from the following list.
* Add support for microseconds timestamps serde serialization for `NaiveDateTime`.
* Add support for optional timestamps serde serialization for `NaiveDateTime`.
* Fix build for wasm32-unknown-emscripten (@yu-re-ka #593)
* Implement `DoubleEndedIterator` for `NaiveDateDaysIterator` and `NaiveDateWeeksIterator`

## 0.4.19

Expand Down
38 changes: 36 additions & 2 deletions src/naive/date.rs
Expand Up @@ -1044,7 +1044,7 @@ impl NaiveDate {
self.format_with_items(StrftimeItems::new(fmt))
}

/// Returns an iterator that steps by days until the last representable date.
/// Returns an iterator that steps by days across all representable dates.
///
/// # Example
///
Expand All @@ -1064,13 +1064,18 @@ impl NaiveDate {
/// count += 1;
/// }
/// assert_eq!(count, 4);
///
/// for d in NaiveDate::from_ymd(2016, 3, 1).iter_days().rev().take(4) {
/// count -= 1;
/// assert_eq!(d, expected[count]);
/// }
/// ```
#[inline]
pub fn iter_days(&self) -> NaiveDateDaysIterator {
NaiveDateDaysIterator { value: *self }
}

/// Returns an iterator that steps by weeks until the last representable date.
/// Returns an iterator that steps by weeks across all representable dates.
///
/// # Example
///
Expand All @@ -1090,6 +1095,11 @@ impl NaiveDate {
/// count += 1;
/// }
/// assert_eq!(count, 4);
///
/// for d in NaiveDate::from_ymd(2016, 3, 19).iter_weeks().rev().take(4) {
/// count -= 1;
/// assert_eq!(d, expected[count]);
/// }
/// ```
#[inline]
pub fn iter_weeks(&self) -> NaiveDateWeeksIterator {
Expand Down Expand Up @@ -1577,6 +1587,17 @@ impl Iterator for NaiveDateDaysIterator {

impl ExactSizeIterator for NaiveDateDaysIterator {}

impl DoubleEndedIterator for NaiveDateDaysIterator {
fn next_back(&mut self) -> Option<Self::Item> {
if self.value == MIN_DATE {
return None;
}
let current = self.value;
self.value = current.pred();
Some(current)
}
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct NaiveDateWeeksIterator {
value: NaiveDate,
Expand All @@ -1602,6 +1623,17 @@ impl Iterator for NaiveDateWeeksIterator {

impl ExactSizeIterator for NaiveDateWeeksIterator {}

impl DoubleEndedIterator for NaiveDateWeeksIterator {
fn next_back(&mut self) -> Option<Self::Item> {
if self.value - MIN_DATE < OldDuration::weeks(1) {
return None;
}
let current = self.value;
self.value = current - OldDuration::weeks(1);
Some(current)
}
}

// TODO: NaiveDateDaysIterator and NaiveDateWeeksIterator should implement FusedIterator,
// TrustedLen, and Step once they becomes stable.
// See: https://github.com/chronotope/chrono/issues/208
Expand Down Expand Up @@ -2405,10 +2437,12 @@ mod tests {
#[test]
fn test_day_iterator_limit() {
assert_eq!(NaiveDate::from_ymd(262143, 12, 29).iter_days().take(4).count(), 2);
assert_eq!(NaiveDate::from_ymd(-262144, 1, 3).iter_days().rev().take(4).count(), 2);
}

#[test]
fn test_week_iterator_limit() {
assert_eq!(NaiveDate::from_ymd(262143, 12, 12).iter_weeks().take(4).count(), 2);
assert_eq!(NaiveDate::from_ymd(-262144, 1, 15).iter_weeks().rev().take(4).count(), 2);
}
}

0 comments on commit 5bf8016

Please sign in to comment.