@@ -1,12 +1,61 @@
1−use gregorian::{Date, DateResultExt};
2use regex::Regex;
1use regex::Regex;
4use std::borrow::Cow;
3use std::borrow::Cow;
6use ropey::RopeSlice;
6use ropey::RopeSlice;
8use crate::{Range, Tendril};
8use crate::{Range, Tendril};
10+use chrono::{Datelike, Duration, NaiveDate};
12+fn ndays_in_month(year: i32, month: u32) -> u32 {
13+ // The first day of the next month...
14+ let (y, m) = if month == 12 {
19+ let d = NaiveDate::from_ymd(y, m, 1);
21+ // ...is preceded by the last day of the original month.
25+fn add_days(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
26+ date.checked_add_signed(Duration::days(amount))
29+fn add_months(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
30+ let month = date.month0() as i64 + amount;
31+ let year = date.year() + i32::try_from(month / 12).ok()?;
34+ let month = month % 12;
35+ let month = if month.is_negative() {
41+ let day = cmp::min(date.day(), ndays_in_month(year, month));
43+ Some(NaiveDate::from_ymd(year, month, day))
46+fn add_years(date: NaiveDate, amount: i64) -> Option<NaiveDate> {
47+ let year = i32::try_from(date.year() as i64 + amount).ok()?;
49+ let ndays = ndays_in_month(year, date.month());
51+ if date.day() > ndays {
52+ let d = NaiveDate::from_ymd(year, date.month(), ndays);
10#[derive(Copy, Clone, Debug, PartialEq, Eq)]
59#[derive(Copy, Clone, Debug, PartialEq, Eq)]
11struct Format {
60struct Format {
12 regex: &'static str,
61 regex: &'static str,
@@ -36,7 +85,7 @@ enum DateField {
37#[derive(Debug, PartialEq, Eq)]
86#[derive(Debug, PartialEq, Eq)]
38pub struct DateIncrementor {
87pub struct DateIncrementor {
39− pub date: Date,
88+ pub date: NaiveDate,
40 pub range: Range,
89 pub range: Range,
42 field: DateField,
91 field: DateField,
@@ -87,12 +136,11 @@ impl DateIncrementor {
87 return None;
136 return None;
90− let date = Date::new(
139+ let date = NaiveDate::from_ymd_opt(
91− year.as_str().parse::<i16>().ok()?,
140+ year.as_str().parse::<i32>().ok()?,
92− month.as_str().parse::<u8>().ok()?,
141+ month.as_str().parse::<u32>().ok()?,
93− day.as_str().parse::<u8>().ok()?,
142+ day.as_str().parse::<u32>().ok()?,
97 Some(DateIncrementor {
145 Some(DateIncrementor {
@@ -105,22 +153,17 @@ impl DateIncrementor {
106 pub fn incremented_text(&self, amount: i64) -> Tendril {
154 pub fn incremented_text(&self, amount: i64) -> Tendril {
107 let date = match self.field {
155 let date = match self.field {
108− DateField::Year => self
156+ DateField::Year => add_years(self.date, amount),
110− .add_years(amount.try_into().unwrap_or(0))
112− DateField::Month => self
157+ DateField::Month => add_months(self.date, amount),
114− .add_months(amount.try_into().unwrap_or(0))
116− DateField::Day => self.date.add_days(amount.try_into().unwrap_or(0)),
158+ DateField::Day => add_days(self.date, amount),
160+ .unwrap_or(self.date);
120 "{:04}{}{:02}{}{:02}",
163 "{:04}{}{:02}{}{:02}",
121 date.year(),
164 date.year(),
122 self.format.separator,
165 self.format.separator,
123− date.month().to_number(),
166+ date.month(),
124 self.format.separator,
167 self.format.separator,
125 date.day()
168 date.day()
@@ -142,7 +185,7 @@ mod test {
142 assert_eq!(
185 assert_eq!(
143 DateIncrementor::from_range(rope.slice(..), range),
186 DateIncrementor::from_range(rope.slice(..), range),
144 Some(DateIncrementor {
187 Some(DateIncrementor {
145− date: Date::new(2021, 11, 15).unwrap(),
188+ date: NaiveDate::from_ymd(2021, 11, 15),
146 range: Range::new(0, 10),
189 range: Range::new(0, 10),
147 field: DateField::Year,
190 field: DateField::Year,
148 format: FORMATS[0],
191 format: FORMATS[0],
@@ -160,7 +203,7 @@ mod test {
160 assert_eq!(
203 assert_eq!(
161 DateIncrementor::from_range(rope.slice(..), range),
204 DateIncrementor::from_range(rope.slice(..), range),
162 Some(DateIncrementor {
205 Some(DateIncrementor {
163− date: Date::new(2021, 11, 15).unwrap(),
206+ date: NaiveDate::from_ymd(2021, 11, 15),
164 range: Range::new(0, 10),
207 range: Range::new(0, 10),
165 field: DateField::Month,
208 field: DateField::Month,
166 format: FORMATS[0],
209 format: FORMATS[0],
@@ -178,7 +221,7 @@ mod test {
178 assert_eq!(
221 assert_eq!(
179 DateIncrementor::from_range(rope.slice(..), range),
222 DateIncrementor::from_range(rope.slice(..), range),
180 Some(DateIncrementor {
223 Some(DateIncrementor {
181− date: Date::new(2021, 11, 15).unwrap(),
224+ date: NaiveDate::from_ymd(2021, 11, 15),
182 range: Range::new(0, 10),
225 range: Range::new(0, 10),
183 field: DateField::Day,
226 field: DateField::Day,
184 format: FORMATS[0],
227 format: FORMATS[0],
@@ -206,7 +249,7 @@ mod test {
206 assert_eq!(
249 assert_eq!(
207 DateIncrementor::from_range(rope.slice(..), range),
250 DateIncrementor::from_range(rope.slice(..), range),
208 Some(DateIncrementor {
251 Some(DateIncrementor {
209− date: Date::new(2021, 11, 15).unwrap(),
252+ date: NaiveDate::from_ymd(2021, 11, 15),
210 range: Range::new(0, 10),
253 range: Range::new(0, 10),
211 field: DateField::Year,
254 field: DateField::Year,
212 format: FORMATS[1],
255 format: FORMATS[1],
@@ -224,7 +267,7 @@ mod test {
224 assert_eq!(
267 assert_eq!(
225 DateIncrementor::from_range(rope.slice(..), range),
268 DateIncrementor::from_range(rope.slice(..), range),
226 Some(DateIncrementor {
269 Some(DateIncrementor {
227− date: Date::new(2021, 11, 15).unwrap(),
270+ date: NaiveDate::from_ymd(2021, 11, 15),
228 range: Range::new(0, 10),
271 range: Range::new(0, 10),
229 field: DateField::Month,
272 field: DateField::Month,
230 format: FORMATS[1],
273 format: FORMATS[1],
@@ -242,7 +285,7 @@ mod test {
242 assert_eq!(
285 assert_eq!(
243 DateIncrementor::from_range(rope.slice(..), range),
286 DateIncrementor::from_range(rope.slice(..), range),
244 Some(DateIncrementor {
287 Some(DateIncrementor {
245− date: Date::new(2021, 11, 15).unwrap(),
288+ date: NaiveDate::from_ymd(2021, 11, 15),
246 range: Range::new(0, 10),
289 range: Range::new(0, 10),
247 field: DateField::Day,
290 field: DateField::Day,
248 format: FORMATS[1],
291 format: FORMATS[1],
@@ -268,7 +311,7 @@ mod test {
268 assert_eq!(
311 assert_eq!(
269 DateIncrementor::from_range(rope.slice(..), range),
312 DateIncrementor::from_range(rope.slice(..), range),
270 Some(DateIncrementor {
313 Some(DateIncrementor {
271− date: Date::new(2021, 11, 15).unwrap(),
314+ date: NaiveDate::from_ymd(2021, 11, 15),
272 range: Range::new(3, 13),
315 range: Range::new(3, 13),
273 field: DateField::Year,
316 field: DateField::Year,
274 format: FORMATS[0],
317 format: FORMATS[0],
@@ -283,7 +326,7 @@ mod test {
283 assert_eq!(
326 assert_eq!(
284 DateIncrementor::from_range(rope.slice(..), range),
327 DateIncrementor::from_range(rope.slice(..), range),
285 Some(DateIncrementor {
328 Some(DateIncrementor {
286− date: Date::new(2021, 11, 15).unwrap(),
329+ date: NaiveDate::from_ymd(2021, 11, 15),
287 range: Range::new(8, 18),
330 range: Range::new(8, 18),
288 field: DateField::Year,
331 field: DateField::Year,
289 format: FORMATS[0],
332 format: FORMATS[0],
@@ -298,7 +341,7 @@ mod test {
298 assert_eq!(
341 assert_eq!(
299 DateIncrementor::from_range(rope.slice(..), range),
342 DateIncrementor::from_range(rope.slice(..), range),
300 Some(DateIncrementor {
343 Some(DateIncrementor {
301− date: Date::new(2021, 11, 15).unwrap(),
344+ date: NaiveDate::from_ymd(2021, 11, 15),
302 range: Range::new(12, 22),
345 range: Range::new(12, 22),
303 field: DateField::Year,
346 field: DateField::Year,
304 format: FORMATS[0],
347 format: FORMATS[0],
@@ -327,7 +370,7 @@ mod test {
327 assert_eq!(
370 assert_eq!(
328 DateIncrementor::from_range(rope.slice(..), range),
371 DateIncrementor::from_range(rope.slice(..), range),
329 Some(DateIncrementor {
372 Some(DateIncrementor {
330− date: Date::new(2021, 11, 15).unwrap(),
373+ date: NaiveDate::from_ymd(2021, 11, 15),
331 range: Range::new(0, 10),
374 range: Range::new(0, 10),
332 field: DateField::Year,
375 field: DateField::Year,
333 format: FORMATS[0],
376 format: FORMATS[0],
@@ -342,7 +385,7 @@ mod test {
342 assert_eq!(
385 assert_eq!(
343 DateIncrementor::from_range(rope.slice(..), range),
386 DateIncrementor::from_range(rope.slice(..), range),
344 Some(DateIncrementor {
387 Some(DateIncrementor {
345− date: Date::new(2021, 11, 15).unwrap(),
388+ date: NaiveDate::from_ymd(2021, 11, 15),
346 range: Range::new(0, 10),
389 range: Range::new(0, 10),
347 field: DateField::Month,
390 field: DateField::Month,
348 format: FORMATS[0],
391 format: FORMATS[0],