Expand description
§Overview
Parse a rust string into a crate::Duration.
fundu is a configurable, precise and blazingly fast duration parser
- with the flexibility to customize 
TimeUnits, or even create own time units with aCustomTimeUnit(thecustomfeature is needed) - without floating point calculations. What you put in is what you get out.
 - with sound limit handling. Infinity and numbers larger than 
Duration::MAXevaluate toDuration::MAX. Numbersxwithabs(x) < 1e-18evaluate toDuration::ZERO. - with many options to customize the number format and other aspects of the parsing process like parsing negative durations
 - and with meaningful error messages
 
§Fundu’s Duration
This crate::Duration is returned by the parser of this library and can be converted to a
std::time::Duration and if the feature is activated into a time::Duration respectively
chrono::Duration. This crates duration is a superset of the aforementioned durations ranging
from -Duration::MAX to +Duration::MAX with Duration::MAX having u64::MAX seconds and
999_999_999 nano seconds. Converting to fundu’s duration from any of the above durations with
From or Into is lossless. Converting from crate::Duration to any of the other durations
can overflow or can’t be negative, so conversions must be done with TryFrom or TryInto.
Additionally, fundu’s duration implements SaturatingInto for the above durations, so
conversions saturate at the maximum or minimum of these durations.
§Features
§standard
The standard feature exposes the DurationParser and DurationParserBuilder structs with
the a predefined small set of time units. The set of time units can be customized but the
identifier for each TimeUnit is fixed.
§custom
The custom feature provides a CustomDurationParser and CustomDurationParserBuilder
with fully customizable identifiers for each TimeUnit. With the CustomDurationParser
it is also possible to define completely new time units, a CustomTimeUnit.
§base
The base feature exports the basic Parser and the Config on which the standard and
custom features are built. It may lack the convenience of the other features but provides
greater freedom. To be able to use this Parser an implementation of TimeUnitsLike is
needed for time units and optionally for time keywords. Optionally, NumbersLike
implementations are supported, too. For fixed sets of time units and time keywords this is
usually a simple and straightforward process. See the documentation of Parser,
TimeUnitsLike and NumbersLike for examples.
§chrono and time
The chrono feature activates methods of Duration to convert from and to a
chrono::Duration. The time feature activates methods of Duration to convert from and
to a time::Duration. Both of these durations allow negative durations. Parsing negative
numbers can be enabled with DurationParser::allow_negative or
CustomDurationParser::allow_negative independently of the chrono or time feature.
§serde
Some structs and enums can be serialized and deserialized with serde if the feature is
activated.
§Configuration and Format
The standard parser can be configured to accept strings with a default set of time units
DurationParser::new, with all time units DurationParser::with_all_time_units or without
DurationParser::without_time_units. A custom set of time units is also possible with
DurationParser::with_time_units. All these parsers accept strings such as
1.41422e-8,2e+8(or likewise2.0e8).5or likewise0.53.or likewise3.0inf,+inf,infinity,+infinity
All alphabetic characters are matched case-insensitive, so InFINity or 2E8 are valid input
strings. Additionally, depending on the chosen set of time units one of the following time
units (the first column) is accepted.
TimeUnit | default id | is default time unit | 
|---|---|---|
| Nanosecond | ns | yes | 
| Microsecond | Ms | yes | 
| Millisecond | ms | yes | 
| Second | s | yes | 
| Minute | m | yes | 
| Hour | h | yes | 
| Day | d | yes | 
| Week | w | yes | 
| Month | M | no | 
| Year | y | no | 
If no time unit is given and not specified otherwise with DurationParser::default_unit
then s (= Second) is assumed. Some accepted strings with time units
31.2s200000Ms3.14e8w- …
 
Per default there is no whitespace allowed between the number and the TimeUnit, but this
behavior can be changed with DurationParser::allow_time_unit_delimiter.
§Format specification
The TimeUnits and every Char is case-sensitive, all other alphabetic characters are
case-insensitive
Durations ::= Duration [ DurationStartingWithDigit
            | ( Delimiter+ ( Duration | Conjunction ))
            ]* ;
Conjunction ::= ConjunctionWord (( Delimiter+ Duration ) | DurationStartingWithDigit ) ;
ConjunctionWord ::= Char+ ;
Duration ::= Sign? ( 'inf' | 'infinity'
            | TimeKeyword
            | Number [ TimeUnit [ Delimiter+ 'ago' ]]
            ) ;
DurationStartingWithDigit ::=
            ( Digit+ | Digit+ '.' Digit* ) Exp? [ TimeUnit [ Delimiter+ 'ago' ]] ;
TimeUnit ::= ns | Ms | ms | s | m | h | d | w | M | y | CustomTimeUnit ;
CustomTimeUnit ::= Char+ ;
TimeKeyword ::= Char+ ;
Number   ::= ( Digits Exp? ) | Exp ;
Digits   ::= Digit+ | Digit+ '.' Digit* | Digit* '.' Digit+
Exp      ::= 'e' Sign? Digit+ ;
Sign     ::= [+-] ;
Digit    ::= [0-9] ;
Char     ::= ? a valid UTF-8 character ? ;
Delimiter ::= ? a closure with the signature u8 -> bool ? ;Special cases which are not displayed in the specification:
- Parsing multiple 
Durationsmust be enabled withparse_multiple. TheDelimiterandConjunctionWordscan also be defined with theparse_multiplemethod. MultipleDurationsare summed up following the saturation rule below - A negative 
Duration(Sign==-), including negative infinity is not allowed as long as theallow_negativeoption is not enabled. For exceptions see the next point. - Numbers 
x(positive and negative) close to0(abs(x) < 1e-18) are treated as0 - Positive infinity and numbers exceeding 
Duration::MAXsaturate atDuration::MAX. If theallow_negativeoption is enabled, negative infinity and numbers falling belowDuration::MINsaturate atDuration::MIN. - The exponent must be in the range 
-32768 <= Exp <= 32767 - If 
allow_time_unit_delimiteris set then anyDelimiteris allowed between theNumberandTimeUnit. - If 
number_is_optionalis enabled then theNumberis optional but theTimeUnitmust be present instead. - The 
agokeyword must be enabled in the parser withallow_ago TimeKeywordis acustomfeature which must be enabled by adding aTimeKeywordto theCustomDurationParserCustomTimeUnitis acustomfeature which lets you define own time units
§Examples
If only the default configuration is required once, the parse_duration method can be used.
use std::time::Duration;
use fundu::parse_duration;
let input = "1.0e2s";
assert_eq!(parse_duration(input).unwrap(), Duration::new(100, 0));When a customization of the accepted TimeUnits is required, then DurationParser can be
used.
use fundu::{Duration, DurationParser};
let input = "3m";
assert_eq!(
    DurationParser::with_all_time_units().parse(input).unwrap(),
    Duration::positive(180, 0)
);When no time units are configured, seconds is assumed.
use fundu::{Duration, DurationParser};
let input = "1.0e2";
assert_eq!(
    DurationParser::without_time_units().parse(input).unwrap(),
    Duration::positive(100, 0)
);However, the following will return an error because y (Years) is not a default time unit:
use fundu::DurationParser;
let input = "3y";
assert!(DurationParser::new().parse(input).is_err());The parser is reusable and the set of time units is fully customizable
use fundu::TimeUnit::*;
use fundu::{Duration, DurationParser};
let parser = DurationParser::with_time_units(&[NanoSecond, Minute, Hour]);
assert_eq!(parser.parse("9e3ns").unwrap(), Duration::positive(0, 9000));
assert_eq!(parser.parse("10m").unwrap(), Duration::positive(600, 0));
assert_eq!(parser.parse("1.1h").unwrap(), Duration::positive(3960, 0));
assert_eq!(parser.parse("7").unwrap(), Duration::positive(7, 0));Setting the default time unit (if no time unit is given in the input string) to something different than seconds is also easily possible
use fundu::TimeUnit::*;
use fundu::{Duration, DurationParser};
assert_eq!(
    DurationParser::without_time_units()
        .default_unit(MilliSecond)
        .parse("1000")
        .unwrap(),
    Duration::positive(1, 0)
);The identifiers for time units can be fully customized with any number of valid
utf-8 sequences if the custom feature is activated:
use fundu::TimeUnit::*;
use fundu::{CustomTimeUnit, CustomDurationParser, Duration};
let parser = CustomDurationParser::with_time_units(&[
    CustomTimeUnit::with_default(MilliSecond, &["χιλιοστό του δευτερολέπτου"]),
    CustomTimeUnit::with_default(Second, &["s", "secs"]),
    CustomTimeUnit::with_default(Hour, &["⏳"]),
]);
assert_eq!(parser.parse(".3χιλιοστό του δευτερολέπτου"), Ok(Duration::positive(0, 300_000)));
assert_eq!(parser.parse("1e3secs"), Ok(Duration::positive(1000, 0)));
assert_eq!(parser.parse("1.1⏳"), Ok(Duration::positive(3960, 0)));The custom feature can be used to customize a lot more. See the documentation of the exported
items of the custom feature (like CustomTimeUnit, TimeKeyword) for more information.
Also, fundu tries to give informative error messages
use fundu::DurationParser;
assert_eq!(
    DurationParser::without_time_units()
        .parse("1y")
        .unwrap_err()
        .to_string(),
    "Time unit error: No time units allowed but found: 'y' at column 1"
);The number format can be easily adjusted to your needs. For example to allow numbers being optional, allow some ascii whitespace between the number and the time unit and restrict the number format to whole numbers, without fractional part and an exponent:
use fundu::TimeUnit::*;
use fundu::{Duration, DurationParser, ParseError};
const PARSER: DurationParser = DurationParser::builder()
    .time_units(&[NanoSecond])
    .allow_time_unit_delimiter()
    .number_is_optional()
    .disable_fraction()
    .disable_exponent()
    .build();
assert_eq!(PARSER.parse("ns").unwrap(), Duration::positive(0, 1));
assert_eq!(
    PARSER.parse("1000\t\n\r ns").unwrap(),
    Duration::positive(0, 1000)
);
assert_eq!(
    PARSER.parse("1.0ns").unwrap_err(),
    ParseError::Syntax(1, "No fraction allowed".to_string())
);
assert_eq!(
    PARSER.parse("1e9ns").unwrap_err(),
    ParseError::Syntax(1, "No exponent allowed".to_string())
);Structs§
- Config
base - The structure containing all options for the 
crate::parse::Parser - Config
Builder base - A builder to create a 
Config - Custom
Duration Parser custom - A parser with a customizable set of 
TimeUnits and customizable identifiers. - Custom
Duration Parser Builder custom - Like 
crate::DurationParserBuilderforcrate::DurationParser, this is a builder for aCustomDurationParser. - Custom
Time Unit custom - A 
CustomTimeUnitis a completely customizableTimeUnitusing an additionalMultiplier. - Duration
 - The duration which is returned by the parser
 - Duration
Parser standard - A parser with a customizable set of 
TimeUnits with default identifiers. - Duration
Parser Builder standard - An ergonomic builder for a 
DurationParser. - Multiplier
 - The multiplier of a 
TimeUnit. - Numeral
custom - A 
Numeralcan occur where numbers usually occur in the source string - Parser
base - The core duration parser to parse strings into a 
crate::time::Duration - Time
Keyword custom - A 
TimeKeywordrepresents a complete duration without the need for a number 
Enums§
- Parse
Error  - Error type emitted during the parsing
 - Time
Unit  - The time units used to define possible time units in the input string
 - TryFrom
Duration Error  - This error may occur when converting a 
crate::time::Durationto a different duration likestd::time::Duration 
Constants§
- DEFAULT_
ALL_ TIME_ UNITS custom - All identifiers taken from the 
standardfeature withMonthandYear - DEFAULT_
ID_ DAY  - The default identifier of 
TimeUnit::Day - DEFAULT_
ID_ HOUR  - The default identifier of 
TimeUnit::Hour - DEFAULT_
ID_ MICRO_ SECOND  - The default identifier of 
TimeUnit::MicroSecond - DEFAULT_
ID_ MILLI_ SECOND  - The default identifier of 
TimeUnit::MicroSecond - DEFAULT_
ID_ MINUTE  - The default identifier of 
TimeUnit::Minute - DEFAULT_
ID_ MONTH  - The default identifier of 
TimeUnit::Month - DEFAULT_
ID_ NANO_ SECOND  - The default identifier of 
TimeUnit::NanoSecond - DEFAULT_
ID_ SECOND  - The default identifier of 
TimeUnit::Second - DEFAULT_
ID_ WEEK  - The default identifier of 
TimeUnit::Week - DEFAULT_
ID_ YEAR  - The default identifier of 
TimeUnit::Year - DEFAULT_
TIME_ UNITS custom - The default identifiers taken from the 
standardfeature (withoutMonthandYear) - SYSTEMD_
TIME_ UNITS custom - The identifiers as defined in
systemd.time 
Traits§
- Numbers
Like base NumbersLikestrings can occur where usually a number would occur in the source string- Saturating
Into  - Conversion which saturates at the maximum or maximum instead of overflowing
 - Time
Units Like base - To be able to use the basic 
crate::parse::Parserthis trait needs to be implemented 
Functions§
- parse_
duration standard - Parse a string into a 
std::time::Durationby accepting astringsimilar to floating point with the default set of time units. 
Type Aliases§
- Delimiter
 - An ascii delimiter defined as closure.