Fechas y horas en Rust con chrono

Rust no trae fechas de calendario en su biblioteca estándar: std::time sirve para medir intervalos, no para saber en qué día caemos. Para trabajar con fechas se usa chrono, que es el crate habitual.

La dependencia

cargo add chrono
[dependencies]
chrono = "0.4.45"

Analizar, formatear y calcular

use chrono::{Duration, NaiveDate, Utc};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let lanzamiento = NaiveDate::parse_from_str("2015-05-15", "%Y-%m-%d")?;
    println!("Rust 1.0        : {}", lanzamiento.format("%d de %B de %Y"));
    println!("formato corto   : {}", lanzamiento.format("%d/%m/%Y"));

    let siguiente = lanzamiento + Duration::days(42);
    println!("42 días después : {siguiente}");

    let otra = NaiveDate::from_ymd_opt(2021, 2, 11).unwrap();
    println!("días entre ambas: {}", (otra - lanzamiento).num_days());

    println!("ahora (UTC)     : {}", Utc::now().format("%Y-%m-%d %H:%M"));
    Ok(())
}
salidaRust 1.0        : 15 de May de 2015
formato corto   : 15/05/2015
42 días después : 2015-06-26
días entre ambas: 2099
ahora (UTC)     : 2026-10-02 19:27
Mira la primera línea: dice «May», no «mayo». El formato %B escribe el nombre del mes, pero chrono no está localizado y lo da en inglés aunque el resto del texto esté en español. No es un fallo del ejemplo, es el comportamiento por defecto. Para nombres en español hay que activar la característica unstable-locales y usar format_localized, o escribir una tabla propia de doce meses, que para un caso sencillo suele salir más a cuenta.

La última línea cambia en cada ejecución, por razones evidentes; las otras cuatro no. Y la resta de dos fechas devuelve una Duration, de la que se piden los días con num_days(), las horas con num_hours() y así.

Por qué from_ymd_opt y no from_ymd. Acaba en _opt y devuelve un Option porque no toda combinación de números es una fecha: el 31 de febrero no existe. chrono te obliga a reconocer esa posibilidad en vez de dejar que el programa reviente al construirla. Es el Option de la lección de manejo de errores, aplicado a algo cotidiano.

Qué tipo usar

Para qué Tipo
Solo una fecha, sin hora NaiveDate
Fecha y hora, sin zona horaria NaiveDateTime
Instante universal DateTime<Utc>
Hora local de la máquina DateTime<Local>
Un intervalo Duration
Medir cuánto tarda un trozo de código std::time::Instant, sin chrono

La regla práctica: guarda y calcula siempre en Utc, y convierte a hora local solo al mostrar. Mezclar zonas horarias dentro de la lógica es una fuente inagotable de errores de una hora.

El código de esta página se compiló y ejecutó con rustc 1.96.1 y chrono 0.4.45 antes de publicarla; las salidas están copiadas de la ejecución real, incluido el «May» en inglés. Documentación oficial: chrono en docs.rs.