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 chrono if working with time zones, JSON serialization, or external APIs.
  • Use time for 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.