1use crate::unit::{opt_unit_abbr, TimeUnit};
2use crate::{Calc, CondUnit, ExpectErr};
3use std::time::Duration;
4use winnow::ascii::{digit1, multispace0};
5use winnow::combinator::{alt, cut_err};
6use winnow::combinator::{eof, peek, repeat};
7use winnow::error::{ContextError, StrContext, StrContextValue};
8use winnow::ModalResult as WResult;
9use winnow::Parser;
10
11pub(crate) fn cond_unit1(input: &mut &str) -> WResult<CondUnit> {
12 alt(('+'.value(CondUnit::Plus), '*'.value(CondUnit::Star)))
13 .context(StrContext::Expected(StrContextValue::Description(
14 CondUnit::get_expect_val(),
15 )))
16 .parse_next(input)
17}
18
19fn opt_cond_unit(input: &mut &str) -> WResult<CondUnit> {
20 let result = cond_unit1.parse_next(input);
21 if result.is_err() {
22 multispace0.parse_next(input)?;
23 if eof::<_, ContextError>.parse_next(input).is_ok() {
24 return Ok(CondUnit::Plus);
26 }
27
28 return cut_err(peek((digit1, multispace0, opt_unit_abbr)))
29 .context(StrContext::Expected(StrContextValue::Description(
30 CondUnit::get_expect_val(),
31 )))
32 .value(CondUnit::Plus)
33 .parse_next(input);
34 }
35 result
36}
37
38pub(crate) fn parse_expr_time(input: &mut &str) -> WResult<u64> {
39 (multispace0, digit1, multispace0, opt_unit_abbr, multispace0)
40 .map(|x| (x.1, x.3))
41 .try_map(|(v, unit)| unit.duration(v))
42 .parse_next(input)
43}
44
45pub(crate) fn cond_time<'a>(input: &mut &'a str) -> WResult<Vec<(&'a str, CondUnit, TimeUnit)>> {
46 repeat(
47 0..,
48 (
49 multispace0,
50 opt_cond_unit,
51 multispace0,
52 digit1,
53 multispace0,
54 opt_unit_abbr,
57 multispace0,
58 )
59 .map(|x| (x.3, x.1, x.5)),
60 )
61 .fold(Vec::new, |mut acc: Vec<_>, item| {
62 acc.push(item);
63 acc
64 })
65 .parse_next(input)
66}
67
68pub fn parse(input: impl AsRef<str>) -> Result<Duration, String> {
69 let input = input.as_ref();
70 if input.is_empty() {
71 return Err(String::from("Empty input"));
72 }
73 #[cfg(all(feature = "no_calc", not(feature = "calc")))]
74 {
75 use crate::DError;
76
77 let d = repeat(0.., parse_expr_time)
78 .try_fold(
79 Default::default,
80 |mut acc: u64, item| -> Result<_, DError> {
81 acc = acc.checked_add(item).ok_or(DError::OverflowError)?;
82 Ok(acc)
83 },
84 )
85 .parse(input)
86 .map_err(|err| err.to_string())?;
87 return Ok(Duration::from_nanos(d));
88 }
89
90 #[cfg(feature = "calc")]
91 {
92 let (unit_time, cond_val) = (parse_expr_time, cond_time)
93 .parse(input)
94 .map_err(|e| format!("{}", e))?;
95
96 let (init_cond, init_duration) = if cond_val.is_empty() {
97 CondUnit::init()
98 } else {
99 cond_val.calc().map_err(|err| err.to_string())?
100 };
101
102 let duration = init_cond
103 .calc(unit_time, init_duration)
104 .map_err(|err| err.to_string())?;
105 Ok(duration)
106 }
107}
108
109#[cfg(test)]
110#[allow(clippy::identity_op)]
111mod tests {
112 use super::*;
113 use crate::{catch_err, unit::TimeUnit, CondUnit};
114
115 #[test]
116 fn test_parse_expr_time() {
117 let (input, val) = parse_expr_time.parse_peek("123m").unwrap();
118 assert_eq!(input, "");
119 assert_eq!(val, 7380000000000);
120 }
121
122 #[test]
123 fn test_cond_unit() {
124 let (input, format) = cond_unit1.parse_peek("*123").unwrap();
125 assert_eq!(input, "123");
126 assert_eq!(format, CondUnit::Star);
127 }
128
129 #[test]
130 fn test_cond_time() {
131 let (input, out) = cond_time.parse_peek(" * 60").unwrap();
132 assert_eq!(input, "");
133 assert_eq!(out, vec![("60", CondUnit::Star, TimeUnit::Second)]);
134 }
135
136 #[test]
137 fn test_cond_time2() {
138 let (input, out) = cond_time.parse_peek(" * 60*30").unwrap();
139 assert_eq!(input, "");
140 assert_eq!(
141 out,
142 vec![
143 ("60", CondUnit::Star, TimeUnit::Second),
144 ("30", CondUnit::Star, TimeUnit::Second),
145 ]
146 );
147 }
148
149 #[test]
150 fn test_duration_parse0() {
151 let duration = parse("0").unwrap();
152 assert_eq!(duration, Duration::new(0, 0));
153
154 let duration = parse("0 ").unwrap();
155 assert_eq!(duration, Duration::new(0, 0));
156
157 let duration = parse(" 0 ").unwrap();
158 assert_eq!(duration, Duration::new(0, 0));
159
160 let duration = parse("1").unwrap();
161 assert_eq!(duration, Duration::new(1, 0));
162
163 let duration = parse("0m").unwrap();
164 assert_eq!(duration, Duration::new(0, 0));
165
166 let duration = parse("1hr").unwrap();
167 assert_eq!(duration, Duration::new(3600, 0));
168
169 let duration = parse("1m+31").unwrap();
170 assert_eq!(duration, Duration::new(91, 0));
171
172 let duration = parse("1m31").unwrap();
173 assert_eq!(duration, Duration::new(91, 0));
174
175 let duration = parse("1m31s").unwrap();
176 assert_eq!(duration, Duration::new(91, 0));
177
178 let duration = parse("1m*60").unwrap();
179 assert_eq!(duration, Duration::new(3600, 0));
180
181 let duration = parse("1m*60*20").unwrap();
182 assert_eq!(duration, Duration::new(72000, 0));
183
184 let duration = parse("1m+60+24").unwrap();
185 assert_eq!(duration, Duration::new(144, 0));
186
187 let duration = parse("1m+60+24 ").unwrap();
188 assert_eq!(duration, Duration::new(144, 0));
189
190 let duration = parse(" 1m + 60 + 24 ").unwrap();
191 assert_eq!(duration, Duration::new(144, 0))
192 }
193
194 #[cfg(feature = "cn_unit")]
195 #[test]
196 fn test_parse_unit_cn() {
197 let duration = parse("1年").unwrap();
198 assert_eq!(duration, Duration::new(31536000, 0));
199
200 let duration = parse("1月").unwrap();
201 assert_eq!(duration, Duration::new(2592000, 0));
202
203 let duration = parse("1周").unwrap();
204 assert_eq!(duration, Duration::new(604800, 0));
205
206 let duration = parse("1日").unwrap();
207 assert_eq!(duration, Duration::new(86400, 0));
208
209 let duration = parse("1天").unwrap();
210 assert_eq!(duration, Duration::new(86400, 0));
211
212 let duration = parse("1时").unwrap();
213 assert_eq!(duration, Duration::new(3600, 0));
214
215 let duration = parse("1分").unwrap();
216 assert_eq!(duration, Duration::new(60, 0));
217
218 let duration = parse("1秒").unwrap();
219 assert_eq!(duration, Duration::new(1, 0));
220
221 let duration = parse("1毫秒").unwrap();
222 assert_eq!(duration, Duration::new(0, 1 * 1000 * 1000));
223
224 let duration = parse("1微秒").unwrap();
225 assert_eq!(duration, Duration::new(0, 1 * 1000));
226
227 let duration = parse("1纳秒").unwrap();
228 assert_eq!(duration, Duration::new(0, 1));
229
230 let duration = parse("1年 2日").unwrap();
231 assert_eq!(duration, Duration::new(31708800, 0));
232
233 let duration = parse("1分31秒").unwrap();
234 assert_eq!(duration, Duration::new(91, 0));
235
236 let duration = parse("1分+31秒").unwrap();
237 assert_eq!(duration, Duration::new(91, 0));
238
239 let duration = parse("1分+31秒+2毫秒+3纳秒").unwrap();
240 assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));
241
242 let duration = parse(" 1分+ 31秒 + 2毫秒+ 3纳秒 ").unwrap();
243 assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));
244 }
245
246 #[test]
247 fn test_duration_err() {
248 assert_eq!(
249 catch_err!(parse("0m+3-5")),
250 r#"
2510m+3-5
252 ^
253expected ["y", "mon", "w", "d", "h", "m", "s", "ms", "µs", "us", "ns"]"#
254 .trim()
255 );
256
257 assert_eq!(
258 catch_err!(parse("0mxyz")),
259 r#"
2600mxyz
261 ^
262expected ["y", "mon", "w", "d", "h", "m", "s", "ms", "µs", "us", "ns"]"#
263 .trim()
264 );
265
266 assert_eq!(
267 catch_err!(parse("3ms-2ms")),
268 r#"
2693ms-2ms
270 ^
271expected ['+', '*']"#
272 .trim()
273 );
274
275 assert_eq!(catch_err!(parse("")), "Empty input");
276 }
277
278 #[test]
279 fn test_parse() {
280 let duration = parse("1d").unwrap();
281 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
282
283 let duration = parse(" 1d").unwrap();
284 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
285
286 let duration = parse("1d ").unwrap();
287 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
288
289 let duration = parse(" 1d ").unwrap();
290 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
291
292 let duration = parse("3m+31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
294
295 let duration = parse("3m + 31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
297
298 let duration = parse("3m + 13s + 29ms").unwrap();
299 assert_eq!(duration, Duration::new(193, 29 * 1000 * 1000 + 0 + 0));
300
301 let duration = parse("3m + 1s + 29ms +17µs").unwrap();
302 assert_eq!(
303 duration,
304 Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0)
305 );
306
307 let duration = parse("1m*10").unwrap(); assert_eq!(duration, Duration::new(600, 0));
309
310 let duration = parse("1m*10ms").unwrap();
311 assert_eq!(duration, Duration::new(0, 600 * 1000 * 1000));
312
313 let duration = parse("1m * 1ns").unwrap();
314 assert_eq!(duration, Duration::new(0, 60));
315
316 let duration = parse("1m * 1m").unwrap();
317 assert_eq!(duration, Duration::new(3600, 0));
318
319 let duration = parse("3m + 31").unwrap();
320 assert_eq!(duration, Duration::new(211, 0));
321
322 let duration = parse("3m 31s").unwrap();
323 assert_eq!(duration, Duration::new(211, 0));
324
325 let duration = parse("3m31s0ns").unwrap();
326 assert_eq!(duration, Duration::new(211, 0));
327
328 let duration = parse(" 3m 31s 0ns ").unwrap();
329 assert_eq!(duration, Duration::new(211, 0));
330
331 let duration = parse("1d2h3min4s").unwrap();
332 assert_eq!(duration, Duration::new(93784, 0));
333 }
334
335 #[test]
336 fn test_overflow_plus() {
337 assert_eq!(
338 catch_err!(parse("10000000000000000y+60")),
339 r#"
34010000000000000000y+60
341^
342overflow error"#
343 .trim()
344 .to_string()
345 );
346 }
347
348 #[test]
349 fn test_max_mul() {
350 let duration = parse("580y*1").unwrap();
351 assert_eq!(
352 duration,
353 std::time::Duration::from_millis(18290880000) * 1000
354 );
355 }
356
357 #[test]
358 fn test_overflow_mul() {
359 let err = parse("580y*2").err().unwrap();
360 assert_eq!(err, "overflow error");
361 }
362
363 #[test]
364 fn test_parse_optional_spaces() {
365 let duration = parse("1 d").unwrap();
366 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
367
368 let duration = parse("3 m+31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
370
371 let duration = parse("3 m + 31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
373
374 let duration = parse("3 m + 13 s + 29 ms").unwrap();
375 assert_eq!(duration, Duration::new(193, 29 * 1000 * 1000 + 0 + 0));
376
377 let duration = parse("3 m + 1 s + 29 ms +17µs").unwrap();
378 assert_eq!(
379 duration,
380 Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0)
381 );
382
383 let duration = parse("1 m*10").unwrap(); assert_eq!(duration, Duration::new(600, 0));
385
386 let duration = parse("1 m*10 ms").unwrap();
387 assert_eq!(duration, Duration::new(0, 600 * 1000 * 1000));
388
389 let duration = parse("1 m * 1ns").unwrap();
390 assert_eq!(duration, Duration::new(0, 60));
391
392 let duration = parse("1 m * 1 m").unwrap();
393 assert_eq!(duration, Duration::new(3600, 0));
394
395 let duration = parse("3 m + 31").unwrap();
396 assert_eq!(duration, Duration::new(211, 0));
397
398 let duration = parse("3 m 31 s").unwrap();
399 assert_eq!(duration, Duration::new(211, 0));
400
401 let duration = parse("3 m31 s0 ns").unwrap();
402 assert_eq!(duration, Duration::new(211, 0));
403
404 let duration = parse(" 3 m 31 s 0 ns ").unwrap();
405 assert_eq!(duration, Duration::new(211, 0));
406
407 let duration = parse("1 d2 h3 min 4s").unwrap();
408 assert_eq!(duration, Duration::new(93784, 0));
409 }
410}
411
412#[cfg(all(test, feature = "chrono"))]
413mod chrono_tests {
414 use crate::{
415 after_naive_date, after_naive_date_time, before_naive_date, before_naive_date_time,
416 parse_chrono,
417 };
418 use chrono::{Datelike, Utc};
419
420 #[test]
421 fn test_parse_chrono() {
422 use chrono::Duration;
423 let duration = parse_chrono("1m+60+24 ").unwrap();
424 assert_eq!(duration, Duration::seconds(144))
425 }
426
427 #[test]
428 fn test_after_naive_date_time() {
429 let date = Utc::now().naive_utc().date();
430 let jd = date.num_days_from_ce() + 180;
431 let date = after_naive_date_time("180d").unwrap();
432 assert_eq!(date.num_days_from_ce(), jd)
433 }
434
435 #[test]
436 fn test_after_naive_date() {
437 let date = Utc::now().naive_utc().date();
438 let jd = date.num_days_from_ce() + 180;
439 let date = after_naive_date("180d").unwrap();
440 assert_eq!(date.num_days_from_ce(), jd)
441 }
442
443 #[test]
444 fn test_before_naive_date_time() {
445 let date = Utc::now().naive_utc().date();
446 let jd = date.num_days_from_ce() - 180;
447 let date = before_naive_date_time("180d").unwrap();
448 assert_eq!(date.num_days_from_ce(), jd)
449 }
450
451 #[test]
452 fn test_before_naive_date() {
453 let date = Utc::now().naive_utc().date();
454 let jd = date.num_days_from_ce() - 180;
455 let date = before_naive_date("180d").unwrap();
456 assert_eq!(date.num_days_from_ce(), jd)
457 }
458}
459
460#[cfg(all(test, feature = "time"))]
461mod time_tests {
462 use crate::parse_time;
463 use time::Duration;
464
465 #[test]
466 fn test_parse_time() {
467 let duration = parse_time("1m+60+24 ").unwrap();
468 assert_eq!(duration, Duration::seconds(144))
469 }
470}