Repository: time-rs/time

Issue #193: tzdb support
Created: 2019-12-04T16:14:01Z
This is a general tracking issue for all support related to the IANA Time Zone database.
At some point in the future, my hope is to have full support for the tzdb via a ZonedDateTime struct and a Period type.
General inspiration could come from C++20's proposed API for timezones [ref]. It should be possible to build a static/const singleton by using a build script.

Duplicate issue #423: Support Parsing Named Timezones
Created: 2022-01-05T22:40:00Z
I'm building a simple demo application which maintains a list of X509 certificates obtained from www.googleapis.com/oauth2/v1/certs. These certificates are used in Google's OAuth flow, these certificates sign and can be used to verify the returned JWT tokens. As part of my demo, I'm writing a service to wrap my certificate store which runs at an interval to refresh the certificates, based on the value of the expires HTTP header.
I'm using time because of the localtime_r security issue in chrono. I know it's fairly rare, but I like to have my code pass cargo audit.
Essentially this boils down to a loop:
loop {
    let resp = isahc::get_async("https://www.googleapis.com/oauth2/v1/certs").await?;

    let expires: OffsetDateTime = resp.headers().get("expires")
        .map(|h| h.to_str().unwrap())
        .map(|s| parse_expires_date(s))
        .unwrap();

    update_certificate_store(resp.json().await?);

    sleep_until(expires);
}
I was able to figure out how to parse datetimes using the format_description! macro; it wasn't easy but I was able to compile a description:
static EXPIRES_TIME_FORMAT: &'static [FormatItem<'static>] = format_description!(
    "[weekday repr:short], [day padding:zero] [month repr:short] [year repr:full] [hour repr:24]:[minute padding:zero]:[second padding:zero]"
);
The format of the expires header looks like this:
Thu, 06 Jan 2022 02:53:35 GMT

This is a well-known and widely used format described in RFC 7231.
I've written a test case:
static EXPIRES_TIME_FORMAT: &'static [FormatItem<'static>] = format_description!(
    "[weekday repr:short], [day padding:zero] [month repr:short] [year repr:full] [hour repr:24]:[minute padding:zero]:[second padding:zero]"
);

const EXPIRES_EXAMPLE: &'static str = "Thu, 06 Jan 2022 02:53:35";

#[test]
fn test_expires_header_parse() {
    let date = OffsetDateTime::parse(EXPIRES_EXAMPLE, EXPIRES_TIME_FORMAT).unwrap();

    println!("{:?}", date);
}
This unfortunately fails at runtime:
called `Result::unwrap()` on an `Err` value: TryFromParsed(InsufficientInformation)
thread 'google::tests::test_expires_header_parse' panicked at 'called `Result::unwrap()` on an `Err` value: TryFromParsed(InsufficientInformation)'

The only way I can get this to work is:

Change the string datetime to Thu, 06 Jan 2022 02:53:35 00:00, replacing GMT with the hours/minutes UTC offset.
Append [offset_hour padding:zero]:[offset_minute padding:zero] to the format description.

In the format description documentation, I don't see a way to specify a timezone by name, which makes parsing this HTTP date string impossible.
I can probably work around this issue by using regular expressions and another crate to replace the timezone name with the hours/minutes offset, but if this crate is going to be the default choice for the Rust community for datetime formatting/parsing/etc. we should probably support parsing timezones by name.
Is there any way that I can help with a fix?

Closing comment (2022-01-05T22:58:20Z): I have not checked for the nuances of the format, but it appears to be roughly similar to RFC2822. If this is sufficient for your use case, it's already implemented and will be included in the next release.

I'll take a look at that RFC. Hopefully the implementation of this will cover parsing the expires header as well, as that would be very convenient.

In terms of actually supporting time zone names, this is unlikely. While GMT is unambiguous to my knowledge, other names are not. What does "CST" refer to? US central time, Mexico central time, or China standard time?

Yes, you're absolutely right. I wish the format would be more like ISO-8601 and use either an explicit hours/minutes offset or Z for UTC. I think for my use-case I'll just replace GMT with 00:00 and then parse the string. I don't know if any implementations out there give timezone abbreviations other than GMT.

Even then this would require tzdb integration, which is tracked in #193.

Yes, saw that issue, that would be very helpful as an addition I think. Hopefully for static builds it would also be possible to bundle the timezone file into the binary to make sure there are no system dependencies at runtime.