duration-str 0.17.0

duration string parser
Documentation

parse string to std::time::Duration

Chrono GitHub Actions Crates.io Docs.rs Coverage Status

Features:

Performance

Suggestion: It is recommended to enable the lowercase feature to improve performance:

  • Default: Calls to_lowercase() each time, designed for compatibility, suitable for flexible input but with lower performance.
  • lowercase feature: Skips the conversion, ideal for lowercase input scenarios, offering better performance."
  • no_calc feature: When enabled, the parse function only parses and sums expression values without complex logic, ideal for high-performance scenarios not requiring intricate calculations.

Notice ⚠️

The default duration unit is second.Also use below duration unit

Duration Unit List

Parse string to Duration . The String duration unit support for one of:["y","mon","w","d","h","m","s", "ms", "µs", "ns"]

unit Description unit list option(one of) example
y Year ["y" , "year" , "Y" , "YEAR" , "Year"] 1y
mon Month ["mon" , "MON" , "Month" , "month" , "MONTH"] 1mon
w Week ["w" , "W" , "Week" ,"WEEK" , "week"] 1w
d Day ["d" , "D" , "Day" , "DAY" , "day"] 1d
h Hour ["h" , "hr" , "H" , "Hour" , "HOUR" , "hour"] 1h
m Minute ["m" , "M" , "Minute" , "MINUTE" , "minute" , "min" , "MIN"] 1m
s Second ["s" , "S" , "Second" , "SECOND" , "second" , "sec" , "SEC"] 1s
ms Millisecond ["ms" , "MS" , "Millisecond" , "MilliSecond" , "MILLISECOND" , "millisecond" , "mSEC"] 1ms
µs Microsecond ["µs" , "µS" , "µsecond" , "Microsecond" , "MicroSecond" , "MICROSECOND" , "microsecond" , "µSEC"] 1µs
ns Nanosecond ["ns" , "NS" , "Nanosecond" , "NanoSecond" , "NANOSECOND" , "nanosecond" , "nSEC"] 1ns

Also,duration_str support time duration simple evaluation(+,*). See example:

example

[dependencies]
duration-str = "{latest version}" 
use duration_str::parse;
use std::time::Duration;

fn main() {
    let duration = parse("1d").unwrap();
    assert_eq!(duration, Duration::new(24 * 60 * 60, 0));

    let duration = parse("3m+31").unwrap(); //the default duration unit is second.
    assert_eq!(duration, Duration::new(211, 0));

    let duration = parse("3m + 31").unwrap(); //the default duration unit is second.
    assert_eq!(duration, Duration::new(211, 0));

    let duration = parse("3m31s").unwrap();
    assert_eq!(duration, Duration::new(211, 0));

    let duration = parse("3m + 13s + 29ms").unwrap();
    assert_eq!(duration, Duration::new(193, 29 * 1000 * 1000 + 0 + 0));

    let duration = parse("3m + 1s + 29ms +17µs").unwrap();
    assert_eq!(
        duration,
        Duration::new(181, 29 * 1000 * 1000 + 17 * 1000 + 0)
    );

    let duration = parse("1m*10").unwrap(); //the default duration unit is second.
    assert_eq!(duration, Duration::new(600, 0));

    let duration = parse("1m*10ms").unwrap();
    assert_eq!(duration, Duration::new(0, 600 * 1000 * 1000));

    let duration = parse("1m * 1ns").unwrap();
    assert_eq!(duration, Duration::new(0, 60));

    let duration = parse("1m * 1m").unwrap();
    assert_eq!(duration, Duration::new(3600, 0));


    // The following code requires the `cn_unit` feature.
    // Add it to your `Cargo.toml` like this:
    // duration-str = { version = "{latest version}", features = ["cn_unit"] } 

    let duration = parse("1年").unwrap();
    assert_eq!(duration, Duration::new(31536000, 0));

    let duration = parse("1月").unwrap();
    assert_eq!(duration, Duration::new(2592000, 0));

    let duration = parse("1周").unwrap();
    assert_eq!(duration, Duration::new(604800, 0));

    let duration = parse("1日").unwrap();
    assert_eq!(duration, Duration::new(86400, 0));

    let duration = parse("1天").unwrap();
    assert_eq!(duration, Duration::new(86400, 0));

    let duration = parse("1时").unwrap();
    assert_eq!(duration, Duration::new(3600, 0));

    let duration = parse("1分").unwrap();
    assert_eq!(duration, Duration::new(60, 0));

    let duration = parse("1秒").unwrap();
    assert_eq!(duration, Duration::new(1, 0));

    let duration = parse("1毫秒").unwrap();
    assert_eq!(duration, Duration::new(0, 1 * 1000 * 1000));

    let duration = parse("1微秒").unwrap();
    assert_eq!(duration, Duration::new(0, 1 * 1000));

    let duration = parse("1纳秒").unwrap();
    assert_eq!(duration, Duration::new(0, 1));

    let duration = parse("1年 2日").unwrap();
    assert_eq!(duration, Duration::new(31708800, 0));

    let duration = parse("1分31秒").unwrap();
    assert_eq!(duration, Duration::new(91, 0));

    let duration = parse("1分+31秒").unwrap();
    assert_eq!(duration, Duration::new(91, 0));

    let duration = parse("1分+31秒+2毫秒+3纳秒").unwrap();
    assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));

    let duration = parse(" 1分+   31秒 + 2毫秒+  3纳秒  ").unwrap();
    assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));
    
}

deserialize in struct

deserialize to std::time::Duration

use duration_str::deserialize_duration;
use serde::*;
use std::time::Duration;

#[derive(Debug, Deserialize)]
struct Config {
    #[serde(deserialize_with = "deserialize_duration")]
    time_ticker: Duration,
}

fn main() {
    let json = r#"{"time_ticker":"1m+30"}"#;
    let config: Config = serde_json::from_str(json).unwrap();
    assert_eq!(config.time_ticker, Duration::new(60 + 30, 0));

    let json = r#"{"time_ticker":"1m+30s"}"#;
    let config: Config = serde_json::from_str(json).unwrap();
    assert_eq!(config.time_ticker, Duration::new(60 + 30, 0));
}
  • option filed deserialize
use duration_str::deserialize_option_duration;
use serde::*;
use std::time::Duration;

#[derive(Debug, Deserialize, PartialEq)]
struct Config {
    #[serde(default, deserialize_with = "deserialize_option_duration")]
    time_ticker: Option<Duration>,
    name: String,
}

fn main() {
    let json = r#"{"time_ticker":null,"name":"foo"}"#;
    let config: Config = serde_json::from_str(json).unwrap();

    assert_eq!(
        config,
        Config {
            time_ticker: None,
            name: "foo".into()
        }
    );

    let json = r#"{"name":"foo"}"#;
    let config: Config = serde_json::from_str(json).unwrap();
    assert_eq!(
        config,
        Config {
            time_ticker: None,
            name: "foo".into()
        }
    );
}

Also you can use deserialize_duration_chrono or deserialize_duration_time function

E.g:

use chrono::Duration;
use duration_str::deserialize_duration_chrono;
use serde::*;

#[derive(Debug, Deserialize)]
struct Config {
    #[serde(deserialize_with = "deserialize_duration_chrono")]
    time_ticker: Duration,
}

fn main() {
    let json = r#"{"time_ticker":"1m+30"}"#;
    let config: Config = serde_json::from_str(json).unwrap();
    assert_eq!(config.time_ticker, Duration::seconds(60 + 30));
}