Loading page…
Rust walkthroughs
Loading page…
Chrono is a comprehensive date and time library for Rust. It provides robust support for parsing, formatting, and manipulating dates, times, and time zones. Chrono is designed to be correct, handling edge cases like leap seconds, time zone transitions, and calendar arithmetic properly.
Key concepts:
strftime-like format specifiersWhen to use Chrono:
When NOT to use Chrono:
std::time::Instant)std::time::SystemTime)use chrono::{DateTime, Utc, Local, TimeZone};
fn main() {
// Current UTC time
let now_utc: DateTime<Utc> = Utc::now();
println!("UTC: {}", now_utc);
// Current local time
let now_local: DateTime<Local> = Local::now();
println!("Local: {}", now_local);
// Individual components
println!("Year: {}", now_utc.year());
println!("Month: {}", now_utc.month());
println!("Day: {}", now_utc.day());
println!("Hour: {}", now_utc.hour());
println!("Minute: {}", now_utc.minute());
println!("Second: {}", now_utc.second());
}use chrono::{NaiveDate, NaiveTime, NaiveDateTime, Utc, TimeZone};
fn main() {
// Create a date
let date = NaiveDate::from_ymd_opt(2024, 1, 15).unwrap();
println!("Date: {}", date);
// Create a time
let time = NaiveTime::from_hms_opt(14, 30, 0).unwrap();
println!("Time: {}", time);
// Combine date and time (naive - no timezone)
let naive_dt = NaiveDateTime::new(date, time);
println!("Naive DateTime: {}", naive_dt);
// Add timezone (UTC)
let dt_utc = Utc.from_utc_datetime(&naive_dt);
println!("DateTime UTC: {}", dt_utc);
}use chrono::{Duration, NaiveDate, Utc, DateTime};
fn main() {
let now = Utc::now();
// Add/subtract duration
let tomorrow = now + Duration::days(1);
let yesterday = now - Duration::days(1);
let next_week = now + Duration::weeks(1);
let in_2_hours = now + Duration::hours(2);
println!("Now: {}", now);
println!("Tomorrow: {}", tomorrow);
println!("Yesterday: {}", yesterday);
// Duration between two dates
let start = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
let end = NaiveDate::from_ymd_opt(2024, 12, 31).unwrap();
let duration = end - start;
println!("Days in year: {}", duration.num_days());
}use chrono::{DateTime, Utc, Local};
fn main() {
let now = Utc::now();
// Default format
println!("Default: {}", now);
// RFC 2822 format
println!("RFC 2822: {}", now.to_rfc2822());
// RFC 3339 format (ISO 8601)
println!("RFC 3339: {}", now.to_rfc3339());
// Custom format
println!("Custom: {}", now.format("%Y-%m-%d %H:%M:%S"));
println!("Pretty: {}", now.format("%A, %B %d, %Y at %I:%M %p"));
}use chrono::{NaiveDate, NaiveDateTime, DateTime, Utc, TimeZone};
fn main() {
// Parse date
let date = NaiveDate::parse_from_str("2024-01-15", "%Y-%m-%d").unwrap();
println!("Date: {}", date);
// Parse datetime
let dt = NaiveDateTime::parse_from_str("2024-01-15 14:30:00", "%Y-%m-%d %H:%M:%S").unwrap();
println!("DateTime: {}", dt);
// Parse from RFC 3339
let dt_rfc = DateTime::parse_from_rfc3339("2024-01-15T14:30:00Z").unwrap();
println!("RFC 3339: {}", dt_rfc);
// Parse from RFC 2822
let dt_2822 = DateTime::parse_from_rfc2822("Mon, 15 Jan 2024 14:30:00 +0000").unwrap();
println!("RFC 2822: {}", dt_2822);
}use chrono::{DateTime, Utc, Local, FixedOffset, TimeZone};
fn main() {
let now_utc: DateTime<Utc> = Utc::now();
// Convert to local timezone
let now_local: DateTime<Local> = now_utc.with_timezone(&Local);
println!("Local: {}", now_local);
// Fixed offset timezone (UTC+8)
let offset = FixedOffset::east_opt(8 * 3600).unwrap(); // 8 hours in seconds
let now_singapore: DateTime<FixedOffset> = now_utc.with_timezone(&offset);
println!("Singapore: {}", now_singapore);
// UTC-5 (Eastern Time without DST)
let est = FixedOffset::west_opt(5 * 3600).unwrap();
let now_est: DateTime<FixedOffset> = now_utc.with_timezone(&est);
println!("EST: {}", now_est);
}use chrono::{DateTime, Utc, TimeZone};
fn main() {
// Current Unix timestamp
let now = Utc::now();
let timestamp = now.timestamp();
println!("Unix timestamp: {}", timestamp);
// From timestamp to DateTime
let from_ts: DateTime<Utc> = Utc.timestamp_opt(1700000000, 0).unwrap();
println!("From timestamp: {}", from_ts);
// With milliseconds
let timestamp_millis = now.timestamp_millis();
println!("Timestamp (ms): {}", timestamp_millis);
// With nanoseconds
let timestamp_nanos = now.timestamp_nanos_opt().unwrap();
println!("Timestamp (ns): {}", timestamp_nanos);
}use chrono::{NaiveDate, Weekday, Datelike};
fn main() {
let date = NaiveDate::from_ymd_opt(2024, 1, 15).unwrap();
// Get weekday
let weekday = date.weekday();
println!("Weekday: {:?}", weekday); // Monday
// Week number (ISO week)
let iso_week = date.iso_week();
println!("ISO Week: {}-{:02}", iso_week.year(), iso_week.week());
// Day of year
let day_of_year = date.ordinal();
println!("Day of year: {}", day_of_year);
// Is weekend?
let is_weekend = matches!(weekday, Weekday::Sat | Weekday::Sun);
println!("Is weekend: {}", is_weekend);
}use chrono::{NaiveDate, NaiveDateTime, Utc, DateTime};
fn main() {
let date1 = NaiveDate::from_ymd_opt(2024, 1, 15).unwrap();
let date2 = NaiveDate::from_ymd_opt(2024, 6, 20).unwrap();
// Comparison
println!("date1 < date2: {}", date1 < date2);
println!("Equal: {}", date1 == date1);
// Duration between dates
let diff = date2 - date1;
println!("Days between: {}", diff.num_days());
// Check if date is between two dates
let middle = NaiveDate::from_ymd_opt(2024, 3, 1).unwrap();
let is_between = date1 < middle && middle < date2;
println!("March 1st is between: {}", is_between);
}use chrono::{NaiveDate, Duration};
fn main() {
let start = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
let end = NaiveDate::from_ymd_opt(2024, 1, 7).unwrap();
// Iterate over dates
let mut current = start;
while current <= end {
println!("{} - {:?}", current, current.weekday());
current = current + Duration::days(1);
}
}use chrono::{DateTime, Utc, Duration};
fn humanize_duration(dt: DateTime<Utc>) -> String {
let now = Utc::now();
let diff = now - 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 {
format!("{} days ago", diff.num_days())
}
}
fn main() {
let past = Utc::now() - Duration::minutes(30);
println!("{}", humanize_duration(past));
let past2 = Utc::now() - Duration::hours(5);
println!("{}", humanize_duration(past2));
}use chrono::{NaiveDate, Datelike};
fn main() {
let date = NaiveDate::from_ymd_opt(2024, 1, 31).unwrap();
// Add months (handles overflow)
// Note: Chrono doesn't have month arithmetic directly
// Use with_month or checked_add_months
// Last day of next month
let next_month = if date.month() == 12 {
NaiveDate::from_ymd_opt(date.year() + 1, 1, 31)
} else {
NaiveDate::from_ymd_opt(date.year(), date.month() + 1, 31)
};
// Note: January 31 + 1 month doesn't have Feb 31
// Chrono handles this with checked arithmetic
// Get number of days in month
let days_in_month = NaiveDate::from_ymd_opt(2024, 2, 1).unwrap()
.with_day(28).unwrap() // Try 28 first (always valid)
.with_day(29).unwrap(); // Try 29 (leap year check)
println!("Feb 2024 has 29 days (leap year)");
// Check leap year
let is_leap = 2024 % 4 == 0 && (2024 % 100 != 0 || 2024 % 400 == 0);
println!("2024 is leap year: {}", is_leap);
}use chrono::{NaiveDate, NaiveDateTime};
fn parse_flexible(input: &str) -> Option<NaiveDateTime> {
// Try multiple formats
let formats = [
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%dT%H:%M:%S",
"%Y/%m/%d %H:%M:%S",
"%d-%m-%Y %H:%M:%S",
"%Y-%m-%d",
];
for fmt in formats {
if let Ok(dt) = NaiveDateTime::parse_from_str(input, fmt) {
return Some(dt);
}
// Try as date only
if let Ok(date) = NaiveDate::parse_from_str(input, fmt) {
return Some(date.and_hms_opt(0, 0, 0).unwrap());
}
}
None
}
fn main() {
let inputs = [
"2024-01-15 14:30:00",
"2024-01-15T14:30:00",
"2024/01/15 14:30:00",
"2024-01-15",
];
for input in inputs {
if let Some(dt) = parse_flexible(input) {
println!("Parsed '{}': {}", input, dt);
}
}
}use chrono::NaiveDate;
fn is_valid_date(year: i32, month: u32, day: u32) -> bool {
NaiveDate::from_ymd_opt(year, month, day).is_some()
}
fn main() {
println!("2024-01-15: {}", is_valid_date(2024, 1, 15)); // true
println!("2024-02-30: {}", is_valid_date(2024, 2, 30)); // false
println!("2023-02-29: {}", is_valid_date(2023, 2, 29)); // false (not leap year)
println!("2024-02-29: {}", is_valid_date(2024, 2, 29)); // true (leap year)
println!("2024-13-01: {}", is_valid_date(2024, 13, 1)); // false
}use chrono::{DateTime, Utc, Serde};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Event {
name: String,
#[serde(with = "Serde")]
timestamp: DateTime<Utc>,
}
fn main() {
let event = Event {
name: "Meeting".to_string(),
timestamp: Utc::now(),
};
let json = serde_json::to_string(&event).unwrap();
println!("JSON: {}", json);
let parsed: Event = serde_json::from_str(&json).unwrap();
println!("Parsed: {:?}", parsed);
}use chrono::{DateTime, Utc, Duration};
fn time_until(target: DateTime<Utc>) -> (i64, i64, i64) {
let now = Utc::now();
let diff = target - now;
let total_seconds = diff.num_seconds();
let hours = total_seconds / 3600;
let minutes = (total_seconds % 3600) / 60;
let seconds = total_seconds % 60;
(hours, minutes, seconds)
}
fn main() {
// Target: 24 hours from now
let target = Utc::now() + Duration::hours(24);
let (h, m, s) = time_until(target);
println!("Time remaining: {}h {}m {}s", h, m, s);
}use chrono::{NaiveDate, Weekday, Duration, Datelike};
fn is_business_day(date: NaiveDate) -> bool {
!matches!(date.weekday(), Weekday::Sat | Weekday::Sun)
}
fn add_business_days(start: NaiveDate, days: u32) -> NaiveDate {
let mut current = start;
let mut added = 0;
while added < days {
current = current + Duration::days(1);
if is_business_day(current) {
added += 1;
}
}
current
}
fn main() {
let start = NaiveDate::from_ymd_opt(2024, 1, 15).unwrap(); // Monday
let five_business_days = add_business_days(start, 5);
println!("5 business days from Monday: {} ({:?})",
five_business_days, five_business_days.weekday());
}use chrono::{NaiveDate, Local, Datelike};
fn calculate_age(birthday: NaiveDate) -> u32 {
let today = Local::now().date_naive();
let mut age = today.year() - birthday.year();
// Adjust if birthday hasn't occurred this year
let birthday_this_year = birthday
.with_year(today.year())
.unwrap();
if birthday_this_year > today {
age -= 1;
}
age as u32
}
fn main() {
let birthday = NaiveDate::from_ymd_opt(1990, 6, 15).unwrap();
println!("Age: {}", calculate_age(birthday));
}use chrono::{DateTime, Utc, Datelike, Timelike};
fn next_hourly() -> DateTime<Utc> {
let now = Utc::now();
now.with_minute(0).unwrap()
.with_second(0).unwrap()
.with_nanosecond(0).unwrap()
+ chrono::Duration::hours(1)
}
fn next_daily(hour: u32) -> DateTime<Utc> {
let now = Utc::now();
let next = now
.with_hour(hour).unwrap()
.with_minute(0).unwrap()
.with_second(0).unwrap()
.with_nanosecond(0).unwrap();
if next > now {
next
} else {
next + chrono::Duration::days(1)
}
}
fn main() {
println!("Next hourly: {}", next_hourly());
println!("Next daily at 9am: {}", next_daily(9));
}use chrono::{Duration, NaiveDate};
fn main() {
let date = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
// Checked arithmetic
match date.checked_add_signed(Duration::days(365)) {
Some(new_date) => println!("One year later: {}", new_date),
None => println!("Overflow occurred"),
}
// Also checked_sub_signed, checked_add_days, etc.
let earlier = date.checked_sub_days(chrono::Days::new(1));
println!("Previous day: {:?}", earlier);
}Chrono Key Imports:
use chrono::{DateTime, Utc, Local, NaiveDate, NaiveTime, NaiveDateTime, Duration, TimeZone};Core Types:
| Type | Description |
|------|-------------|
| DateTime<Tz> | Date and time with timezone |
| NaiveDateTime | Date and time without timezone |
| NaiveDate | Date without timezone |
| NaiveTime | Time without timezone |
| Duration | Span of time |
Time Zones:
| Type | Description |
|------|-------------|
| Utc | UTC timezone |
| Local | System local timezone |
| FixedOffset | Fixed UTC offset |
Format Specifiers:
| Specifier | Description |
|-----------|-------------|
| %Y | 4-digit year |
| %m | Month (01-12) |
| %d | Day (01-31) |
| %H | Hour (00-23) |
| %M | Minute (00-59) |
| %S | Second (00-59) |
| %A | Weekday name |
| %B | Month name |
| %I | Hour (01-12) |
| %p | AM/PM |
Common Operations:
// Current time
let now = Utc::now();
// Create date
let date = NaiveDate::from_ymd_opt(2024, 1, 15).unwrap();
// Add duration
let tomorrow = now + Duration::days(1);
// Format
let s = now.format("%Y-%m-%d %H:%M:%S").to_string();
// Parse
let dt = NaiveDateTime::parse_from_str("2024-01-15 14:30:00", "%Y-%m-%d %H:%M:%S").unwrap();Key Points:
Utc for storage, Local for displayNaive* types have no timezone infoDuration for time spanschecked_add_signed for safe arithmetic#[serde(with = "Serde")]from_ymd_opt returns Option for validationwith_timezone to convert between time zones