/rust/registry/src/index.crates.io-1949cf8c6b5b557f/duration-str-0.21.0/src/lib.rs
Line | Count | Source |
1 | | #![doc( |
2 | | html_logo_url = "https://raw.githubusercontent.com/baoyachi/duration-str/master/duration-str.png" |
3 | | )] |
4 | | //! Parse string to `Duration` . |
5 | | //! |
6 | | //! The String value unit support for one of:["y","mon","w","d","h","m","s", "ms", "µs", "ns"] |
7 | | //! |
8 | | //! - y:Year. Support string value: ["y" | "year" | "Y" | "YEAR" | "Year"]. e.g. 1y |
9 | | //! |
10 | | //! - mon:Month.Support string value: ["mon" | "MON" | "Month" | "month" | "MONTH"]. e.g. 1mon |
11 | | //! |
12 | | //! - w:Week.Support string value: ["w" | "W" | "Week" | "WEEK" | "week"]. e.g. 1w |
13 | | //! |
14 | | //! - d:Day.Support string value: ["d" | "D" | "Day" | "DAY" | "day"]. e.g. 1d |
15 | | //! |
16 | | //! - h:Hour.Support string value: ["h" | "H" | "hr" | "Hour" | "HOUR" | "hour"]. e.g. 1h |
17 | | //! |
18 | | //! - m:Minute.Support string value: ["m" | "M" | "Minute" | "MINUTE" | "minute" | "min" | "MIN"]. e.g. 1m |
19 | | //! |
20 | | //! - s:Second.Support string value: ["s" | "S" | "Second" | "SECOND" | "second" | "sec" | "SEC"]. e.g. 1s |
21 | | //! |
22 | | //! - ms:Millisecond.Support string value: ["ms" | "MS" | "Millisecond" | "MilliSecond" | "MILLISECOND" | "millisecond" | "mSEC" ]. e.g. 1ms |
23 | | //! |
24 | | //! - µs:Microsecond.Support string value: ["µs" | "µS" | "µsecond" | "us" | "uS" | "usecond" | "Microsecond" | "MicroSecond" | "MICROSECOND" | "microsecond" | "µSEC"]. e.g. 1µs |
25 | | //! |
26 | | //! - ns:Nanosecond.Support string value: ["ns" | "NS" | "Nanosecond" | "NanoSecond" | "NANOSECOND" | "nanosecond" | "nSEC"]. e.g. 1ns |
27 | | //! |
28 | | //! Also, `duration_str` support time duration simple evaluation(+,*). See examples below. |
29 | | //! |
30 | | //! # Example |
31 | | //! ```rust |
32 | | //! use duration_str::parse; |
33 | | //! use std::time::Duration; |
34 | | //! |
35 | | //! let duration = parse("1d").unwrap(); |
36 | | //! assert_eq!(duration, Duration::new(24 * 60 * 60, 0)); |
37 | | //! |
38 | | //! let duration = parse("3m+31").unwrap(); //the default duration unit is second. |
39 | | //! assert_eq!(duration, Duration::new(211, 0)); |
40 | | //! |
41 | | //! let duration = parse("3m + 31").unwrap(); //the default duration unit is second. |
42 | | //! assert_eq!(duration, Duration::new(211, 0)); |
43 | | //! |
44 | | //! let duration = parse("3m + 13s + 29ms").unwrap(); |
45 | | //! assert_eq!(duration, Duration::new(193, 29 * 1000 * 1000 + 0 + 0)); |
46 | | //! |
47 | | //! let duration = parse("3m + 1s + 29ms +17µs").unwrap(); |
48 | | //! assert_eq!( |
49 | | //! duration, |
50 | | //! Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0) |
51 | | //! ); |
52 | | //! |
53 | | //! let duration = parse("3m 1s 29ms 17µs").unwrap(); |
54 | | //! assert_eq!( |
55 | | //! duration, |
56 | | //! Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0) |
57 | | //! ); |
58 | | //! |
59 | | //! let duration = parse("3m1s29ms17us").unwrap(); |
60 | | //! assert_eq!( |
61 | | //! duration, |
62 | | //! Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0) |
63 | | //! ); |
64 | | //! |
65 | | //! let duration = parse("1m*10").unwrap(); //the default duration unit is second. |
66 | | //! assert_eq!(duration, Duration::new(600, 0)); |
67 | | //! |
68 | | //! let duration = parse("1m*10ms").unwrap(); |
69 | | //! assert_eq!(duration, Duration::new(0, 600 * 1000 * 1000)); |
70 | | //! |
71 | | //! let duration = parse("1m * 1ns").unwrap(); |
72 | | //! assert_eq!(duration, Duration::new(0, 60)); |
73 | | //! |
74 | | //! let duration = parse("1m * 1m").unwrap(); |
75 | | //! assert_eq!(duration, Duration::new(3600, 0)); |
76 | | //! let duration = parse("42µs").unwrap(); |
77 | | //! assert_eq!(duration,Duration::from_micros(42)); |
78 | | //! ``` |
79 | | //! |
80 | | //! # deserialize to std::time::Duration |
81 | | //! |
82 | | #![cfg_attr(not(feature = "serde"), doc = "This requires the `serde` feature")] |
83 | | //! |
84 | | #![cfg_attr(not(feature = "serde"), doc = "```ignore")] |
85 | | #![cfg_attr(feature = "serde", doc = "```rust")] |
86 | | //! use duration_str::deserialize_duration; |
87 | | //! use serde::*; |
88 | | //! use std::time::Duration; |
89 | | //! |
90 | | //! /// Uses `deserialize_duration`. |
91 | | //! #[derive(Debug, Deserialize)] |
92 | | //! struct Config { |
93 | | //! #[serde(deserialize_with = "deserialize_duration")] |
94 | | //! time_ticker: Duration, |
95 | | //! } |
96 | | //! |
97 | | //! fn needless_main() { |
98 | | //! let json = r#"{"time_ticker":"1m+30"}"#; |
99 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
100 | | //! assert_eq!(config.time_ticker, Duration::new(60 + 30, 0)); |
101 | | //! |
102 | | //! let json = r#"{"time_ticker":"1m+30s"}"#; |
103 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
104 | | //! assert_eq!(config.time_ticker, Duration::new(60 + 30, 0)); |
105 | | //! |
106 | | //! let json = r#"{"time_ticker":"3m 1s 29ms 17µs"}"#; |
107 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
108 | | //! assert_eq!( |
109 | | //! config.time_ticker, |
110 | | //! Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0) |
111 | | //! ); |
112 | | //! |
113 | | //! let json = r#"{"time_ticker":"3m1s29ms17us"}"#; |
114 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
115 | | //! assert_eq!( |
116 | | //! config.time_ticker, |
117 | | //! Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0) |
118 | | //! ); |
119 | | //! } |
120 | | //! ``` |
121 | | //! |
122 | | //! ## deserialize option duration (using the same function) |
123 | | //! |
124 | | #![cfg_attr(not(feature = "serde"), doc = "This requires the `serde` feature")] |
125 | | //! |
126 | | #![cfg_attr(not(feature = "serde"), doc = "```ignore")] |
127 | | #![cfg_attr(feature = "serde", doc = "```rust")] |
128 | | //! use duration_str::deserialize_duration; |
129 | | //! use serde::*; |
130 | | //! use std::time::Duration; |
131 | | //! |
132 | | //! /// Uses `deserialize_duration` for both required and optional fields. |
133 | | //! #[derive(Debug, Deserialize, PartialEq)] |
134 | | //! struct Config { |
135 | | //! #[serde(default, deserialize_with = "deserialize_duration")] |
136 | | //! time_ticker: Option<Duration>, |
137 | | //! name: String, |
138 | | //! } |
139 | | //! |
140 | | //! fn needless_main() { |
141 | | //! // With valid duration string |
142 | | //! let json = r#"{"time_ticker":"1m+30","name":"foo"}"#; |
143 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
144 | | //! assert_eq!(config.time_ticker, Some(Duration::new(90, 0))); |
145 | | //! |
146 | | //! // With null value |
147 | | //! let json = r#"{"time_ticker":null,"name":"foo"}"#; |
148 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
149 | | //! assert_eq!(config.time_ticker, None); |
150 | | //! |
151 | | //! // With missing field |
152 | | //! let json = r#"{"name":"foo"}"#; |
153 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
154 | | //! assert_eq!(config.time_ticker, None); |
155 | | //! |
156 | | //! // With empty string |
157 | | //! let json = r#"{"time_ticker":"","name":"foo"}"#; |
158 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
159 | | //! assert_eq!(config.time_ticker, None); |
160 | | //! } |
161 | | //! ``` |
162 | | //! |
163 | | //! # deserialize to chrono::Duration |
164 | | #![cfg_attr( |
165 | | not(all(feature = "chrono", feature = "serde")), |
166 | | doc = "This requires both the `chrono` and `serde` features" |
167 | | )] |
168 | | //! |
169 | | #![cfg_attr(not(all(feature = "chrono", feature = "serde")), doc = "```ignore")] |
170 | | #![cfg_attr(all(feature = "chrono", feature = "serde"), doc = "```rust")] |
171 | | //! use chrono::Duration; |
172 | | //! use duration_str::deserialize_duration_chrono; |
173 | | //! use serde::*; |
174 | | //! |
175 | | //! #[derive(Debug, Deserialize)] |
176 | | //! struct Config { |
177 | | //! #[serde(deserialize_with = "deserialize_duration_chrono")] |
178 | | //! time_ticker: Duration, |
179 | | //! } |
180 | | //! |
181 | | //! fn needless_main() { |
182 | | //! let json = r#"{"time_ticker":"1m+30"}"#; |
183 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
184 | | //! assert_eq!(config.time_ticker, Duration::seconds(60 + 30)); |
185 | | //! |
186 | | //! let json = r#"{"time_ticker":"1m+30s"}"#; |
187 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
188 | | //! assert_eq!(config.time_ticker, Duration::seconds(60 + 30)); |
189 | | //! |
190 | | //! let json = r#"{"time_ticker":"3m 1s 29ms 17µs"}"#; |
191 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
192 | | //! assert_eq!( |
193 | | //! config.time_ticker, |
194 | | //! Duration::minutes(3) |
195 | | //! + Duration::seconds(1) |
196 | | //! + Duration::milliseconds(29) |
197 | | //! + Duration::microseconds(17) |
198 | | //! ); |
199 | | //! |
200 | | //! let json = r#"{"time_ticker":"3m1s29ms17us"}"#; |
201 | | //! let config: Config = serde_json::from_str(json).unwrap(); |
202 | | //! assert_eq!( |
203 | | //! config.time_ticker, |
204 | | //! Duration::minutes(3) |
205 | | //! + Duration::seconds(1) |
206 | | //! + Duration::milliseconds(29) |
207 | | //! + Duration::microseconds(17) |
208 | | //! ); |
209 | | //! } |
210 | | //! ``` |
211 | | |
212 | | mod error; |
213 | | pub(crate) mod ext; |
214 | | pub(crate) mod macros; |
215 | | mod parser; |
216 | | #[cfg(feature = "serde")] |
217 | | mod serde; |
218 | | mod unit; |
219 | | |
220 | | pub use parser::parse; |
221 | | #[cfg(feature = "serde")] |
222 | | pub use serde::*; |
223 | | use std::fmt::{Debug, Display}; |
224 | | |
225 | | use rust_decimal::prelude::ToPrimitive; |
226 | | use rust_decimal::Decimal; |
227 | | use std::str::FromStr; |
228 | | use std::time::Duration; |
229 | | |
230 | | pub use crate::error::DError; |
231 | | use crate::unit::TimeUnit; |
232 | | #[cfg(feature = "chrono")] |
233 | | pub use naive_date::{ |
234 | | after_naive_date, after_naive_date_time, before_naive_date, before_naive_date_time, |
235 | | }; |
236 | | |
237 | | pub use ext::*; |
238 | | |
239 | | pub type DResult<T> = Result<T, DError>; |
240 | | |
241 | | const ONE_MICROSECOND_NANOSECOND: u64 = 1000; |
242 | | const ONE_MILLISECOND_NANOSECOND: u64 = 1000 * ONE_MICROSECOND_NANOSECOND; |
243 | | const ONE_SECOND_NANOSECOND: u64 = 1000 * ONE_MILLISECOND_NANOSECOND; |
244 | | const ONE_MINUTE_NANOSECOND: u64 = 60 * ONE_SECOND_NANOSECOND; |
245 | | const ONE_HOUR_NANOSECOND: u64 = 60 * ONE_MINUTE_NANOSECOND; |
246 | | const ONE_DAY_NANOSECOND: u64 = 24 * ONE_HOUR_NANOSECOND; |
247 | | const ONE_WEEK_NANOSECOND: u64 = 7 * ONE_DAY_NANOSECOND; |
248 | | const ONE_MONTH_NANOSECOND: u64 = 30 * ONE_DAY_NANOSECOND; |
249 | | const ONE_YEAR_NANOSECOND: u64 = 365 * ONE_DAY_NANOSECOND; |
250 | | |
251 | | // const ONE_SECOND_DECIMAL: Decimal = 1_000_000_000.into(); |
252 | 0 | fn one_second_decimal() -> Decimal { |
253 | 0 | 1_000_000_000.into() |
254 | 0 | } |
255 | | |
256 | | const PLUS: &str = "+"; |
257 | | const STAR: &str = "*"; |
258 | | |
259 | | trait ExpectErr { |
260 | | type Output: Debug; |
261 | | |
262 | | fn expect_val() -> Self::Output; |
263 | | |
264 | | fn get_expect_val() -> &'static str; |
265 | | fn expect_err<S: AsRef<str> + Display>(s: S) -> String; |
266 | | } |
267 | | |
268 | | #[macro_export] |
269 | | macro_rules! impl_expect_err { |
270 | | ($type:ty, $output:ty, [$($val:tt),* $(,)?]) => { |
271 | | impl ExpectErr for $type { |
272 | | type Output = $output; |
273 | | |
274 | 0 | fn expect_val() -> Self::Output { |
275 | 0 | [$($val),*] |
276 | 0 | } Unexecuted instantiation: <duration_str::unit::TimeUnit as duration_str::ExpectErr>::expect_val Unexecuted instantiation: <duration_str::CondUnit as duration_str::ExpectErr>::expect_val |
277 | | |
278 | 0 | fn expect_err<S: AsRef<str> + Display>(s: S) -> String { |
279 | 0 | format!("expect one of:{:?}, but find:{}", Self::expect_val(), s) |
280 | 0 | } Unexecuted instantiation: <duration_str::unit::TimeUnit as duration_str::ExpectErr>::expect_err::<&str> Unexecuted instantiation: <duration_str::CondUnit as duration_str::ExpectErr>::expect_err::<&str> |
281 | | |
282 | 0 | fn get_expect_val() -> &'static str { |
283 | | static EXPECT_VAL_STR: &str = concat!( |
284 | | "[", |
285 | | impl_expect_err_internal!($($val),*), |
286 | | "]" |
287 | | ); |
288 | 0 | EXPECT_VAL_STR |
289 | 0 | } Unexecuted instantiation: <duration_str::unit::TimeUnit as duration_str::ExpectErr>::get_expect_val Unexecuted instantiation: <duration_str::CondUnit as duration_str::ExpectErr>::get_expect_val |
290 | | } |
291 | | }; |
292 | | } |
293 | | |
294 | | #[macro_export] |
295 | | macro_rules! impl_expect_err_internal { |
296 | | // match empty |
297 | | () => { |
298 | | "" |
299 | | }; |
300 | | // match single type |
301 | | ($first:expr) => { |
302 | | stringify!($first) |
303 | | }; |
304 | | // match multi type |
305 | | ($first:expr, $($rest:expr),*) => { |
306 | | concat!( |
307 | | stringify!($first), |
308 | | ", ", |
309 | | impl_expect_err_internal!($($rest),*) |
310 | | ) |
311 | | }; |
312 | | } |
313 | | |
314 | | #[derive(Debug, Eq, PartialEq, Clone)] |
315 | | enum CondUnit { |
316 | | Plus, |
317 | | Star, |
318 | | } |
319 | | |
320 | | impl FromStr for CondUnit { |
321 | | type Err = String; |
322 | | |
323 | 0 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
324 | 0 | match s { |
325 | 0 | "+" => Ok(CondUnit::Plus), |
326 | 0 | "*" => Ok(CondUnit::Star), |
327 | 0 | _ => Err(Self::expect_err(s)), |
328 | | } |
329 | 0 | } |
330 | | } |
331 | | |
332 | | impl_expect_err!(CondUnit, [char; 2], ['+', '*']); |
333 | | |
334 | | impl CondUnit { |
335 | 0 | fn init() -> (Self, u64) { |
336 | 0 | (CondUnit::Star, ONE_SECOND_NANOSECOND) |
337 | 0 | } |
338 | | |
339 | 0 | fn contain(c: char) -> bool { |
340 | 0 | Self::expect_val().contains(&c) |
341 | 0 | } |
342 | | |
343 | 0 | fn change_duration(&self) -> u64 { |
344 | 0 | match self { |
345 | 0 | CondUnit::Plus => 0, |
346 | 0 | CondUnit::Star => ONE_SECOND_NANOSECOND, |
347 | | } |
348 | 0 | } |
349 | | |
350 | 0 | fn calc(&self, x: u64, y: u64) -> DResult<Duration> { |
351 | 0 | let nano_second = match self { |
352 | 0 | CondUnit::Plus => x.checked_add(y).ok_or(DError::OverflowError)?, |
353 | | CondUnit::Star => { |
354 | 0 | let x: Decimal = x.into(); |
355 | 0 | let y: Decimal = y.into(); |
356 | 0 | let ret = (x / one_second_decimal()) |
357 | 0 | .checked_mul(y / one_second_decimal()) |
358 | 0 | .ok_or(DError::OverflowError)? |
359 | 0 | .checked_mul(one_second_decimal()) |
360 | 0 | .ok_or(DError::OverflowError)?; |
361 | 0 | ret.to_u64().ok_or(DError::OverflowError)? |
362 | | } |
363 | | }; |
364 | 0 | Ok(Duration::from_nanos(nano_second)) |
365 | 0 | } |
366 | | } |
367 | | |
368 | | trait Calc<T> { |
369 | | fn calc(&self) -> DResult<T>; |
370 | | } |
371 | | |
372 | | impl Calc<(CondUnit, u64)> for Vec<(&str, CondUnit, TimeUnit)> { |
373 | 0 | fn calc(&self) -> DResult<(CondUnit, u64)> { |
374 | 0 | let (mut init_cond, mut init_duration) = CondUnit::init(); |
375 | 0 | for (index, (val, cond, time_unit)) in self.iter().enumerate() { |
376 | 0 | if index == 0 { |
377 | 0 | init_cond = cond.clone(); |
378 | 0 | init_duration = init_cond.change_duration(); |
379 | 0 | } else if &init_cond != cond { |
380 | 0 | return Err(DError::ParseError(format!( |
381 | 0 | "not support '{}' with '{}' calculate", |
382 | 0 | init_cond, cond |
383 | 0 | ))); |
384 | 0 | } |
385 | 0 | match init_cond { |
386 | | CondUnit::Plus => { |
387 | 0 | init_duration = init_duration |
388 | 0 | .checked_add(time_unit.duration(val)?) |
389 | 0 | .ok_or(DError::OverflowError)?; |
390 | | } |
391 | | CondUnit::Star => { |
392 | 0 | let time: Decimal = time_unit.duration(val)?.into(); |
393 | 0 | let i = time / one_second_decimal(); |
394 | 0 | let mut init: Decimal = init_duration.into(); |
395 | 0 | init = init.checked_mul(i).ok_or(DError::OverflowError)?; |
396 | 0 | init_duration = init.to_u64().ok_or(DError::OverflowError)?; |
397 | | } |
398 | | } |
399 | | } |
400 | 0 | Ok((init_cond, init_duration)) |
401 | 0 | } |
402 | | } |
403 | | |
404 | | impl Display for CondUnit { |
405 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
406 | 0 | let str = match self { |
407 | 0 | Self::Plus => PLUS.to_string(), |
408 | 0 | Self::Star => STAR.to_string(), |
409 | | }; |
410 | 0 | write!(f, "{}", str) |
411 | 0 | } |
412 | | } |
413 | | |
414 | | /// convert `Into<String>` to `std::time::Duration` |
415 | | /// |
416 | | /// # Example |
417 | | /// |
418 | | /// ```rust |
419 | | /// use duration_str::parse; |
420 | | /// use std::time::Duration; |
421 | | /// |
422 | | /// // supports units |
423 | | /// let duration = parse("1d").unwrap(); |
424 | | /// assert_eq!(duration,Duration::new(24*60*60,0)); |
425 | | /// |
426 | | /// // supports addition |
427 | | /// let duration = parse("3m+31").unwrap(); |
428 | | /// assert_eq!(duration,Duration::new(211,0)); |
429 | | /// |
430 | | /// // spaces are optional |
431 | | /// let duration = parse("3m + 31").unwrap(); |
432 | | /// assert_eq!(duration,Duration::new(211,0)); |
433 | | /// |
434 | | /// // plus sign is optional |
435 | | /// let duration = parse("3m 31").unwrap(); |
436 | | /// assert_eq!(duration,Duration::new(211,0)); |
437 | | /// |
438 | | /// // both plus and spaces are optional |
439 | | /// let duration = parse("3m31").unwrap(); |
440 | | /// assert_eq!(duration,Duration::new(211,0)); |
441 | | /// |
442 | | /// // supports multiplication |
443 | | /// let duration = parse("1m*10").unwrap(); |
444 | | /// assert_eq!(duration,Duration::new(600,0)); |
445 | | /// |
446 | | /// // spaces are optional |
447 | | /// let duration = parse("1m * 10").unwrap(); |
448 | | /// assert_eq!(duration,Duration::new(600,0)); |
449 | | /// ``` |
450 | 0 | pub fn parse_std(input: impl AsRef<str>) -> Result<Duration, String> { |
451 | 0 | parse(input.as_ref()) |
452 | 0 | } |
453 | | |
454 | | /// convert `Into<String>` to `chrono::Duration` |
455 | | /// |
456 | | /// # Example |
457 | | /// |
458 | | /// ```rust |
459 | | /// use duration_str::parse_chrono; |
460 | | /// use chrono::Duration; |
461 | | /// |
462 | | /// // supports units |
463 | | /// let duration = parse_chrono("1d").unwrap(); |
464 | | /// assert_eq!(duration,Duration::seconds(24*60*60)); |
465 | | /// |
466 | | /// // supports addition |
467 | | /// let duration = parse_chrono("3m+31").unwrap(); |
468 | | /// assert_eq!(duration,Duration::seconds(211)); |
469 | | /// |
470 | | /// // spaces are optional |
471 | | /// let duration = parse_chrono("3m + 31").unwrap(); |
472 | | /// assert_eq!(duration,Duration::seconds(211)); |
473 | | /// |
474 | | /// // plus sign is optional |
475 | | /// let duration = parse_chrono("3m 31").unwrap(); |
476 | | /// assert_eq!(duration,Duration::seconds(211)); |
477 | | /// |
478 | | /// // both plus and spaces are optional |
479 | | /// let duration = parse_chrono("3m31").unwrap(); |
480 | | /// assert_eq!(duration,Duration::seconds(211)); |
481 | | /// |
482 | | /// // supports multiplication |
483 | | /// let duration = parse_chrono("1m*10").unwrap(); |
484 | | /// assert_eq!(duration,Duration::seconds(600)); |
485 | | /// |
486 | | /// // spaces are optional |
487 | | /// let duration = parse_chrono("1m * 10").unwrap(); |
488 | | /// assert_eq!(duration,Duration::seconds(600)); |
489 | | /// ``` |
490 | | #[cfg(feature = "chrono")] |
491 | 0 | pub fn parse_chrono(input: impl AsRef<str>) -> Result<chrono::Duration, String> { |
492 | 0 | let std_duration = parse_std(input)?; |
493 | 0 | let duration = chrono::Duration::from_std(std_duration).map_err(|e| e.to_string())?; |
494 | 0 | Ok(duration) |
495 | 0 | } |
496 | | |
497 | | /// convert `Into<String>` to `time::Duration` |
498 | | /// |
499 | | /// # Example |
500 | | /// |
501 | | /// ```rust |
502 | | /// use duration_str::parse_time; |
503 | | /// use time::Duration; |
504 | | /// |
505 | | /// // supports units |
506 | | /// let duration = parse_time("1d").unwrap(); |
507 | | /// assert_eq!(duration,Duration::seconds(24*60*60)); |
508 | | /// |
509 | | /// // supports addition |
510 | | /// let duration = parse_time("3m+31").unwrap(); |
511 | | /// assert_eq!(duration,Duration::seconds(211)); |
512 | | /// |
513 | | /// // spaces are optional |
514 | | /// let duration = parse_time("3m + 31").unwrap(); |
515 | | /// assert_eq!(duration,Duration::seconds(211)); |
516 | | /// |
517 | | /// // plus sign is optional |
518 | | /// let duration = parse_time("3m 31").unwrap(); |
519 | | /// assert_eq!(duration,Duration::seconds(211)); |
520 | | /// |
521 | | /// // both plus and spaces are optional |
522 | | /// let duration = parse_time("3m31").unwrap(); |
523 | | /// assert_eq!(duration,Duration::seconds(211)); |
524 | | /// |
525 | | /// // supports multiplication |
526 | | /// let duration = parse_time("1m*10").unwrap(); |
527 | | /// assert_eq!(duration,Duration::seconds(600)); |
528 | | /// |
529 | | /// // spaces are optional |
530 | | /// let duration = parse_time("1m * 10").unwrap(); |
531 | | /// assert_eq!(duration,Duration::seconds(600)); |
532 | | /// ``` |
533 | | #[cfg(feature = "time")] |
534 | 0 | pub fn parse_time(input: impl AsRef<str>) -> Result<time::Duration, String> { |
535 | 0 | let std_duration = parse_std(input)?; |
536 | 0 | let duration = time::Duration::try_from(std_duration).map_err(|e| e.to_string())?; |
537 | 0 | Ok(duration) |
538 | 0 | } |
539 | | |
540 | | #[cfg(feature = "chrono")] |
541 | | mod naive_date { |
542 | | use crate::parse_chrono; |
543 | | use chrono::Utc; |
544 | | |
545 | | #[allow(dead_code)] |
546 | | pub enum TimeHistory { |
547 | | Before, |
548 | | After, |
549 | | } |
550 | | |
551 | | #[cfg(feature = "chrono")] |
552 | 0 | pub fn calc_naive_date_time( |
553 | 0 | input: impl AsRef<str>, |
554 | 0 | history: TimeHistory, |
555 | 0 | ) -> Result<chrono::NaiveDateTime, String> { |
556 | 0 | let duration = parse_chrono(input)?; |
557 | 0 | let time = match history { |
558 | 0 | TimeHistory::Before => (Utc::now() - duration).naive_utc(), |
559 | 0 | TimeHistory::After => (Utc::now() + duration).naive_utc(), |
560 | | }; |
561 | 0 | Ok(time) |
562 | 0 | } |
563 | | |
564 | | macro_rules! gen_naive_date_func { |
565 | | ($date_time:ident,$date:ident,$history:expr) => { |
566 | | #[allow(dead_code)] |
567 | | #[cfg(feature = "chrono")] |
568 | 0 | pub fn $date_time(input: impl AsRef<str>) -> Result<chrono::NaiveDateTime, String> { |
569 | 0 | calc_naive_date_time(input, $history) |
570 | 0 | } Unexecuted instantiation: duration_str::naive_date::after_naive_date_time::<_> Unexecuted instantiation: duration_str::naive_date::before_naive_date_time::<_> |
571 | | |
572 | | #[allow(dead_code)] |
573 | | #[cfg(feature = "chrono")] |
574 | 0 | pub fn $date(input: impl AsRef<str>) -> Result<chrono::NaiveDate, String> { |
575 | 0 | let date: chrono::NaiveDateTime = calc_naive_date_time(input, $history)?; |
576 | 0 | Ok(date.date()) |
577 | 0 | } Unexecuted instantiation: duration_str::naive_date::after_naive_date::<_> Unexecuted instantiation: duration_str::naive_date::before_naive_date::<_> |
578 | | }; |
579 | | } |
580 | | |
581 | | gen_naive_date_func!( |
582 | | before_naive_date_time, |
583 | | before_naive_date, |
584 | | TimeHistory::Before |
585 | | ); |
586 | | |
587 | | gen_naive_date_func!(after_naive_date_time, after_naive_date, TimeHistory::After); |
588 | | } |