العمل المتقدم مع التواريخ والوقت في Rust: من NaiveDateTime إلى Timezone
العمل مع التواريخ والوقت — من أكثر المهام شيوعًا في تطوير الواجهة الخلفية، وتسجيل الأحداث، والأنظمة المالية، ومعالجة البيانات. في Rust، توفر المكتبة القياسية الوحدة الأساسية std::time، ولكنها غير كافية للمشاريع الجادة. على المستوى المتقدم، نلجأ إلى الكريت chrono — المعيار الفعلي للعمل مع التواريخ والوقت. في هذه المقالة، سنستعرض السيناريوهات المعقدة: العمل مع المناطق الزمنية، وتحليل التنسيقات غير القياسية، والتعامل مع الفترات الزمنية، وتحسين الأداء.
1. التثبيت والهيكل الأساسي لـ chrono
أضف التبعية في Cargo.toml:
[dependencies]chrono = { version = "0.4", features = ["serde"] }الأنواع الأساسية في chrono للعمل المتقدم:
NaiveDateTime— تاريخ-وقت بدون منطقة زمنية (محلي).DateTime<Tz>— تاريخ-وقت مرتبط بمنطقة زمنية (مثلUtc،Local،FixedOffset).Duration— فترة زمنية (تختلف عنstd::time::Duration، وتدعم القيم السالبة).TimeDelta— مرادف لـDurationفي الإصدارات الجديدة.
مثال لإنشاء اللحظة الحالية في UTC والوقت المحلي:
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. العمل مع المناطق الزمنية (Timezone)
إحدى الإمكانيات القوية لـ chrono هي دعم قاعدة بيانات Olson للمناطق الزمنية من خلال الكريت chrono-tz. يتيح ذلك العمل مع أسماء المناطق مثل "Europe/Moscow" أو "America/New_York".
قم بالتثبيت:
[dependencies]chrono = "0.4"chrono-tz = "0.8"مثال لتحويل الوقت بين المناطق:
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);}نقطة مهمة: احفظ الوقت دائمًا بصيغة UTC في قاعدة البيانات، وقم بالتحويل إلى الوقت المحلي فقط عند العرض للمستخدم. هذا يمنع الارتباك مع التوقيت الصيفي/الشتوي.
2.1. العمل مع FixedOffset
إذا كنت تعرف الإزاحة الثابتة (مثل +03:00)، استخدم 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!("With offset +03:00: {}", now_offset);}3. تحليل وتنسيق التواريخ (تقنيات متقدمة)
التحليل القياسي عبر parse_from_str يتطلب تنسيقًا دقيقًا. لكن في المشاريع الحقيقية، قد تختلف التنسيقات (مثل سجلات من أنظمة مختلفة). لنستعرض عدة طرق.
3.1. تنسيقات متعددة مع try_parse
استخدم التكرار عبر التنسيقات:
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