TL;DR: I’ve written a httpdate
crate to parse and format dates found in HTTP. It has no dependencies and uses
std::time::SystemTime to store all times.
HTTP communicates some timestamps. To do this it uses an old format called
Sat, 15 Oct 2016 11:48:13 GMT. (For compatibility with ancient
endpoints it supports parsing two more formats.) While Rust has the excellent
chrono crate and the deprecated but usable time crate (chrono still
depends on it) for time handling they are both overkill for the task. These
crates do a lot of things that are generally useful if you work with dates but
in this case are not needed like timezones, extensive formatting and parsing
methods and a lot more.
I wrote a small crate called httpdate to parse a timestamp to a
std::time::SystemTime and format it as required for HTTP. It is both less code
(more then ten thousand lines vs about 300 lines) so it compiles in an instant
and it is faster because it is written specially for HTTP timestamps (not that
it would matter in normal use but some micro-benchmarks will be faster).
Using httpdate is very straightforward:
parse_http_date(s: &str) -> Result<SystemTime, ()> a date from HTTP is parsed.
The function tries to parse the string in all supported formats.
fmt_http_date(d: SystemTime) -> String a system time is formatted
to an IMF-fixdate.
Rusts standard system time is used to store the timestamps from HTTP internally. From the documentation:
SystemTimecannot be directly inspected, the
UNIX_EPOCHconstant is provided in this module as an anchor in time to learn information about a
SystemTime. By calculating the duration from this fixed point in time, a
SystemTimecan be converted to a human-readable time, or perhaps some other string representation.
To use a
SystemTime I first convert it to the number of seconds since the
epoch (sub seconds are discarded in HTTP):
let secs_since_epoch = v // the system time .duration_since(UNIX_EPOCH) // get the duration from the epoch .unwrap() // Dates prior to 1970 are not expected // common HTTP are either the current date, // last-modified dates or events in the future // like cache expiration. // Only if you do time-travel you may have problems. .as_secs(); // Convert the duration to an integer.
SystemTime is constructed by adding a duration to the epoch:
let time: SystemTime = UNIX_EPOCH + Duration::from_secs(1482490056);
The crate converts strings to an internal
DateTime struct first. This structure has
fields for time (second, minute, hour) and date (day, month, year, day of week). The
result is then converted to a
SystemTime. To get a HTTP date from a
the above steps are applied the other way, but calculating the day for a given moment
is more compex.