Rust’s standard library does not include a built-in DateTime type. Instead, external crates provide date and time support. The two primary choices are chrono and time, each with different strengths and trade-offs.
Chrono: The De Facto Standard
chrono is the most widely used crate for date and time handling. It provides comprehensive support for time zones, serialization, and formatting.
Creating a Date and Time
use chrono::{NaiveDate, NaiveDateTime, NaiveTime, Utc};
let date = NaiveDate::from_ymd_opt(2024, 2, 8).unwrap();
let time = NaiveTime::from_hms_opt(14, 30, 45).unwrap();
let datetime = NaiveDateTime::new(date, time);
println!("Date: {}", date);
println!("Time: {}", time);
println!("Datetime: {}", datetime);Getting the Current Time
use chrono::Utc;
let now = Utc::now();
println!("Current UTC time: {}", now);Adding and Subtracting Time Intervals
use chrono::{Duration, Utc};
let now = Utc::now();
let later = now + Duration::days(3);
let earlier = now - Duration::hours(5);
println!("Now: {}", now);
println!("Three days later: {}", later);
println!("Five hours earlier: {}", earlier);Serializing and Deserializing with serde
chrono integrates seamlessly with serde, allowing easy serialization and deserialization for JSON-based APIs:
use chrono::{Utc, DateTime};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Event {
name: String,
timestamp: DateTime<Utc>,
}
let event = Event {
name: "Conference".to_string(),
timestamp: Utc::now(),
};
let json = serde_json::to_string(&event).unwrap();
println!("Serialized: {}", json);The Time Crate: A Lightweight Alternative
The time crate provides a smaller and faster alternative to chrono, but lacks time zone support. It is designed for performance-sensitive applications and environments where dependencies should be minimal.
Creating and Manipulating Dates with time
use time::{Date, Time, PrimitiveDateTime, Duration};
let date = Date::from_calendar_date(2024, time::Month::February, 8).unwrap();
let time = Time::from_hms(14, 30, 45).unwrap();
let datetime = PrimitiveDateTime::new(date, time);
println!("Date: {}", date);
println!("Time: {}", time);
println!("Datetime: {}", datetime);Adding and Subtracting Intervals
use time::{Duration, OffsetDateTime};
let now = OffsetDateTime::now_utc();
let later = now + Duration::days(3);
let earlier = now - Duration::hours(5);
println!("Now: {}", now);
println!("Three days later: {}", later);
println!("Five hours earlier: {}", earlier);Serializing with serde
Unlike chrono, time does not include built-in serde support. To serialize time structures, custom implementations are required:
use serde::{Serialize, Serializer};
use time::OffsetDateTime;
fn serialize_datetime<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&datetime.to_string())
}
#[derive(Serialize)]
struct Event {
name: String,
#[serde(serialize_with = "serialize_datetime")]
timestamp: OffsetDateTime,
}
let event = Event {
name: "Conference".to_string(),
timestamp: OffsetDateTime::now_utc(),
};
let json = serde_json::to_string(&event).unwrap();
println!("Serialized: {}", json);Choosing Between Chrono and Time
The choice between chrono and time depends on whether time zone support is required and the need for minimal dependencies.
- Use
chronoif working with time zones, JSON serialization, or external APIs. - Use
timefor a lightweight and faster alternative when time zones are not needed.
For most applications, chrono is the preferred choice due to its ecosystem support and ease of integration with databases and serialization frameworks.