Skip to content

Chrono

Developer UtilitiesDate & TimeRust

What it is

Chrono provides date and time handling for Rust: timezone-aware timestamps, parsing, formatting and duration arithmetic.

DateTime<Utc> for instants, NaiveDate for calendar dates without a zone, and TimeDelta for arithmetic. Formatting uses strftime-style patterns.

Installation

cargo add chrono --features serde

Getting started

The smallest useful thing you can do with it, and what each part means.

Instants, parsing and formatting
use chrono::{DateTime, Utc, NaiveDate, TimeDelta};

let now: DateTime<Utc> = Utc::now();

// RFC 3339 is the right format for APIs and storage.
let text = now.to_rfc3339();
let parsed: DateTime<Utc> = text.parse()?;

let due = now + TimeDelta::days(30);
let overdue = Utc::now() > due;

// A calendar date with no time zone — a birthday, not an instant.
let birthday = NaiveDate::from_ymd_opt(1990, 5, 17).expect("valid date");
println!("{}", now.format("%Y-%m-%d %H:%M:%S UTC"));
The distinction matters: a DateTime<Utc> is a point in time, a NaiveDate is a calendar day. Storing a birthday as a UTC timestamp shifts it by a day for some users.

Advanced usage

Where the library earns its place over a simpler alternative.

Time zones done correctly
use chrono_tz::Europe::London;
use chrono::TimeZone;

let utc = Utc::now();
let local = utc.with_timezone(&London);

// Local times are ambiguous around DST transitions, so this returns
// a LocalResult rather than a value.
match London.with_ymd_and_hms(2026, 10, 25, 1, 30, 0) {
    chrono::LocalResult::Single(dt) => println!("{dt}"),
    chrono::LocalResult::Ambiguous(a, b) => println!("occurs twice: {a} / {b}"),
    chrono::LocalResult::None => println!("does not exist"),
}
Chrono forces you to handle the fact that a local time can occur twice or never during a DST change. Most date libraries silently pick one, which is where scheduling bugs come from.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

input contains invalid characters when parsing
The format does not match. Use parse_from_str with an explicit format, or ensure the input is RFC 3339.
Times shift by an hour twice a year
Arithmetic was done in local time. Convert to UTC, do the arithmetic, then convert back.

Best practices

  • Store and transmit timestamps in UTC; convert to local only for display.
  • Use NaiveDate for calendar dates and DateTime<Utc> for instants — they are not interchangeable.
  • Prefer the _opt constructors; the panicking versions were deprecated for good reason.
  • Enable the serde feature so timestamps serialise as RFC 3339 automatically.

Background

Why it exists, and what it was reacting to.

The standard library only offers SystemTime and Instant. Chrono supplies the calendar layer — civil dates, time zones and human-readable formatting — that real applications need.