Loading page…
Rust walkthroughs
Loading page…
Chrono is the de-facto standard library for date and time handling in Rust. It provides types for timezones, durations, parsing, formatting, and arithmetic. Chrono distinguishes between naive types (no timezone) and aware types (with timezone), preventing common datetime bugs at compile time.
Core types:
NaiveDate — date without timezoneNaiveTime — time without timezoneNaiveDateTime — combined date and time without timezoneDateTime<Tz> — date and time with timezone (e.g., DateTime<Utc>, DateTime<Local>)Duration — span of time for arithmeticChrono integrates well with serde for serialization and provides extensive parsing/formatting options.
# Cargo.toml
[dependencies]
chrono = "0.4"use chrono::{DateTime, Duration, Local, NaiveDate, NaiveDateTime, NaiveTime, Utc};
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 =====
let date = NaiveDate::from_ymd_opt(2024, 3, 15).unwrap();
println!("Date: {}", date);
let time = NaiveTime::from_hms_opt(14, 30, 0).unwrap();
println!("Time: {}", time);
let datetime = NaiveDateTime::new(date, time);
println!("DateTime: {}", datetime);
// With timezone
let utc_datetime = datetime.and_utc();
println!("UTC DateTime: {}", utc_datetime);
// ===== Parsing from Strings =====
let parsed_date = NaiveDate::parse_from_str("2024-03-15", "%Y-%m-%d").unwrap();
println!("Parsed date: {}", parsed_date);
let parsed_datetime = NaiveDateTime::parse_from_str(
"2024-03-15 14:30:00",
"%Y-%m-%d %H:%M:%S"
).unwrap();
println!("Parsed datetime: {}", parsed_datetime);
// Parse directly to DateTime<Utc>
let parsed_utc: DateTime<Utc> = "2024-03-15T14:30:00Z".parse().unwrap();
println!("Parsed UTC: {}", parsed_utc);
}use chrono::{DateTime, Local, NaiveDate, TimeZone, Utc};
fn main() {
let dt = Utc::now();
// RFC 3339 format (ISO 8601)
println!("RFC 3339: {}", dt.to_rfc3339());
// Custom format
println!("Custom: {}", dt.format("%Y-%m-%d %H:%M:%S"));
println!("Readable: {}", dt.format("%A, %B %d, %Y at %I:%M %p"));
// Common format specifiers
let now = Local::now();
println!("Year: {}", now.format("%Y")); // 2024
println!("Month: {}", now.format("%m")); // 03
println!("Day: {}", now.format("%d")); // 15
println!("Hour (24h): {}", now.format("%H")); // 14
println!("Hour (12h): {}", now.format("%I")); // 02
println!("Minute: {}", now.format("%M")); // 30
println!("Second: {}", now.format("%S")); // 45
println!("Weekday: {}", now.format("%A")); // Friday
println!("Month name: {}", now.format("%B")); // March
}use chrono::{Duration, NaiveDate, NaiveDateTime, NaiveTime, Utc};
fn main() {
// ===== Creating Durations =====
let five_days = Duration::days(5);
let three_hours = Duration::hours(3);
let thirty_minutes = Duration::minutes(30);
let thousand_millis = Duration::milliseconds(1000);
// Duration arithmetic
let combined = five_days + three_hours;
println!("Combined: {} days, {} hours", combined.num_days(), combined.num_hours());
// ===== Date Arithmetic =====
let date = NaiveDate::from_ymd_opt(2024, 3, 15).unwrap();
let later = date + Duration::days(7);
println!("One week later: {}", later);
let earlier = date - Duration::days(7);
println!("One week earlier: {}", earlier);
// ===== DateTime Arithmetic =====
let dt = NaiveDate::from_ymd_opt(2024, 3, 15).unwrap()
.and_hms_opt(10, 0, 0).unwrap();
let after = dt + Duration::hours(2) + Duration::minutes(30);
println!("After 2h 30m: {}", after);
// ===== Duration Between Dates =====
let start = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
let end = NaiveDate::from_ymd_opt(2024, 12, 31).unwrap();
let duration = end.signed_duration_since(start);
println!("Days in year: {}", duration.num_days());
// Compare dates
if end > start {
println!("End is after start");
}
// ===== Datetime Differences =====
let dt1 = Utc::now();
let dt2 = dt1 + Duration::hours(5);
let diff = dt2.signed_duration_since(dt1);
println!("Difference: {} minutes", diff.num_minutes());
}use chrono::{DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, TimeZone, Utc};
fn main() {
// ===== UTC to Local =====
let utc_time: DateTime<Utc> = Utc::now();
let local_time: DateTime<Local> = utc_time.with_timezone(&Local);
println!("UTC: {}", utc_time);
println!("Local: {}", local_time);
// ===== Specific Timezones =====
let est = FixedOffset::west_opt(5 * 3600).unwrap(); // UTC-5
let pst = FixedOffset::west_opt(8 * 3600).unwrap(); // UTC-8
let ist = FixedOffset::east_opt(5 * 3600 + 1800).unwrap(); // UTC+5:30
let utc_dt = Utc::now();
let est_dt: DateTime<FixedOffset> = utc_dt.with_timezone(&est);
let pst_dt: DateTime<FixedOffset> = utc_dt.with_timezone(&pst);
println!("EST: {}", est_dt);
println!("PST: {}", pst_dt);
// ===== Create DateTime with Timezone =====
let naive = NaiveDate::from_ymd_opt(2024, 3, 15).unwrap()
.and_hms_opt(14, 30, 0).unwrap();
let with_offset = est.from_utc_datetime(&naive);
println!("EST DateTime: {}", with_offset);
// ===== Parse with Timezone =====
let dt: DateTime<FixedOffset> = "2024-03-15T14:30:00-05:00".parse().unwrap();
println!("Parsed with offset: {}", dt);
// Convert to UTC
let utc: DateTime<Utc> = dt.with_timezone(&Utc);
println!("As UTC: {}", utc);
}use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, Timelike, Weekday};
fn main() {
let dt = NaiveDate::from_ymd_opt(2024, 3, 15).unwrap()
.and_hms_opt(14, 30, 45).unwrap();
// ===== Date Components =====
println!("Year: {}", dt.year());
println!("Month: {}", dt.month());
println!("Day: {}", dt.day());
println!("Hour: {}", dt.hour());
println!("Minute: {}", dt.minute());
println!("Second: {}", dt.second());
// Weekday
let weekday = dt.weekday();
println!("Weekday: {:?} ({})", weekday, weekday.num_days_from_monday());
// Day of year
println!("Day of year: {}", dt.ordinal());
// ISO week
let iso_week = dt.iso_week();
println!("ISO week: {}-{}", iso_week.year(), iso_week.week());
// ===== Modify Components =====
let next_month = dt.with_month(4).unwrap();
let next_year = dt.with_year(2025).unwrap();
let midnight = dt.with_hour(0).unwrap().with_minute(0).unwrap().with_second(0).unwrap();
println!("Next month: {}", next_month);
println!("Next year: {}", next_year);
println!("Midnight: {}", midnight);
// ===== Date Iteration =====
let start = NaiveDate::from_ymd_opt(2024, 3, 1).unwrap();
let end = NaiveDate::from_ymd_opt(2024, 3, 7).unwrap();
let mut current = start;
while current <= end {
println!("{} - {:?}", current, current.weekday());
current = current + Duration::days(1);
}
// Find next Monday
let date = NaiveDate::from_ymd_opt(2024, 3, 15).unwrap(); // Friday
let mut next_monday = date;
while next_monday.weekday() != Weekday::Mon {
next_monday = next_monday + Duration::days(1);
}
println!("Next Monday after {}: {}", date, next_monday);
}# Cargo.toml
[dependencies]
chrono = { version = "0.4", features = ["serde"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"use chrono::{DateTime, NaiveDate, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Event {
name: String,
#[serde(with = "chrono::serde::ts_seconds")]
timestamp: DateTime<Utc>,
#[serde(with = "chrono::serde::ts_milliseconds")]
created_at: DateTime<Utc>,
date: NaiveDate,
}
fn main() {
let event = Event {
name: "Meeting".to_string(),
timestamp: Utc::now(),
created_at: Utc::now(),
date: NaiveDate::from_ymd_opt(2024, 3, 15).unwrap(),
};
// Serialize to JSON
let json = serde_json::to_string(&event).unwrap();
println!("JSON: {}", json);
// Deserialize from JSON
let parsed: Event = serde_json::from_str(&json).unwrap();
println!("Parsed: {:?}", parsed);
}use chrono::{DateTime, Datelike, Duration, Local, NaiveDate, NaiveDateTime, TimeZone, Utc};
// Age calculation
fn calculate_age(birth_date: NaiveDate) -> i32 {
let today = Local::now().date_naive();
let mut age = today.year() - birth_date.year();
if today.month() < birth_date.month() ||
(today.month() == birth_date.month() && today.day() < birth_date.day()) {
age -= 1;
}
age
}
// Time ago formatter
fn time_ago(dt: DateTime<Utc>) -> String {
let now = Utc::now();
let diff = now.signed_duration_since(dt);
if diff.num_minutes() < 1 {
"just now".to_string()
} else if diff.num_minutes() < 60 {
format!("{} minutes ago", diff.num_minutes())
} else if diff.num_hours() < 24 {
format!("{} hours ago", diff.num_hours())
} else if diff.num_days() < 7 {
format!("{} days ago", diff.num_days())
} else {
format!("{} weeks ago", diff.num_weeks())
}
}
// Get start and end of day
fn start_of_day(dt: DateTime<Utc>) -> DateTime<Utc> {
dt.with_hour(0).unwrap()
.with_minute(0).unwrap()
.with_second(0).unwrap()
.with_nanosecond(0).unwrap()
}
fn end_of_day(dt: DateTime<Utc>) -> DateTime<Utc> {
dt.with_hour(23).unwrap()
.with_minute(59).unwrap()
.with_second(59).unwrap()
.with_nanosecond(999_999_999).unwrap()
}
// Check if date is weekend
fn is_weekend(date: NaiveDate) -> bool {
matches!(date.weekday(), chrono::Weekday::Sat | chrono::Weekday::Sun)
}
fn main() {
// Age calculation
let birth = NaiveDate::from_ymd_opt(1990, 6, 15).unwrap();
println!("Age: {}", calculate_age(birth));
// Time ago
let past = Utc::now() - Duration::hours(3);
println!("Time ago: {}", time_ago(past));
// Start/end of day
let now = Utc::now();
println!("Start of day: {}", start_of_day(now));
println!("End of day: {}", end_of_day(now));
// Weekend check
let saturday = NaiveDate::from_ymd_opt(2024, 3, 16).unwrap();
println!("Is weekend: {}", is_weekend(saturday));
}Local::now() for current local time, Utc::now() for UTCNaiveDate::from_ymd_opt(year, month, day) (safe, returns Option)NaiveTime::from_hms_opt(hour, min, sec)NaiveDateTime::new(date, time) then add timezone with .and_utc()parse_from_str(str, format) using strftime specifiers.format("%Y-%m-%d %H:%M:%S") — see strftime documentationDuration::days(), Duration::hours(), etc. for time spansdate + Duration::days(7)dt2.signed_duration_since(dt1).year(), .month(), .day(), .hour(), .weekday().with_year(), .with_month(), .with_hour(), etc.dt.with_timezone(&Local) or dt.with_timezone(&FixedOffset)chrono = { version = "0.4", features = ["serde"] }_opt methods for safe construction (returns Option instead of panicking)