http-date 0.2.0

Parsing and formatting of HTTP date values (RFC 9110)
Documentation

http-date

Parsing and formatting of HTTP date values as defined in RFC 9110 § 5.6.7.

The three HTTP date formats are supported, and the format a value was parsed from is preserved so that re-encoding reproduces the original representation:

Format Example Notes
IMF-fixdate Sun, 06 Nov 1994 08:49:37 GMT Preferred; the only format senders must generate
RFC 850 Sunday, 06-Nov-94 08:49:37 GMT Obsolete; two-digit year (0–99)
asctime Sun Nov 6 08:49:37 1994 Obsolete; space-padded day

decode enforces the grammar strictly (case-sensitive day/month names, exact fixed-width fields, no trailing data) and validates component ranges. HttpDate is constructor-only, so every value is guaranteed well-formed and encode cannot fail.

Usage

Parsing

use http_date::decode;

let date = decode("Sun, 06 Nov 1994 08:49:37 GMT").unwrap();
assert!(date.is_imf_fixdate());

All three formats are accepted:

use http_date::decode;

assert!(decode("Sunday, 06-Nov-94 08:49:37 GMT").unwrap().is_rfc850());
assert!(decode("Sun Nov  6 08:49:37 1994").unwrap().is_asctime());

Formatting

use http_date::{decode, encode};

let date = decode("Sun, 06 Nov 1994 08:49:37 GMT").unwrap();
assert_eq!(encode(&date), "Sun, 06 Nov 1994 08:49:37 GMT");

Building from components

use http_date::{Date, DateTime, DayName, HttpDate, Time};

let date = HttpDate::imf_fixdate(DateTime {
    dayname: DayName::Sun,
    date: Date::new(1994, 11, 6).expect("valid date"),
    time: Time::new(8, 49, 37).expect("valid time"),
});
assert_eq!(date.to_string(), "Sun, 06 Nov 1994 08:49:37 GMT");

HttpDate::rfc850 returns a Result because RFC 850 can only represent the years 0–99; HttpDate::imf_fixdate and HttpDate::asctime are infallible.

Chrono integration

Enabled with the chrono feature:

[dependencies]
http-date = { version = "0.2", features = ["chrono"] }

Convert HttpDate to a UTC datetime and back:

use chrono::{DateTime, Utc};
use http_date::decode;

let date = decode("Sun, 06 Nov 1994 08:49:37 GMT").unwrap();

// HttpDate -> chrono::DateTime<Utc>
let chrono: DateTime<Utc> = DateTime::try_from(date).unwrap();
assert_eq!(chrono.to_rfc3339(), "1994-11-06T08:49:37+00:00");

// chrono::DateTime<Utc> -> HttpDate (always IMF-fixdate)
let back = http_date::HttpDate::try_from(chrono).unwrap();
assert!(back.is_imf_fixdate());

Notes:

  • RFC 850's two-digit year is interpreted with the POSIX century window (69–99 → 1900s, 0–68 → 2000s).
  • Converting to chrono fails on impossible calendar dates (e.g. 31 February), which decode accepts but chrono does not.
  • Converting from chrono fails for years outside 0–9999, which cannot be represented in a four-digit HTTP date year.

Features

Feature Default Description
chrono off Conversions between HttpDate and chrono::DateTime<Utc>

Development

The project uses a Nix flake with two dev shells, managed via direnv:

nix develop             # stable toolchain, just, cargo-nextest, rust-analyzer
nix develop .#fuzz      # nightly toolchain, cargo-fuzz, clang (for fuzzing)

Common tasks are wrapped in a justfile:

just test        # unit + proptest + doctests (--all-features)
just lint        # clippy with -D warnings
just fmt         # rustfmt
just doc         # build API docs
just ci          # fmt-check + lint + test

Fuzzing uses cargo-fuzz with two targets: roundtrip (decode never panics and encode/decode is stable) and chrono_roundtrip (chrono conversion fixed point):

just fuzz roundtrip 2000      # run a target with a run cap
just fuzz chrono_roundtrip    # run until a crash is found
just fuzz-list

License

Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0).