Rust Date Format Codes
`%Y`, `%m`, and `%d` are format codes. One format string can shape a whole log line or file name, and the same string can also read text back into a value.
The date codes
One fixed date shows the core codes. `%e` pads with a space:
let date = NaiveDate::from_ymd_opt(2026, 10, 5).unwrap();
println!("year = {} month = {} day = {}", date.format("%Y"), date.format("%m"), date.format("%d"));
println!("short day = [{}]", date.format("%e"));
println!("names = {} {} {} {}", date.format("%a"), date.format("%A"), date.format("%b"), date.format("%B"));The clock codes
Hours, minutes, and seconds have their own codes. `%I` uses the 12-hour clock:
let dt = NaiveDate::from_ymd_opt(2026, 10, 22).unwrap().and_hms_milli_opt(14, 5, 9, 123).unwrap();
println!("24-hour clock = {}", dt.format("%H:%M:%S"));
println!("12-hour clock = {}", dt.format("%I:%M %p"));
println!("whole clock = {}", dt.format("%T"));Fractions of a second
`%S%.3f` keeps three fraction digits. The dot comes from the fraction code:
let dt = NaiveDate::from_ymd_opt(2026, 10, 22).unwrap().and_hms_milli_opt(14, 5, 9, 123).unwrap();
println!("with millis = {}", dt.format("%S%.3f"));
println!("digits only = {}", dt.format("%f"));
println!("dot form = {}", dt.format("%.f"));Offset codes need a zone
A naive value has no offset to print. Pin the value to UTC first:
let utc = NaiveDate::from_ymd_opt(2026, 10, 22).unwrap().and_hms_milli_opt(14, 5, 9, 123).unwrap().and_utc();
println!("offset = {}", utc.format("%z"));
println!("colon offset = {}", utc.format("%:z"));
println!("zone = {}", utc.format("%Z"));
println!("epoch code = {}", utc.format("%s"));Parse with the same string
The format must match the text shape. A wrong shape fails:
let parsed = NaiveDateTime::parse_from_str("22 Oct 2026 14:05", "%d %b %Y %H:%M").unwrap();
println!("parsed = {}", parsed);
println!("wrong shape works = {}", NaiveDateTime::parse_from_str("2026/10/22", "%Y-%m-%d").is_ok());Words and percent signs
Text in the format string stays in the output. `%j` counts from the start of the year:
let date = NaiveDate::from_ymd_opt(2026, 10, 22).unwrap();
println!("{}", date.format("Day %e of %B, day %j of the year, 100%%"));Example
// Cargo.toml: chrono = "0.4" (verified with chrono 0.4.45)
use chrono::DateTime;
fn main() {
let log_time = DateTime::parse_from_str("2026-10-22 14:05:09 +0000", "%Y-%m-%d %H:%M:%S %z").unwrap();
println!("machine = {}", log_time.format("%Y-%m-%dT%H:%M:%S%:z"));
println!("human = {}", log_time.format("%A %d %B %Y at %I:%M %p"));
println!("file name = {}", log_time.format("%Y%m%d-%H%M%S"));
println!("rfc3339 = {}", log_time.to_rfc3339());
}Key points
- Case matters in format codes.
- `%m` is the month.
- `%M` is the minute.
- Use `%e` for a space-padded day.
- Use `%d` for a zero-padded day.
- Use `%j` for the day of the year.
- Use `%s` for epoch seconds on a zoned value.
- Fraction codes differ.
- `%.3f` writes a dot and three digits.
- `%f` writes digits with no dot.
- Parsing returns a `Result`.
- Bad text gives an error, not a guessed date.
- Format codes are short % spellings that shape how a date or time is written and read back.
In this example, one log time is read with a format string. The `%z` code reads its UTC offset. Three new shapes then print the same moment. One shape suits machines. One shape suits people. One shape suits a file name.
Note
Plain words in a format string pass through as text.
Write `%%` when you need one real percent sign.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
Which code prints the minute?