1use crate::date::Date;
7use crate::datetime::DateTime;
8use crate::error::{RstimeError, RstimeResult};
9use crate::time::Time;
10
11pub fn parse_datetime(s: &str, fmt: &str) -> RstimeResult<DateTime> {
36 let tokens = tokenize_format(fmt);
37 let mut year = 0i32;
38 let mut month = 1u8;
39 let mut day = 1u8;
40 let mut hour = 0u8;
41 let mut minute = 0u8;
42 let mut second = 0u8;
43 let mut millisecond = 0u16;
44 let mut pos = 0usize;
45 let chars: Vec<char> = s.chars().collect();
46
47 for token in &tokens {
48 match token {
49 Token::Literal(lit) => {
50 let lit_chars: Vec<char> = lit.chars().collect();
51 if pos + lit_chars.len() > chars.len() {
52 return Err(RstimeError::new(format!(
53 "期望文本 '{}' 但输入已结束",
54 lit
55 )));
56 }
57 let actual: String = chars[pos..pos + lit_chars.len()].iter().collect();
58 if actual != *lit {
59 return Err(RstimeError::new(format!(
60 "位置 {} 期望 '{}',实际得到 '{}'",
61 pos, lit, actual
62 )));
63 }
64 pos += lit_chars.len();
65 }
66 Token::Specifier(spec) => {
67 let value = read_number(&chars, &mut pos, spec.len);
68 match spec.kind {
69 SpecKind::Year4 => year = value as i32,
70 SpecKind::Year2 => year = 2000 + value as i32,
71 SpecKind::Month => month = value as u8,
72 SpecKind::Day => day = value as u8,
73 SpecKind::Hour24 => hour = value as u8,
74 SpecKind::Hour12 => hour = value as u8,
75 SpecKind::Minute => minute = value as u8,
76 SpecKind::Second => second = value as u8,
77 SpecKind::Millisecond => millisecond = value as u16,
78 }
79 }
80 }
81 }
82
83 let date = Date::new(year, month, day);
84 let time = Time::new(hour, minute, second, millisecond);
85 Ok(DateTime::new(date, time))
86}
87
88pub fn parse_date(s: &str, fmt: &str) -> RstimeResult<Date> {
101 let dt = parse_datetime(s, fmt)?;
102 Ok(dt.date)
103}
104
105pub fn parse_time(s: &str, fmt: &str) -> RstimeResult<Time> {
118 let dt = parse_datetime(&format!("2000-01-01 {}", s), &format!("{{YYYY}}-{{MM}}-{{DD}} {}", fmt))?;
119 Ok(dt.time)
120}
121
122pub fn parse_iso8601(s: &str) -> RstimeResult<DateTime> {
143 let s = s.trim();
144
145 if s.len() >= 23
146 && s.as_bytes()[4] == b'-'
147 && s.as_bytes()[7] == b'-'
148 && (s.as_bytes()[10] == b'T' || s.as_bytes()[10] == b' ')
149 && s.as_bytes()[13] == b':'
150 && s.as_bytes()[16] == b':'
151 && s.as_bytes()[19] == b'.'
152 {
153 return parse_datetime(s, "{YYYY}-{MM}-{DD}T{HH}:{mm}:{ss}.{SSS}");
154 }
155
156 if s.len() >= 19
157 && s.as_bytes()[4] == b'-'
158 && s.as_bytes()[7] == b'-'
159 && (s.as_bytes()[10] == b'T' || s.as_bytes()[10] == b' ')
160 {
161 return parse_datetime(s, "{YYYY}-{MM}-{DD}T{HH}:{mm}:{ss}");
162 }
163
164 if s.len() >= 10 && s.as_bytes()[4] == b'-' && s.as_bytes()[7] == b'-' {
165 let dt = parse_datetime(s, "{YYYY}-{MM}-{DD}")?;
166 return Ok(DateTime::new(dt.date, Time::MIDNIGHT));
167 }
168
169 Err(RstimeError::new(format!("无法识别的 ISO 8601 格式: '{}'", s)))
170}
171
172enum SpecKind {
173 Year4,
174 Year2,
175 Month,
176 Day,
177 Hour24,
178 Hour12,
179 Minute,
180 Second,
181 Millisecond,
182}
183
184struct FormatSpec {
185 kind: SpecKind,
186 len: usize,
187}
188
189enum Token {
190 Literal(String),
191 Specifier(FormatSpec),
192}
193
194fn tokenize_format(fmt: &str) -> Vec<Token> {
195 let mut tokens = Vec::new();
196 let chars: Vec<char> = fmt.chars().collect();
197 let mut i = 0;
198
199 while i < chars.len() {
200 if chars[i] == '{' {
201 let mut end = i + 1;
202 while end < chars.len() && chars[end] != '}' {
203 end += 1;
204 }
205 if end < chars.len() && end > i + 1 {
206 let token: String = chars[i + 1..end].iter().collect();
207 if let Some(spec) = classify_token(&token) {
208 tokens.push(Token::Specifier(spec));
209 i = end + 1;
210 continue;
211 }
212 }
213 }
214 let start = i;
215 while i < chars.len() && (chars[i] != '{' || i == start) {
216 if chars[i] == '{' {
217 let mut j = i + 1;
218 while j < chars.len() && chars[j] != '}' {
219 j += 1;
220 }
221 if j < chars.len() {
222 let t: String = chars[i + 1..j].iter().collect();
223 if classify_token(&t).is_some() {
224 break;
225 }
226 }
227 }
228 i += 1;
229 }
230 if i > start {
231 tokens.push(Token::Literal(chars[start..i].iter().collect()));
232 }
233 }
234
235 tokens
236}
237
238fn classify_token(token: &str) -> Option<FormatSpec> {
239 match token {
240 "YYYY" => Some(FormatSpec {
241 kind: SpecKind::Year4,
242 len: 4,
243 }),
244 "YY" => Some(FormatSpec {
245 kind: SpecKind::Year2,
246 len: 2,
247 }),
248 "MM" => Some(FormatSpec {
249 kind: SpecKind::Month,
250 len: 2,
251 }),
252 "M" => Some(FormatSpec {
253 kind: SpecKind::Month,
254 len: 1,
255 }),
256 "DD" => Some(FormatSpec {
257 kind: SpecKind::Day,
258 len: 2,
259 }),
260 "D" => Some(FormatSpec {
261 kind: SpecKind::Day,
262 len: 1,
263 }),
264 "HH" => Some(FormatSpec {
265 kind: SpecKind::Hour24,
266 len: 2,
267 }),
268 "H" => Some(FormatSpec {
269 kind: SpecKind::Hour24,
270 len: 1,
271 }),
272 "hh" => Some(FormatSpec {
273 kind: SpecKind::Hour12,
274 len: 2,
275 }),
276 "h" => Some(FormatSpec {
277 kind: SpecKind::Hour12,
278 len: 1,
279 }),
280 "mm" => Some(FormatSpec {
281 kind: SpecKind::Minute,
282 len: 2,
283 }),
284 "m" => Some(FormatSpec {
285 kind: SpecKind::Minute,
286 len: 1,
287 }),
288 "ss" => Some(FormatSpec {
289 kind: SpecKind::Second,
290 len: 2,
291 }),
292 "s" => Some(FormatSpec {
293 kind: SpecKind::Second,
294 len: 1,
295 }),
296 "SSS" => Some(FormatSpec {
297 kind: SpecKind::Millisecond,
298 len: 3,
299 }),
300 _ => None,
301 }
302}
303
304fn read_number(chars: &[char], pos: &mut usize, len: usize) -> u32 {
305 let end = (*pos + len).min(chars.len());
306 let num_str: String = chars[*pos..end].iter().collect();
307 *pos = end;
308 num_str.parse::<u32>().unwrap_or(0)
309}