Travail avancé avec les dates et l'heure en Rust : de NaiveDateTime à Timezone
Le travail avec les dates et l'heure est l'une des tâches les plus courantes dans le développement backend, la journalisation, les systèmes financiers et le traitement de données. En Rust, la bibliothèque standard fournit le module de base std::time, mais pour les projets sérieux, cela ne suffit pas. Au niveau avancé, nous utilisons la crate chrono — la norme de facto pour travailler avec les dates et l'heure. Dans cet article, nous aborderons des scénarios complexes : travail avec les fuseaux horaires, parsing de formats non standard, manipulations de durées et optimisation des performances.
1. Installation et structure de base de chrono
Ajoutez la dépendance dans Cargo.toml :
[dependencies]chrono = { version = "0.4", features = ["serde"] }Les types principaux de chrono pour le travail avancé :
NaiveDateTime— date-heure sans fuseau horaire (locale).DateTime<Tz>— date-heure liée à un fuseau horaire (par exemple,Utc,Local,FixedOffset).Duration— intervalle de temps (diffère destd::time::Duration, prend en charge les valeurs négatives).TimeDelta— synonyme deDurationdans les nouvelles versions.
Exemple de création du moment actuel en UTC et en heure locale :
use chrono::{Utc, Local, DateTime};
fn main() { let utc_now: DateTime<Utc> = Utc::now(); let local_now: DateTime<Local> = Local::now(); println!("UTC: {}", utc_now); println!("Local: {}", local_now);}2. Travail avec les fuseaux horaires (Timezone)
L'une des fonctionnalités puissantes de chrono est le support de la base de données de fuseaux horaires Olson via la crate chrono-tz. Cela permet de travailler avec des noms de zones tels que "Europe/Moscow" ou "America/New_York".
Installez :
[dependencies]chrono = "0.4"chrono-tz = "0.8"Exemple de conversion d'heure entre zones :
use chrono::{Utc, DateTime, TimeZone};use chrono_tz::Europe::Moscow;
fn main() { let utc_time: DateTime<Utc> = Utc::now(); let moscow_time = utc_time.with_timezone(&Moscow); println!("UTC: {}", utc_time); println!("Moscow: {}", moscow_time);}Point important : stockez toujours l'heure en UTC dans la base de données et convertissez-la en heure locale uniquement lors de l'affichage à l'utilisateur. Cela évite toute confusion avec l'heure d'été/d'hiver.
2.1. Travail avec FixedOffset
Si vous connaissez un décalage fixe (par exemple, +03:00), utilisez FixedOffset :
use chrono::{FixedOffset, DateTime, Utc};
fn main() { let offset = FixedOffset::east_opt(3 * 3600).unwrap(); // +03:00 let now_utc: DateTime<Utc> = Utc::now(); let now_offset = now_utc.with_timezone(&offset); println!("Avec décalage +03:00: {}", now_offset);}3. Parsing et formatage des dates (techniques avancées)
Le parsing standard via parse_from_str nécessite un format précis. Mais dans les projets réels, les formats peuvent varier (par exemple, les logs de différents systèmes). Examinons plusieurs approches.
3.1. Formats multiples avec try_parse
Utilisez une itération sur les formats :
use chrono::NaiveDateTime;
fn parse_flexible(date_str: &str) -> Option<NaiveDateTime> { let formats = [ "%Y-%m-%d %H:%M:%S", "%d/%m/%Y %H:%M", "%Y%m%dT%H%M%S", "%b %d %Y %I:%M:%S%p", ];
for fmt in &formats { if let Ok(dt) = NaiveDateTime::parse_from_str(date_str, fmt) { return Some(dt); } } None}
fn main() { let dates = vec![ "2024-03-15 14:30:00", "15/03/2024 14:30", "2