Skip to main content

whichtime_sys/dictionaries/
zh.rs

1//! Chinese (中文) locale dictionaries
2//! Supports both Simplified (Hans) and Traditional (Hant) Chinese
3
4use super::{CasualDateType, CasualTimeType, RelativeModifier, TimeUnit, Weekday};
5use phf::phf_map;
6
7/// Weekday dictionary (both simplified and traditional)
8pub static WEEKDAY_MAP: phf::Map<&'static str, Weekday> = phf_map! {
9    // Simplified
10    "星期日" => Weekday::Sunday,
11    "星期天" => Weekday::Sunday,
12    "周日" => Weekday::Sunday,
13    "週日" => Weekday::Sunday,
14    "礼拜日" => Weekday::Sunday,
15    "禮拜日" => Weekday::Sunday,
16    "礼拜天" => Weekday::Sunday,
17    "禮拜天" => Weekday::Sunday,
18    "星期一" => Weekday::Monday,
19    "周一" => Weekday::Monday,
20    "週一" => Weekday::Monday,
21    "礼拜一" => Weekday::Monday,
22    "禮拜一" => Weekday::Monday,
23    "星期二" => Weekday::Tuesday,
24    "周二" => Weekday::Tuesday,
25    "週二" => Weekday::Tuesday,
26    "礼拜二" => Weekday::Tuesday,
27    "禮拜二" => Weekday::Tuesday,
28    "星期三" => Weekday::Wednesday,
29    "周三" => Weekday::Wednesday,
30    "週三" => Weekday::Wednesday,
31    "礼拜三" => Weekday::Wednesday,
32    "禮拜三" => Weekday::Wednesday,
33    "星期四" => Weekday::Thursday,
34    "周四" => Weekday::Thursday,
35    "週四" => Weekday::Thursday,
36    "礼拜四" => Weekday::Thursday,
37    "禮拜四" => Weekday::Thursday,
38    "星期五" => Weekday::Friday,
39    "周五" => Weekday::Friday,
40    "週五" => Weekday::Friday,
41    "礼拜五" => Weekday::Friday,
42    "禮拜五" => Weekday::Friday,
43    "星期六" => Weekday::Saturday,
44    "周六" => Weekday::Saturday,
45    "週六" => Weekday::Saturday,
46    "礼拜六" => Weekday::Saturday,
47    "禮拜六" => Weekday::Saturday,
48};
49
50/// Month dictionary
51pub static MONTH_MAP: phf::Map<&'static str, u32> = phf_map! {
52    "一月" => 1,
53    "1月" => 1,
54    "二月" => 2,
55    "2月" => 2,
56    "三月" => 3,
57    "3月" => 3,
58    "四月" => 4,
59    "4月" => 4,
60    "五月" => 5,
61    "5月" => 5,
62    "六月" => 6,
63    "6月" => 6,
64    "七月" => 7,
65    "7月" => 7,
66    "八月" => 8,
67    "8月" => 8,
68    "九月" => 9,
69    "9月" => 9,
70    "十月" => 10,
71    "10月" => 10,
72    "十一月" => 11,
73    "11月" => 11,
74    "十二月" => 12,
75    "12月" => 12,
76};
77
78/// Chinese number characters
79pub static NUMBER_MAP: phf::Map<&'static str, u32> = phf_map! {
80    "零" => 0,
81    "〇" => 0,
82    "一" => 1,
83    "二" => 2,
84    "两" => 2,
85    "兩" => 2,
86    "三" => 3,
87    "四" => 4,
88    "五" => 5,
89    "六" => 6,
90    "七" => 7,
91    "八" => 8,
92    "九" => 9,
93    "十" => 10,
94    "百" => 100,
95    "千" => 1000,
96};
97
98/// Time unit dictionary
99pub static TIME_UNIT_MAP: phf::Map<&'static str, TimeUnit> = phf_map! {
100    "秒" => TimeUnit::Second,
101    "秒钟" => TimeUnit::Second,
102    "秒鐘" => TimeUnit::Second,
103    "分" => TimeUnit::Minute,
104    "分钟" => TimeUnit::Minute,
105    "分鐘" => TimeUnit::Minute,
106    "小时" => TimeUnit::Hour,
107    "小時" => TimeUnit::Hour,
108    "钟头" => TimeUnit::Hour,
109    "鐘頭" => TimeUnit::Hour,
110    "点" => TimeUnit::Hour,
111    "點" => TimeUnit::Hour,
112    "天" => TimeUnit::Day,
113    "日" => TimeUnit::Day,
114    "号" => TimeUnit::Day,
115    "號" => TimeUnit::Day,
116    "周" => TimeUnit::Week,
117    "週" => TimeUnit::Week,
118    "星期" => TimeUnit::Week,
119    "礼拜" => TimeUnit::Week,
120    "禮拜" => TimeUnit::Week,
121    "月" => TimeUnit::Month,
122    "个月" => TimeUnit::Month,
123    "個月" => TimeUnit::Month,
124    "季度" => TimeUnit::Quarter,
125    "季" => TimeUnit::Quarter,
126    "年" => TimeUnit::Year,
127};
128
129/// Casual date keywords
130pub static CASUAL_DATE_MAP: phf::Map<&'static str, CasualDateType> = phf_map! {
131    // Simplified Chinese
132    "现在" => CasualDateType::Now,
133    "今天" => CasualDateType::Today,
134    "今晚" => CasualDateType::Tonight,
135    "明天" => CasualDateType::Tomorrow,
136    "昨天" => CasualDateType::Yesterday,
137    "后天" => CasualDateType::Overmorrow,
138    "前天" => CasualDateType::DayBeforeYesterday,
139    // Traditional Chinese
140    "現在" => CasualDateType::Now,
141    "今日" => CasualDateType::Today,
142    "今夜" => CasualDateType::Tonight,
143    "明日" => CasualDateType::Tomorrow,
144    "昨日" => CasualDateType::Yesterday,
145    "後天" => CasualDateType::Overmorrow,
146    // Cantonese
147    "而家" => CasualDateType::Now,
148    "聽日" => CasualDateType::Tomorrow,
149    "尋日" => CasualDateType::Yesterday,
150    "琴日" => CasualDateType::Yesterday,
151};
152
153/// Casual time keywords
154pub static CASUAL_TIME_MAP: phf::Map<&'static str, CasualTimeType> = phf_map! {
155    "中午" => CasualTimeType::Noon,
156    "正午" => CasualTimeType::Noon,
157    "午" => CasualTimeType::Noon,
158    "半夜" => CasualTimeType::Midnight,
159    "午夜" => CasualTimeType::Midnight,
160    "凌晨" => CasualTimeType::Midnight,
161    "早上" => CasualTimeType::Morning,
162    "早晨" => CasualTimeType::Morning,
163    "上午" => CasualTimeType::Morning,
164    "下午" => CasualTimeType::Afternoon,
165    "傍晚" => CasualTimeType::Evening,
166    "晚上" => CasualTimeType::Evening,
167    "晚间" => CasualTimeType::Evening,
168    "晚間" => CasualTimeType::Evening,
169    "夜里" => CasualTimeType::Night,
170    "夜裡" => CasualTimeType::Night,
171    "夜晚" => CasualTimeType::Night,
172};
173
174/// Relative modifiers
175pub static RELATIVE_MODIFIER_MAP: phf::Map<&'static str, RelativeModifier> = phf_map! {
176    "这" => RelativeModifier::This,
177    "這" => RelativeModifier::This,
178    "这个" => RelativeModifier::This,
179    "這個" => RelativeModifier::This,
180    "本" => RelativeModifier::This,
181    "今" => RelativeModifier::This,
182    "下" => RelativeModifier::Next,
183    "下个" => RelativeModifier::Next,
184    "下個" => RelativeModifier::Next,
185    "明" => RelativeModifier::Next,
186    "上" => RelativeModifier::Last,
187    "上个" => RelativeModifier::Last,
188    "上個" => RelativeModifier::Last,
189    "去" => RelativeModifier::Last,
190    "前" => RelativeModifier::Last,
191};
192
193// ============================================================================
194// Lookup functions
195// ============================================================================
196
197#[inline]
198pub fn get_weekday(s: &str) -> Option<Weekday> {
199    WEEKDAY_MAP.get(s).copied()
200}
201
202#[inline]
203pub fn get_month(s: &str) -> Option<u32> {
204    MONTH_MAP.get(s).copied()
205}
206
207#[inline]
208pub fn get_number(s: &str) -> Option<u32> {
209    NUMBER_MAP.get(s).copied()
210}
211
212#[inline]
213pub fn get_time_unit(s: &str) -> Option<TimeUnit> {
214    TIME_UNIT_MAP.get(s).copied()
215}
216
217#[inline]
218pub fn get_casual_date(s: &str) -> Option<CasualDateType> {
219    CASUAL_DATE_MAP.get(s).copied()
220}
221
222#[inline]
223pub fn get_casual_time(s: &str) -> Option<CasualTimeType> {
224    CASUAL_TIME_MAP.get(s).copied()
225}
226
227#[inline]
228pub fn get_relative_modifier(s: &str) -> Option<RelativeModifier> {
229    RELATIVE_MODIFIER_MAP.get(s).copied()
230}
231
232/// Convert Chinese string to number
233/// Handles Chinese number characters like 一, 二, 三, 十, 百, etc.
234pub fn zh_string_to_number(text: &str) -> u32 {
235    let mut result = 0u32;
236    let mut current = 0u32;
237
238    for char in text.chars() {
239        let char_str = char.to_string();
240        if let Some(val) = get_number(&char_str) {
241            match val {
242                10 => {
243                    // 十 (ten)
244                    if current == 0 {
245                        current = 10;
246                    } else {
247                        current *= 10;
248                    }
249                }
250                100 => {
251                    // 百 (hundred)
252                    if current == 0 {
253                        current = 100;
254                    } else {
255                        result += current * 100;
256                        current = 0;
257                    }
258                }
259                1000 => {
260                    // 千 (thousand)
261                    if current == 0 {
262                        current = 1000;
263                    } else {
264                        result += current * 1000;
265                        current = 0;
266                    }
267                }
268                _ => {
269                    // Single digit
270                    if current >= 10 {
271                        current += val;
272                    } else {
273                        current = val;
274                    }
275                }
276            }
277        }
278    }
279
280    result + current
281}
282
283/// Parse full-width numbers to half-width
284pub fn fullwidth_to_halfwidth(text: &str) -> String {
285    text.chars()
286        .map(|c| {
287            match c {
288                // Full-width digits (0-9) to half-width (0-9)
289                '\u{FF10}'..='\u{FF19}' => char::from_u32(c as u32 - 0xFEE0).unwrap_or(c),
290                // Full-width space to half-width
291                '\u{3000}' => ' ',
292                _ => c,
293            }
294        })
295        .collect()
296}
297
298/// Parse a number pattern (handles Chinese numbers, digits)
299pub fn parse_number_pattern(text: &str) -> f64 {
300    // Convert full-width digits first
301    let normalized = fullwidth_to_halfwidth(text);
302
303    // Try parsing as regular digit
304    if let Ok(n) = normalized.parse::<f64>() {
305        return n;
306    }
307
308    // Try Chinese number conversion
309    let zh_num = zh_string_to_number(text);
310    if zh_num > 0 {
311        return zh_num as f64;
312    }
313
314    // Try single character
315    if let Some(n) = get_number(text) {
316        return n as f64;
317    }
318
319    0.0
320}