@@ -9,6 +9,8 @@ use crate::{Range, Tendril};
99
1010use chrono::{Datelike, Duration, NaiveDate};
1111
12+use super::Increment;
13+
1214fn ndays_in_month(year: i32, month: u32) -> u32 {
1315 // The first day of the next month...
1416 let (y, m) = if month == 12 {
@@ -29,6 +31,7 @@ fn add_days(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
2931fn add_months(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
3032 let month = date.month0() as i64 + amount;
3133 let year = date.year() + i32::try_from(month / 12).ok()?;
34+ let year = if month.is_negative() { year - 1 } else { year };
3235
3336 // Normalize month
3437 let month = month % 12;
@@ -45,7 +48,6 @@ fn add_months(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
4548
4649fn add_years(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
4750 let year = i32::try_from(date.year() as i64 + amount).ok()?;
48−
4951 let ndays = ndays_in_month(year, date.month());
5052
5153 if date.day() > ndays {
@@ -85,9 +87,8 @@ enum DateField {
8587
8688#[derive(Debug, PartialEq, Eq)]
8789pub struct DateIncrementor {
88− pub date: NaiveDate,
89− pub range: Range,
90−
90+ date: NaiveDate,
91+ range: Range,
9192 field: DateField,
9293 format: Format,
9394}
@@ -150,8 +151,10 @@ impl DateIncrementor {
150151 })
151152 })
152153 }
154+}
153155
154− pub fn incremented_text(&self, amount: i64) -> Tendril {
156+impl Increment for DateIncrementor {
157+ fn increment(&self, amount: i64) -> (Range, Tendril) {
155158 let date = match self.field {
156159 DateField::Year => add_years(self.date, amount),
157160 DateField::Month => add_months(self.date, amount),
@@ -159,15 +162,18 @@ impl DateIncrementor {
159162 }
160163 .unwrap_or(self.date);
161164
162− format!(
163− "{:04}{}{:02}{}{:02}",
164− date.year(),
165− self.format.separator,
166− date.month(),
167− self.format.separator,
168− date.day()
165+ (
166+ self.range,
167+ format!(
168+ "{:04}{}{:02}{}{:02}",
169+ date.year(),
170+ self.format.separator,
171+ date.month(),
172+ self.format.separator,
173+ date.day()
174+ )
175+ .into(),
169176 )
170− .into()
171177 }
172178}
173179
@@ -437,6 +443,8 @@ mod test {
437443 ("2020-02-29", 0, 1, "2021-03-01"),
438444 ("2020-01-31", 5, 1, "2020-02-29"),
439445 ("2020-01-20", 5, 1, "2020-02-20"),
446+ ("2021-01-01", 5, -1, "2020-12-01"),
447+ ("2021-01-31", 5, -2, "2020-11-30"),
440448 ("2020-02-28", 8, 1, "2020-02-29"),
441449 ("2021-02-28", 8, 1, "2021-03-01"),
442450 ("2021-02-28", 0, -1, "2020-02-28"),
@@ -457,7 +465,8 @@ mod test {
457465 assert_eq!(
458466 DateIncrementor::from_range(rope.slice(..), range)
459467 .unwrap()
460− .incremented_text(amount),
468+ .increment(amount)
469+ .1,
461470 expected.into()
462471 );
463472 }