Skip to main content

haystack_core/kinds/
datetime.rs

1use chrono::{DateTime, FixedOffset};
2use std::fmt;
3use std::hash::{Hash, Hasher};
4
5/// Timezone-aware datetime with Haystack city-based timezone name.
6///
7/// Stores chrono DateTime<FixedOffset> plus the Haystack tz name
8/// (e.g., "New_York", "London", "UTC").
9///
10/// Zinc: `2024-01-01T08:12:05-05:00 New_York`
11#[derive(Debug, Clone)]
12pub struct HDateTime {
13    pub dt: DateTime<FixedOffset>,
14    pub tz_name: String,
15}
16
17impl HDateTime {
18    pub fn new(dt: DateTime<FixedOffset>, tz_name: impl Into<String>) -> Self {
19        Self {
20            dt,
21            tz_name: tz_name.into(),
22        }
23    }
24}
25
26impl PartialEq for HDateTime {
27    fn eq(&self, other: &Self) -> bool {
28        self.dt == other.dt && self.tz_name == other.tz_name
29    }
30}
31
32impl Eq for HDateTime {}
33
34impl PartialOrd for HDateTime {
35    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
36        self.dt.partial_cmp(&other.dt)
37    }
38}
39
40impl Hash for HDateTime {
41    fn hash<H: Hasher>(&self, state: &mut H) {
42        self.dt.hash(state);
43        self.tz_name.hash(state);
44    }
45}
46
47impl fmt::Display for HDateTime {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        // Format: 2024-01-01T08:12:05-05:00 New_York
50        write!(
51            f,
52            "{} {}",
53            self.dt.format("%Y-%m-%dT%H:%M:%S%:z"),
54            self.tz_name
55        )
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use chrono::TimeZone;
63
64    #[test]
65    fn hdatetime_display() {
66        let offset = FixedOffset::west_opt(5 * 3600).unwrap();
67        let dt = offset.with_ymd_and_hms(2024, 1, 1, 8, 12, 5).unwrap();
68        let hdt = HDateTime::new(dt, "New_York");
69        let s = hdt.to_string();
70        assert!(s.contains("2024-01-01T08:12:05"));
71        assert!(s.contains("New_York"));
72    }
73
74    #[test]
75    fn hdatetime_equality() {
76        let offset = FixedOffset::west_opt(5 * 3600).unwrap();
77        let dt = offset.with_ymd_and_hms(2024, 1, 1, 8, 0, 0).unwrap();
78        let a = HDateTime::new(dt, "New_York");
79        let b = HDateTime::new(dt, "New_York");
80        assert_eq!(a, b);
81    }
82
83    #[test]
84    fn hdatetime_different_tz_name() {
85        let offset = FixedOffset::west_opt(5 * 3600).unwrap();
86        let dt = offset.with_ymd_and_hms(2024, 1, 1, 8, 0, 0).unwrap();
87        let a = HDateTime::new(dt, "New_York");
88        let b = HDateTime::new(dt, "Chicago");
89        assert_ne!(a, b);
90    }
91
92    #[test]
93    fn hdatetime_utc() {
94        let offset = FixedOffset::east_opt(0).unwrap();
95        let dt = offset.with_ymd_and_hms(2024, 6, 15, 12, 0, 0).unwrap();
96        let hdt = HDateTime::new(dt, "UTC");
97        let s = hdt.to_string();
98        assert!(s.contains("+00:00"));
99        assert!(s.contains("UTC"));
100    }
101}