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
74 #[cfg(feature = "no_calc")]
75 {
76 use crate::DError;
77
78 let d = repeat(0.., parse_expr_time)
79 .try_fold(
80 Default::default,
81 |mut acc: u64, item| -> Result<_, DError> {
82 acc = acc.checked_add(item).ok_or(DError::OverflowError)?;
83 Ok(acc)
84 },
85 )
86 .parse(input)
87 .map_err(|err| err.to_string())?;
88 Ok(Duration::from_nanos(d))
89 }
90
91 #[cfg(not(feature = "no_calc"))]
92 {
93 let (unit_time, cond_val) = (parse_expr_time, cond_time)
94 .parse(input)
95 .map_err(|e| format!("{}", e))?;
96
97 let (init_cond, init_duration) = if cond_val.is_empty() {
98 CondUnit::init()
99 } else {
100 cond_val.calc().map_err(|err| err.to_string())?
101 };
102
103 let duration = init_cond
104 .calc(unit_time, init_duration)
105 .map_err(|err| err.to_string())?;
106 Ok(duration)
107 }
108}
109
110#[cfg(test)]
111#[allow(clippy::identity_op)]
112mod tests {
113 use super::*;
114 use crate::{catch_err, unit::TimeUnit, CondUnit};
115
116 #[test]
117 fn test_parse_expr_time() {
118 let (input, val) = parse_expr_time.parse_peek("123m").unwrap();
119 assert_eq!(input, "");
120 assert_eq!(val, 7380000000000);
121 }
122
123 #[test]
124 fn test_cond_unit() {
125 let (input, format) = cond_unit1.parse_peek("*123").unwrap();
126 assert_eq!(input, "123");
127 assert_eq!(format, CondUnit::Star);
128 }
129
130 #[test]
131 fn test_cond_time() {
132 let (input, out) = cond_time.parse_peek(" * 60").unwrap();
133 assert_eq!(input, "");
134 assert_eq!(out, vec![("60", CondUnit::Star, TimeUnit::Second)]);
135 }
136
137 #[test]
138 fn test_cond_time2() {
139 let (input, out) = cond_time.parse_peek(" * 60*30").unwrap();
140 assert_eq!(input, "");
141 assert_eq!(
142 out,
143 vec![
144 ("60", CondUnit::Star, TimeUnit::Second),
145 ("30", CondUnit::Star, TimeUnit::Second),
146 ]
147 );
148 }
149
150 #[test]
151 fn test_duration_parse0() {
152 let duration = parse("0").unwrap();
153 assert_eq!(duration, Duration::new(0, 0));
154
155 let duration = parse("0 ").unwrap();
156 assert_eq!(duration, Duration::new(0, 0));
157
158 let duration = parse(" 0 ").unwrap();
159 assert_eq!(duration, Duration::new(0, 0));
160
161 let duration = parse("1").unwrap();
162 assert_eq!(duration, Duration::new(1, 0));
163
164 let duration = parse("0m").unwrap();
165 assert_eq!(duration, Duration::new(0, 0));
166
167 let duration = parse("1hr").unwrap();
168 assert_eq!(duration, Duration::new(3600, 0));
169
170 let duration = parse("1m31").unwrap();
171 assert_eq!(duration, Duration::new(91, 0));
172
173 let duration = parse("1m31s").unwrap();
174 assert_eq!(duration, Duration::new(91, 0));
175
176 #[cfg(not(feature = "no_calc"))]
177 {
178 let duration = parse("1m+31").unwrap();
179 assert_eq!(duration, Duration::new(91, 0));
180 let duration = parse("1m*60").unwrap();
181 assert_eq!(duration, Duration::new(3600, 0));
182
183 let duration = parse("1m*60*20").unwrap();
184 assert_eq!(duration, Duration::new(72000, 0));
185
186 let duration = parse("1m+60+24").unwrap();
187 assert_eq!(duration, Duration::new(144, 0));
188
189 let duration = parse("1m+60+24 ").unwrap();
190 assert_eq!(duration, Duration::new(144, 0));
191
192 let duration = parse(" 1m + 60 + 24 ").unwrap();
193 assert_eq!(duration, Duration::new(144, 0))
194 }
195 }
196
197 #[cfg(feature = "cn_unit")]
198 #[test]
199 fn test_parse_unit_cn() {
200 let duration = parse("1年").unwrap();
201 assert_eq!(duration, Duration::new(31536000, 0));
202
203 let duration = parse("1月").unwrap();
204 assert_eq!(duration, Duration::new(2592000, 0));
205
206 let duration = parse("1周").unwrap();
207 assert_eq!(duration, Duration::new(604800, 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(86400, 0));
214
215 let duration = parse("1时").unwrap();
216 assert_eq!(duration, Duration::new(3600, 0));
217
218 let duration = parse("1分").unwrap();
219 assert_eq!(duration, Duration::new(60, 0));
220
221 let duration = parse("1秒").unwrap();
222 assert_eq!(duration, Duration::new(1, 0));
223
224 let duration = parse("1毫秒").unwrap();
225 assert_eq!(duration, Duration::new(0, 1 * 1000 * 1000));
226
227 let duration = parse("1微秒").unwrap();
228 assert_eq!(duration, Duration::new(0, 1 * 1000));
229
230 let duration = parse("1纳秒").unwrap();
231 assert_eq!(duration, Duration::new(0, 1));
232
233 let duration = parse("1年 2日").unwrap();
234 assert_eq!(duration, Duration::new(31708800, 0));
235
236 let duration = parse("1分31秒").unwrap();
237 assert_eq!(duration, Duration::new(91, 0));
238
239 #[cfg(not(feature = "no_calc"))]
240 {
241 let duration = parse("1分+31秒").unwrap();
242 assert_eq!(duration, Duration::new(91, 0));
243
244 let duration = parse("1分+31秒+2毫秒+3纳秒").unwrap();
245 assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));
246
247 let duration = parse(" 1分+ 31秒 + 2毫秒+ 3纳秒 ").unwrap();
248 assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));
249 }
250 }
251
252 #[test]
253 fn test_duration_err() {
254 #[cfg(not(feature = "no_calc"))]
255 assert_eq!(
256 catch_err!(parse("0m+3-5")),
257 r#"
2580m+3-5
259 ^
260expected ["y", "mon", "w", "d", "h", "m", "s", "ms", "µs", "us", "ns"]"#
261 .trim()
262 );
263 #[cfg(feature = "no_calc")]
264 assert_eq!(
265 catch_err!(parse("0m3-5")),
266 r#"
2670m3-5
268 ^
269expected ["y", "mon", "w", "d", "h", "m", "s", "ms", "µs", "us", "ns"]"#
270 .trim()
271 );
272
273 assert_eq!(
274 catch_err!(parse("0mxyz")),
275 r#"
2760mxyz
277 ^
278expected ["y", "mon", "w", "d", "h", "m", "s", "ms", "µs", "us", "ns"]"#
279 .trim()
280 );
281
282 #[cfg(not(feature = "no_calc"))]
283 assert_eq!(
284 catch_err!(parse("3ms-2ms")),
285 r#"
2863ms-2ms
287 ^
288expected ['+', '*']"#
289 .trim()
290 );
291
292 assert_eq!(catch_err!(parse("")), "Empty input");
293 }
294
295 #[test]
296 fn test_parse() {
297 let duration = parse("1d").unwrap();
298 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
299
300 let duration = parse(" 1d").unwrap();
301 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
302
303 let duration = parse("1d ").unwrap();
304 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
305
306 let duration = parse(" 1d ").unwrap();
307 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
308
309 #[cfg(not(feature = "no_calc"))]
310 {
311 let duration = parse("3m+31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
313
314 let duration = parse("3m + 31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
316
317 let duration = parse("3m + 13s + 29ms").unwrap();
318 assert_eq!(duration, Duration::new(193, 29 * 1000 * 1000 + 0 + 0));
319
320 let duration = parse("3m + 1s + 29ms +17µs").unwrap();
321 assert_eq!(
322 duration,
323 Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0)
324 );
325
326 let duration = parse("1m*10").unwrap(); assert_eq!(duration, Duration::new(600, 0));
328
329 let duration = parse("1m*10ms").unwrap();
330 assert_eq!(duration, Duration::new(0, 600 * 1000 * 1000));
331
332 let duration = parse("1m * 1ns").unwrap();
333 assert_eq!(duration, Duration::new(0, 60));
334
335 let duration = parse("1m * 1m").unwrap();
336 assert_eq!(duration, Duration::new(3600, 0));
337
338 let duration = parse("3m + 31").unwrap();
339 assert_eq!(duration, Duration::new(211, 0));
340 }
341
342 #[cfg(feature = "no_calc")]
343 {
344 let duration = parse("3m31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
346
347 let duration = parse("3m 31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
349 }
350
351 let duration = parse("3m 31s").unwrap();
352 assert_eq!(duration, Duration::new(211, 0));
353
354 let duration = parse("3m31s0ns").unwrap();
355 assert_eq!(duration, Duration::new(211, 0));
356
357 let duration = parse(" 3m 31s 0ns ").unwrap();
358 assert_eq!(duration, Duration::new(211, 0));
359
360 let duration = parse("1d2h3min4s").unwrap();
361 assert_eq!(duration, Duration::new(93784, 0));
362 }
363
364 #[cfg(not(feature = "no_calc"))]
365 #[test]
366 fn test_overflow_plus() {
367 assert_eq!(
368 catch_err!(parse("10000000000000000y+60")),
369 r#"
37010000000000000000y+60
371^
372overflow error"#
373 .trim()
374 .to_string()
375 );
376 }
377
378 #[cfg(not(feature = "no_calc"))]
379 #[test]
380 fn test_max_mul() {
381 let duration = parse("580y*1").unwrap();
382 assert_eq!(
383 duration,
384 std::time::Duration::from_millis(18290880000) * 1000
385 );
386 }
387
388 #[cfg(not(feature = "no_calc"))]
389 #[test]
390 fn test_overflow_mul() {
391 let err = parse("580y*2").err().unwrap();
392 assert_eq!(err, "overflow error");
393 }
394
395 #[test]
396 fn test_parse_optional_spaces() {
397 let duration = parse("1 d").unwrap();
398 assert_eq!(duration, Duration::new(24 * 60 * 60, 0));
399
400 #[cfg(not(feature = "no_calc"))]
401 {
402 let duration = parse("3 m+31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
404
405 let duration = parse("3 m + 31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
407
408 let duration = parse("3 m + 13 s + 29 ms").unwrap();
409 assert_eq!(duration, Duration::new(193, 29 * 1000 * 1000 + 0 + 0));
410
411 let duration = parse("3 m + 1 s + 29 ms +17µs").unwrap();
412 assert_eq!(
413 duration,
414 Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0)
415 );
416
417 let duration = parse("1 m*10").unwrap(); assert_eq!(duration, Duration::new(600, 0));
419
420 let duration = parse("1 m*10 ms").unwrap();
421 assert_eq!(duration, Duration::new(0, 600 * 1000 * 1000));
422
423 let duration = parse("1 m * 1ns").unwrap();
424 assert_eq!(duration, Duration::new(0, 60));
425
426 let duration = parse("1 m * 1 m").unwrap();
427 assert_eq!(duration, Duration::new(3600, 0));
428
429 let duration = parse("3 m + 31").unwrap();
430 assert_eq!(duration, Duration::new(211, 0));
431 }
432
433 #[cfg(feature = "no_calc")]
434 {
435 let duration = parse("3 m31").unwrap(); assert_eq!(duration, Duration::new(211, 0));
437 }
438
439 let duration = parse("3 m 31 s").unwrap();
440 assert_eq!(duration, Duration::new(211, 0));
441
442 let duration = parse("3 m31 s0 ns").unwrap();
443 assert_eq!(duration, Duration::new(211, 0));
444
445 let duration = parse(" 3 m 31 s 0 ns ").unwrap();
446 assert_eq!(duration, Duration::new(211, 0));
447
448 let duration = parse("1 d2 h3 min 4s").unwrap();
449 assert_eq!(duration, Duration::new(93784, 0));
450 }
451}
452
453#[cfg(all(test, feature = "chrono"))]
454mod chrono_tests {
455 use crate::{
456 after_naive_date, after_naive_date_time, before_naive_date, before_naive_date_time,
457 parse_chrono,
458 };
459 use chrono::{Datelike, Utc};
460
461 #[test]
462 fn test_parse_chrono() {
463 use chrono::Duration;
464 #[cfg(not(feature = "no_calc"))]
465 let duration = parse_chrono("1m+60+24 ").unwrap();
466 #[cfg(feature = "no_calc")]
467 let duration = parse_chrono("1m84s ").unwrap();
468 assert_eq!(duration, Duration::seconds(144))
469 }
470
471 #[test]
472 fn test_after_naive_date_time() {
473 let date = Utc::now().naive_utc().date();
474 let jd = date.num_days_from_ce() + 180;
475 let date = after_naive_date_time("180d").unwrap();
476 assert_eq!(date.num_days_from_ce(), jd)
477 }
478
479 #[test]
480 fn test_after_naive_date() {
481 let date = Utc::now().naive_utc().date();
482 let jd = date.num_days_from_ce() + 180;
483 let date = after_naive_date("180d").unwrap();
484 assert_eq!(date.num_days_from_ce(), jd)
485 }
486
487 #[test]
488 fn test_before_naive_date_time() {
489 let date = Utc::now().naive_utc().date();
490 let jd = date.num_days_from_ce() - 180;
491 let date = before_naive_date_time("180d").unwrap();
492 assert_eq!(date.num_days_from_ce(), jd)
493 }
494
495 #[test]
496 fn test_before_naive_date() {
497 let date = Utc::now().naive_utc().date();
498 let jd = date.num_days_from_ce() - 180;
499 let date = before_naive_date("180d").unwrap();
500 assert_eq!(date.num_days_from_ce(), jd)
501 }
502}
503
504#[cfg(all(test, feature = "time"))]
505mod time_tests {
506 use crate::parse_time;
507 use time::Duration;
508
509 #[test]
510 fn test_parse_time() {
511 #[cfg(not(feature = "no_calc"))]
512 {
513 let duration = parse_time("1m+60+24 ").unwrap();
514 assert_eq!(duration, Duration::seconds(144))
515 }
516 #[cfg(feature = "no_calc")]
517 {
518 let duration = parse_time("1m84 ").unwrap();
519 assert_eq!(duration, Duration::seconds(144))
520 }
521 }
522}