| 303 | } |
| 304 | |
| 305 | fn string_to_time(s: &str) -> Option<NaiveTime> { |
| 306 | let bytes = s.as_bytes(); |
| 307 | if bytes.len() < 4 { |
| 308 | return None; |
| 309 | } |
| 310 | |
| 311 | let (am, bytes) = match bytes.get(bytes.len() - 3..) { |
| 312 | Some(b" AM" | b" am" | b" Am" | b" aM") => (Some(true), &bytes[..bytes.len() - 3]), |
| 313 | Some(b" PM" | b" pm" | b" pM" | b" Pm") => (Some(false), &bytes[..bytes.len() - 3]), |
| 314 | _ => (None, bytes), |
| 315 | }; |
| 316 | |
| 317 | if bytes.len() < 4 { |
| 318 | return None; |
| 319 | } |
| 320 | |
| 321 | let mut digits = [b'0'; 6]; |
| 322 | |
| 323 | // Extract hour |
| 324 | let bytes = match (bytes[1], bytes[2]) { |
| 325 | (b':', _) => { |
| 326 | digits[1] = bytes[0]; |
| 327 | &bytes[2..] |
| 328 | } |
| 329 | (_, b':') => { |
| 330 | digits[0] = bytes[0]; |
| 331 | digits[1] = bytes[1]; |
| 332 | &bytes[3..] |
| 333 | } |
| 334 | _ => return None, |
| 335 | }; |
| 336 | |
| 337 | if bytes.len() < 2 { |
| 338 | return None; // Minutes required |
| 339 | } |
| 340 | |
| 341 | // Extract minutes |
| 342 | digits[2] = bytes[0]; |
| 343 | digits[3] = bytes[1]; |
| 344 | |
| 345 | let nanoseconds = match bytes.get(2) { |
| 346 | Some(b':') => { |
| 347 | if bytes.len() < 5 { |
| 348 | return None; |
| 349 | } |
| 350 | |
| 351 | // Extract seconds |
| 352 | digits[4] = bytes[3]; |
| 353 | digits[5] = bytes[4]; |
| 354 | |
| 355 | // Extract sub-seconds if any |
| 356 | match bytes.get(5) { |
| 357 | Some(b'.') => { |
| 358 | let decimal = &bytes[6..]; |
| 359 | if decimal.iter().any(|x| !x.is_ascii_digit()) { |
| 360 | return None; |
| 361 | } |
| 362 | match decimal.len() { |