How do I handle dates and times in Rust?
Walkthrough
Date and time handling is essential for many applications. The chrono crate provides comprehensive datetime functionality including parsing, formatting, time zones, and arithmetic. It's the de facto standard for datetime operations in Rust.
Key types:
NaiveDate/NaiveTime/NaiveDateTime— dates and times without timezone awarenessDateTime<Tz>— timezone-aware date and time, commonlyDateTime<Utc>orDateTime<Local>Duration— represents time spans for arithmeticParseResult— handles parsing errors from string-to-datetime conversions
Use naive types when timezones don't matter, and timezone-aware types when they do.
Code Example
# Cargo.toml
[dependencies]
chrono = "0.4"use chrono::{
DateTime, Duration, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc,
format::strftime::StrftimeItems,
};
fn main() {
// ===== Current Date and Time =====
let now = Local::now();
println!("Local now: {}", now);
let utc_now = Utc::now();
println!("UTC now: {}", utc_now);
// ===== Creating Specific Dates/Times =====
// Naive types (no timezone)
let date = NaiveDate::from_ymd_opt(2024, 3, 15).expect("Invalid date");
let time = NaiveTime::from_hms_opt(14, 30, 45).expect("Invalid time");
let datetime = NaiveDateTime::new(date, time);
println!("Naive datetime: {}", datetime);
// Timezone-aware datetime
let utc_datetime = Utc.with_ymd_and_hms(2024, 3, 15, 14, 30, 45).unwrap();
println!("UTC datetime: {}", utc_datetime);
// ===== Parsing from Strings =====
// Common format (ISO 8601)
let parsed: DateTime<Utc> = "2024-03-15T14:30:45Z".parse().unwrap();
println!("Parsed UTC: {}", parsed);
// Custom format
let custom = NaiveDateTime::parse_from_str("15-03-2024 14:30:45", "%d-%m-%Y %H:%M:%S")
.unwrap();
println!("Custom parsed: {}", custom);
// Parse date only
let just_date = NaiveDate::parse_from_str("2024-03-15", "%Y-%m-%d").unwrap();
println!("Just date: {}", just_date);
// ===== Formatting =====
let dt = Utc::now();
println!("Default: {}", dt);
println!("RFC 2822: {}", dt.to_rfc2822());
println!("RFC 3339: {}", dt.to_rfc3339());
println!("Custom: {}", dt.format("%A, %B %d, %Y at %I:%M %p"));
// ===== Date/Time Arithmetic =====
let start = Utc::now();
// Add/subtract durations
let later = start + Duration::hours(3);
let earlier = start - Duration::days(7);
println!("3 hours later: {}", later);
println!("7 days earlier: {}", earlier);
// Duration between datetimes
let diff = later.signed_duration_since(start);
println!("Difference: {} hours", diff.num_hours());
// ===== Date Components =====
let dt = Local::now();
println!("Year: {}", dt.year());
println!("Month: {}", dt.month());
println!("Day: {}", dt.day());
println!("Hour: {}", dt.hour());
println!("Minute: {}", dt.minute());
println!("Weekday: {:?}", dt.weekday());
println!("Day of year: {}", dt.ordinal());
// ===== Date Range Operations =====
let start_date = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
let end_date = NaiveDate::from_ymd_opt(2024, 12, 31).unwrap();
let days_in_year = (end_date - start_date).num_days();
println!("Days in 2024: {}", days_in_year);
// Iterate over dates
let mut current = start_date;
while current <= end_date {
if current.weekday() == chrono::Weekday::Fri && current.day() == 13 {
println!("Friday the 13th: {}", current);
}
current = current + Duration::days(1);
}
}Working with Time Zones
use chrono::{DateTime, FixedOffset, Utc, TimeZone};
fn main() {
// Create a fixed offset timezone (UTC+8)
let singapore = FixedOffset::east_opt(8 * 3600).unwrap();
// Convert UTC to Singapore time
let utc_time = Utc::now();
let singapore_time: DateTime<FixedOffset> = utc_time.with_timezone(&singapore);
println!("UTC: {}", utc_time);
println!("Singapore: {}", singapore_time);
}Summary
- Use
Local::now()/Utc::now()for current time;NaiveDate::from_ymd_opt()for specific dates parse()handles ISO 8601 by default;parse_from_str()accepts custom formats with strftime specifiers- Format dates with
.format()using specifiers like%Y,%m,%d,%H,%M,%S - Add and subtract
Durationfor datetime arithmetic; usesigned_duration_since()for differences - Access components like
.year(),.month(),.weekday()directly on datetime objects - Use
Naive*types when timezones don't matter;DateTime<Tz>when they do - The
unresolvedfeature flag enables serde serialization support
