Trabalho Avançado com Datas e Horas em Rust
\n\nNo desenvolvimento moderno em Rust, o trabalho com datas e horas vai muito além da simples obtenção do momento atual. Ao criar sistemas de alta carga, aplicações financeiras ou serviços distribuídos, é necessário um controle preciso de fusos horários, parsing eficiente, serialização e cálculos temporais complexos. Neste artigo, exploraremos técnicas avançadas de trabalho com datas e horas, utilizando as crates chrono e time.
1. Biblioteca chrono: a base do trabalho avançado
\n\nA crate chrono é o padrão de facto para trabalhar com datas e horas em Rust. Ela fornece duas abstrações principais: NaiveDateTime (data-hora sem fuso horário) e DateTime<Tz> (data-hora vinculada a um fuso horário).
Exemplo: trabalhando com fusos horários
\n\nuse chrono::{DateTime, Utc, Local, FixedOffset, NaiveDateTime};\nuse chrono::format::ParseError;\n\nfn main() -> Result<(), ParseError> {\n // Hora atual em UTC\n let utc_now: DateTime<Utc> = Utc::now();\n println!("UTC agora: {}", utc_now);\n\n // Hora local atual\n let local_now: DateTime<Local> = Local::now();\n println!("Local agora: {}", local_now);\n\n // Conversão para outro fuso horário (Moscou, UTC+3)\n let moscow_offset = FixedOffset::east_opt(3 * 3600).unwrap();\n let moscow_time = utc_now.with_timezone(&moscow_offset);\n println!("Horário de Moscou: {}", moscow_time);\n\n // Parsing de string com fuso horário\n let parsed = DateTime::parse_from_rfc3339("2024-03-15T14:30:00+05:00")?;\n println!("Parseado com offset: {}", parsed);\n\n Ok(())\n}\n\nImportante: Use Utc para armazenamento em bancos de dados e APIs, e realize a conversão para fusos locais apenas no nível de apresentação.
2. Cálculos temporais complexos e intervalos
\n\nA biblioteca chrono suporta aritmética de datas com o tipo Duration e operações mais complexas através da trait TimeDelta. Para trabalhar com intervalos e períodos (por exemplo, "próximo mês"), use Months e Weeks.
Exemplo: cálculos com datas
\n\nuse chrono::{NaiveDate, Duration, Months, Datelike, Weekday};\n\nfn main() {\n let start = NaiveDate::from_ymd_opt(2024, 1, 15).unwrap();\n\n // Adição de dias\n let plus_10_days = start + Duration::days(10);\n println!("+10 dias: {}", plus_10_days);\n\n // Adição de meses (considera diferentes durações de meses)\n let plus_2_months = start.checked_add_months(Months::new(2)).unwrap();\n println!("+2 meses: {}", plus_2_months);\n\n // Encontrar a próxima segunda-feira\n let next_monday = start.iter_days()\n .skip(1)\n .find(|d| d.weekday() == Weekday::Mon)\n .unwrap();\n println!("Próxima segunda: {}", next_monday);\n\n // Diferença entre datas em dias\n let end = NaiveDate::from_ymd_opt(2024, 12, 31).unwrap();\n let days_diff = end.signed_duration_since(start).num_days();\n println!("Dias entre: {}", days_diff);\n}\n\nDica: Para cálculos financeiros, use checked_add_months em vez de simples adição de dias, para lidar corretamente com finais de mês (por exemplo, 31 de janeiro + 1 mês = 28/29 de fevereiro).
3. Serialização e parsing de datas com serde
\n\nAo trabalhar com JSON, YAML ou bancos de dados, a serialização correta de datas é crucial. A crate chrono integra-se com serde através da feature serde. Para formatos personalizados, use os atributos #[serde(with = "...")].
Exemplo: serialização em ISO 8601 e formatos personalizados
\n\nuse chrono::{DateTime, Utc, NaiveDateTime};\nuse serde::{Serialize, Deserialize};\n\n#[derive(Debug, Serialize, Deserialize)]