@@ -67,27 +67,16 @@ impl DateTimeIncrementor {
6767 let has_date = format.fields.iter().any(|f| f.unit.is_date());
6868 let has_time = format.fields.iter().any(|f| f.unit.is_time());
6969
70+ let date_time = &text[date_time.start()..date_time.end()];
7071 let date_time = match (has_date, has_time) {
71− (true, true) => NaiveDateTime::parse_from_str(
72− &text[date_time.start()..date_time.end()],
73− format.fmt,
74− )
75− .ok()?,
72+ (true, true) => NaiveDateTime::parse_from_str(date_time, format.fmt).ok()?,
7673 (true, false) => {
77− let date = NaiveDate::parse_from_str(
78− &text[date_time.start()..date_time.end()],
79− format.fmt,
80− )
81− .ok()?;
74+ let date = NaiveDate::parse_from_str(date_time, format.fmt).ok()?;
8275
8376 date.and_hms(0, 0, 0)
8477 }
8578 (false, true) => {
86− let time = NaiveTime::parse_from_str(
87− &text[date_time.start()..date_time.end()],
88− format.fmt,
89− )
90− .ok()?;
79+ let time = NaiveTime::parse_from_str(date_time, format.fmt).ok()?;
9180
9281 NaiveDate::from_ymd(0, 1, 1).and_time(time)
9382 }
@@ -123,22 +112,22 @@ impl Increment for DateTimeIncrementor {
123112
124113static FORMATS: Lazy<Vec<Format>> = Lazy::new(|| {
125114 vec![
126− Format::new("%Y-%m-%d %H:%M:%S"), // 2021-11-24 07:12:23
127− Format::new("%Y/%m/%d %H:%M:%S"), // 2021/11/24 07:12:23
128− Format::new("%Y-%m-%d %H:%M"), // 2021-11-24 07:12
129− Format::new("%Y/%m/%d %H:%M"), // 2021/11/24 07:12
130− Format::new("%Y-%m-%d"), // 2021-11-24
131− Format::new("%Y/%m/%d"), // 2021/11/24
132− Format::new("%a %b %d %Y"), // Wed Nov 24 2021
133− Format::new("%d-%b-%Y"), // 24-Nov-2021
134− Format::new("%Y %b %d"), // 2021 Nov 24
135− Format::new("%b %d, %Y"), // Nov 24, 2021
136− Format::new("%-I:%M:%S %P"), // 7:21:53 am
137− Format::new("%-I:%M %P"), // 7:21 am
138− Format::new("%-I:%M:%S %p"), // 7:21:53 AM
139− Format::new("%-I:%M %p"), // 7:21 AM
140− Format::new("%H:%M:%S"), // 23:24:23
141− Format::new("%H:%M"), // 23:24
115+ Format::new("%Y-%m-%d %H:%M:%S").unwrap(), // 2021-11-24 07:12:23
116+ Format::new("%Y/%m/%d %H:%M:%S").unwrap(), // 2021/11/24 07:12:23
117+ Format::new("%Y-%m-%d %H:%M").unwrap(), // 2021-11-24 07:12
118+ Format::new("%Y/%m/%d %H:%M").unwrap(), // 2021/11/24 07:12
119+ Format::new("%Y-%m-%d").unwrap(), // 2021-11-24
120+ Format::new("%Y/%m/%d").unwrap(), // 2021/11/24
121+ Format::new("%a %b %d %Y").unwrap(), // Wed Nov 24 2021
122+ Format::new("%d-%b-%Y").unwrap(), // 24-Nov-2021
123+ Format::new("%Y %b %d").unwrap(), // 2021 Nov 24
124+ Format::new("%b %d, %Y").unwrap(), // Nov 24, 2021
125+ Format::new("%-I:%M:%S %P").unwrap(), // 7:21:53 am
126+ Format::new("%-I:%M %P").unwrap(), // 7:21 am
127+ Format::new("%-I:%M:%S %p").unwrap(), // 7:21:53 AM
128+ Format::new("%-I:%M %p").unwrap(), // 7:21 AM
129+ Format::new("%H:%M:%S").unwrap(), // 23:24:23
130+ Format::new("%H:%M").unwrap(), // 23:24
142131 ]
143132});
144133
@@ -151,55 +140,65 @@ struct Format {
151140}
152141
153142impl Format {
154− fn new(fmt: &'static str) -> Self {
143+ fn new(fmt: &'static str) -> Result<Self, FormatError> {
155144 let mut remaining = fmt;
156145 let mut fields = Vec::new();
157146 let mut regex = String::new();
158147 let mut max_len = 0;
159148
160149 while let Some(i) = remaining.find('%') {
161− let mut chars = remaining[i + 1..].chars();
162− let spec_len = if let Some(c) = chars.next() {
163− if c == '-' {
164− if chars.next().is_some() {
165− 2
166− } else {
167− 0
168− }
150+ let after = &remaining[i + 1..];
151+ let mut chars = after.chars();
152+ let c = chars
153+ .next()
154+ .ok_or(FormatError::UnexpectedEndOfFormatString)?;
155+
156+ let spec_len = if c == '-' {
157+ if let Some(c) = chars.next() {
158+ 1 + c.len_utf8()
169159 } else {
170− 1
160+ return Err(FormatError::UnexpectedEndOfFormatString);
171161 }
172162 } else {
173− 0
163+ c.len_utf8()
174164 };
175165
176166 if i < remaining.len() - spec_len {
177− let specifier = &remaining[i + 1..i + 1 + spec_len];
167+ let specifier = &after[..spec_len];
178168 if let Some(field) = DateField::from_specifier(specifier) {
179169 fields.push(field);
180170 max_len += field.max_len + remaining[..i].len();
181171 regex += &remaining[..i];
182172 regex += &format!("({})", field.regex);
183− remaining = &remaining[i + spec_len + 1..];
173+ remaining = &after[spec_len..];
184174 } else {
185− regex += &remaining[..=i];
175+ return Err(FormatError::UnsupportedSpecifier(
176+ &remaining[i..i + 1 + spec_len],
177+ ));
186178 }
187179 } else {
188− regex += remaining;
180+ return Err(FormatError::UnexpectedEndOfFormatString);
189181 }
190182 }
191183
192− let regex = Regex::new(®ex).unwrap();
184+ let regex = Regex::new(®ex).map_err(FormatError::Regex)?;
193185
194− Self {
186+ Ok(Self {
195187 fmt,
196188 fields,
197189 regex,
198190 max_len,
199− }
191+ })
200192 }
201193}
202194
195+#[derive(Clone, Debug)]
196+enum FormatError {
197+ UnexpectedEndOfFormatString,
198+ UnsupportedSpecifier(&'static str),
199+ Regex(regex::Error),
200+}
201+
203202impl PartialEq for Format {
204203 fn eq(&self, other: &Self) -> bool {
205204 self.fmt == other.fmt && self.fields == other.fields && self.max_len == other.max_len
@@ -348,10 +347,11 @@ fn add_months(date_time: NaiveDateTime, amount: i64) -> Option<NaiveDateTime> {
348347 // Normalize month
349348 let month = month % 12;
350349 let month = if month.is_negative() {
351− month + 13
350+ month + 12
352351 } else {
353− month + 1
354− } as u32;
352+ month
353+ } as u32
354+ + 1;
355355
356356 let day = cmp::min(date_time.day(), ndays_in_month(year, month));
357357