wasmer_cli/utils/
timestamp.rs

1use time::{
2    Date, OffsetDateTime, PrimitiveDateTime, Time,
3    format_description::well_known::{Rfc2822, Rfc3339},
4};
5
6/// Try to parse the string as a timestamp in a number of well-known formats.
7///
8/// Supported formats,
9///
10/// - RFC 3339 (`2006-01-02T03:04:05-07:00`)
11/// - RFC 2822 (`Mon, 02 Jan 2006 03:04:05 MST`)
12/// - Date (`2006-01-02`)
13/// - Unix timestamp (`1136196245`)
14/// - Relative time (`10m` / `-1h`, `1d`)
15pub fn parse_timestamp_or_relative_time(
16    s: &str,
17    assume_negative_offset: bool,
18) -> Result<OffsetDateTime, anyhow::Error> {
19    parse_timestamp_or_relative_time_based(s, OffsetDateTime::now_utc(), assume_negative_offset)
20}
21
22/// See [`parse_timestamp_or_relative_time`].
23///
24/// NOTE: assumes a negative offset if time is specified in a format like "1h".
25pub fn parse_timestamp_or_relative_time_negative_offset(
26    s: &str,
27) -> Result<OffsetDateTime, anyhow::Error> {
28    parse_timestamp_or_relative_time(s, true)
29}
30
31/// See [`parse_timestamp_or_relative_time`].
32pub fn parse_timestamp_or_relative_time_based(
33    s: &str,
34    base: OffsetDateTime,
35    assume_negative_offset: bool,
36) -> Result<OffsetDateTime, anyhow::Error> {
37    if let Ok(t) = OffsetDateTime::parse(s, &Rfc3339) {
38        return Ok(t);
39    }
40    if let Ok(t) = OffsetDateTime::parse(s, &Rfc2822) {
41        return Ok(t);
42    }
43    if let Ok(t) = Date::parse(s, time::macros::format_description!("[year]-[month]-[day]")) {
44        return Ok(PrimitiveDateTime::new(t, Time::MIDNIGHT).assume_utc());
45    }
46    if let Ok(t) = OffsetDateTime::parse(s, time::macros::format_description!("[unix_timestamp]")) {
47        return Ok(t);
48    }
49
50    // Relative time.
51    let (is_negative, v) = match s.strip_prefix('-') {
52        Some(rest) => (true, rest),
53        // Note: `assume_negative_offset` forces offsets to be negative.
54        None => (assume_negative_offset, s.trim_start_matches('+')),
55    };
56
57    if let Ok(duration) = humantime::parse_duration(v) {
58        let time = if is_negative {
59            base - duration
60        } else {
61            base + duration
62        };
63
64        return Ok(time);
65    }
66
67    anyhow::bail!("Unable to parse the timestamp - no known format matched")
68}