🎓 A1Learner
🔍

Rust Dates & Times

A date is a year, a month, and a day. Months have different lengths, and leap years add an extra day.

Make a date

from_ymd_opt takes year, month, day. The opt in the name means it can say no:

let date = NaiveDate::from_ymd_opt(2026, 10, 22).unwrap();
println!("date = {}", date);
println!("bad date exists = {}", NaiveDate::from_ymd_opt(2026, 2, 31).is_some());

Read the pieces

The Datelike trait gives a date its pieces. Bring it in with use chrono::Datelike:

let date = NaiveDate::from_ymd_opt(2026, 10, 22).unwrap();
println!("year = {}", date.year());
println!("month = {}", date.month());
println!("day = {}", date.day());
println!("weekday = {:?}", date.weekday());

Print a date your way

let date = NaiveDate::from_ymd_opt(2026, 10, 22).unwrap();
println!("{}", date.format("%A %d %B %Y"));
println!("{}", date.format("%d/%m/%Y"));

Turn text into a date

parse_from_str reads text in the shape your format describes. Month 13 does not exist, so the second check fails:

let date = NaiveDate::parse_from_str("22/10/2026", "%d/%m/%Y").unwrap();
println!("parsed = {}", date);
println!("wrong shape works = {}", NaiveDate::parse_from_str("2026-13-01", "%Y-%m-%d").is_ok());

Add days, count days

let start = NaiveDate::from_ymd_opt(2026, 10, 22).unwrap();
let end = start + Duration::days(10);
println!("ten days later = {}", end);
println!("days between = {}", (end - start).num_days());

The current name for a gap

`TimeDelta` is the current chrono name for a signed gap. It can point backwards:

let gap = TimeDelta::days(2) + TimeDelta::hours(3);
println!("gap hours = {}", gap.num_hours());
println!("backwards hours = {}", (-gap).num_hours());

Example

use chrono::{Datelike, Duration, NaiveDate};

fn main() {
    let start = NaiveDate::parse_from_str("22/10/2026", "%d/%m/%Y").unwrap();
    let end = start + Duration::days(45);

    println!("starts {}", start.format("%A %d %B %Y"));
    println!("ends {}", end.format("%A %d %B %Y"));
    println!("course length = {} days", (end - start).num_days());
    println!("ends in month {}", end.month());
}

Key points

  • NaiveDate is a date with no time and no time zone: just a year, a month and a day
  • The from_ymd_opt constructor returns an Option: None means the date does not exist, like 31 February
  • Format codes start with %.
  • %Y is the four-digit year.
  • %m is the month number.
  • %d is the day.
  • %A is the weekday name.
  • %B is the month name.
  • chrono also has NaiveTime for a time of day.
  • It has NaiveDateTime for a date and time together.
  • `Duration` in older chrono code is the former name for `TimeDelta`.
  • New code can use `TimeDelta`.
  • Add chrono = "0.4" under [dependencies] in Cargo.toml to use chrono dates.

In this example, a start date is parsed from the text "22/10/2026" with the format "%d/%m/%Y". Adding Duration::days(45) crosses two month ends. It lands on Sunday 06 December 2026. chrono counts the real days in October and November for you. Subtracting the dates gives the course length back, 45 days, and month() reads 12 from the end date. The Time Zones lesson pins them to real places.

Note

chrono dates can be compared with < and ==, and sorted like numbers — earliest first.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What does NaiveDate::from_ymd_opt(2026, 2, 31) give back?