haystack_core/kinds/
tz.rs1use std::collections::HashMap;
2use std::sync::LazyLock;
3
4static TZ_MAP: LazyLock<HashMap<String, String>> = LazyLock::new(build_tz_map);
5
6fn build_tz_map() -> HashMap<String, String> {
7 let mut map = HashMap::new();
8
9 let data = include_str!("../../data/tz_map.txt");
11 for line in data.lines() {
12 let line = line.trim();
13 if line.is_empty() || line.starts_with('#') {
14 continue;
15 }
16 if let Some((city, iana)) = line.split_once('=') {
17 map.insert(city.trim().to_string(), iana.trim().to_string());
18 }
19 }
20
21 map.insert("UTC".to_string(), "UTC".to_string());
23 map.insert("GMT".to_string(), "Etc/GMT".to_string());
24 map.insert("Rel".to_string(), "UTC".to_string());
25
26 map
27}
28
29pub fn tz_for(name: &str) -> Option<&'static str> {
34 if let Some(iana) = TZ_MAP.get(name) {
36 return Some(iana.as_str());
37 }
38 if name.contains('/') {
40 for v in TZ_MAP.values() {
41 if v == name {
42 return Some(v.as_str());
43 }
44 }
45 }
46 None
47}
48
49pub fn tz_map() -> &'static HashMap<String, String> {
51 &TZ_MAP
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn tz_map_loaded() {
60 let map = tz_map();
61 assert!(
62 map.len() > 100,
63 "expected 100+ timezone mappings, got {}",
64 map.len()
65 );
66 }
67
68 #[test]
69 fn tz_utc() {
70 assert_eq!(tz_for("UTC"), Some("UTC"));
71 }
72
73 #[test]
74 fn tz_gmt() {
75 assert_eq!(tz_for("GMT"), Some("Etc/GMT"));
76 }
77
78 #[test]
79 fn tz_rel() {
80 assert_eq!(tz_for("Rel"), Some("UTC"));
81 }
82
83 #[test]
84 fn tz_new_york() {
85 let result = tz_for("New_York");
86 assert!(result.is_some(), "New_York should resolve");
87 assert_eq!(result.unwrap(), "America/New_York");
88 }
89
90 #[test]
91 fn tz_london() {
92 let result = tz_for("London");
93 assert!(result.is_some(), "London should resolve");
94 assert_eq!(result.unwrap(), "Europe/London");
95 }
96
97 #[test]
98 fn tz_unknown() {
99 assert_eq!(tz_for("Nonexistent_City"), None);
100 }
101
102 #[test]
103 fn tz_full_iana_path() {
104 let result = tz_for("America/New_York");
105 assert!(result.is_some(), "Full IANA path should resolve");
106 }
107}