Skip to content

Commit

Permalink
Merge pull request chronotope#457 from robyoung/pr/209
Browse files Browse the repository at this point in the history
Add days and weeks iterators for `NaiveDate`
  • Loading branch information
quodlibetor authored Jul 24, 2020
2 parents 6b600e8 + bfddc1e commit 53e63c3
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 1 deletion.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ Versions with only mechanical changes will be omitted from the following list.

## 0.4.14 (unreleased)

## Improvements
### Features

* Added day and week iterators for `NaiveDate` (@gnzlbg & @robyoung)

### Improvements

* Added MIN and MAX values for `NaiveTime`, `NaiveDateTime` and `DateTime<Utc>`.

Expand Down
125 changes: 125 additions & 0 deletions src/naive/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,58 @@ impl NaiveDate {
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
}

/// Returns an iterator that steps by days until the last representable date.
///
/// # Example
///
/// ```
/// # use chrono::NaiveDate;
///
/// let expected = [
/// NaiveDate::from_ymd(2016, 2, 27),
/// NaiveDate::from_ymd(2016, 2, 28),
/// NaiveDate::from_ymd(2016, 2, 29),
/// NaiveDate::from_ymd(2016, 3, 1),
/// ];
///
/// let mut count = 0;
/// for (idx, d) in NaiveDate::from_ymd(2016, 2, 27).iter_days().take(4).enumerate() {
/// assert_eq!(d, expected[idx]);
/// count += 1;
/// }
/// assert_eq!(count, 4);
/// ```
#[inline]
pub fn iter_days(&self) -> NaiveDateDaysIterator {
NaiveDateDaysIterator { value: *self }
}

/// Returns an iterator that steps by weeks until the last representable date.
///
/// # Example
///
/// ```
/// # use chrono::NaiveDate;
///
/// let expected = [
/// NaiveDate::from_ymd(2016, 2, 27),
/// NaiveDate::from_ymd(2016, 3, 5),
/// NaiveDate::from_ymd(2016, 3, 12),
/// NaiveDate::from_ymd(2016, 3, 19),
/// ];
///
/// let mut count = 0;
/// for (idx, d) in NaiveDate::from_ymd(2016, 2, 27).iter_weeks().take(4).enumerate() {
/// assert_eq!(d, expected[idx]);
/// count += 1;
/// }
/// assert_eq!(count, 4);
/// ```
#[inline]
pub fn iter_weeks(&self) -> NaiveDateWeeksIterator {
NaiveDateWeeksIterator { value: *self }
}
}

impl Datelike for NaiveDate {
Expand Down Expand Up @@ -1511,6 +1563,63 @@ impl Sub<NaiveDate> for NaiveDate {
}
}

/// Iterator over `NaiveDate` with a step size of one day.
#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct NaiveDateDaysIterator {
value: NaiveDate,
}

impl Iterator for NaiveDateDaysIterator {
type Item = NaiveDate;

fn next(&mut self) -> Option<Self::Item> {
if self.value == MAX_DATE {
return None;
}
// current < MAX_DATE from here on:
let current = self.value;
// This can't panic because current is < MAX_DATE:
self.value = current.succ();
Some(current)
}

fn size_hint(&self) -> (usize, Option<usize>) {
let exact_size = MAX_DATE.signed_duration_since(self.value).num_days();
(exact_size as usize, Some(exact_size as usize))
}
}

impl ExactSizeIterator for NaiveDateDaysIterator {}

#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct NaiveDateWeeksIterator {
value: NaiveDate,
}

impl Iterator for NaiveDateWeeksIterator {
type Item = NaiveDate;

fn next(&mut self) -> Option<Self::Item> {
if MAX_DATE - self.value < OldDuration::weeks(1) {
return None;
}
let current = self.value;
self.value = current + OldDuration::weeks(1);
Some(current)
}

fn size_hint(&self) -> (usize, Option<usize>) {
let exact_size = MAX_DATE.signed_duration_since(self.value).num_weeks();
(exact_size as usize, Some(exact_size as usize))
}
}

impl ExactSizeIterator for NaiveDateWeeksIterator {}

// TODO: NaiveDateDaysIterator and NaiveDateWeeksIterator should implement FusedIterator,
// TrustedLen, and Step once they becomes stable.
// See: https://github.com/chronotope/chrono/issues/208

/// The `Debug` output of the naive date `d` is the same as
/// [`d.format("%Y-%m-%d")`](../format/strftime/index.html).
///
Expand Down Expand Up @@ -2270,4 +2379,20 @@ mod tests {
"2009,09,01,00,53"
);
}

#[test]
fn test_day_iterator_limit() {
assert_eq!(
NaiveDate::from_ymd(262143, 12, 29).iter_days().take(4).collect::<Vec<_>>().len(),
2
);
}

#[test]
fn test_week_iterator_limit() {
assert_eq!(
NaiveDate::from_ymd(262143, 12, 12).iter_weeks().take(4).collect::<Vec<_>>().len(),
2
);
}
}

0 comments on commit 53e63c3

Please sign in to comment.