1use core::num::NonZero;
4
5use num_conv::prelude::*;
6
7use crate::format_description::{Period, modifier};
8use crate::parsing::ParsedItem;
9use crate::parsing::combinator::{
10 ExactlyNDigits, Sign, any_digit, exactly_n_digits_padded, n_to_m_digits, n_to_m_digits_padded,
11 opt, sign,
12};
13use crate::unit::*;
14use crate::{Month, Weekday};
15
16#[inline]
21pub(crate) fn parse_calendar_year_full_extended_range(
22 input: &[u8],
23 modifiers: modifier::CalendarYearFullExtendedRange,
24) -> Option<ParsedItem<'_, i32>> {
25 let ParsedItem(input, sign) = opt(sign)(input);
26
27 if let Some(sign) = sign {
28 let ParsedItem(input, year) = n_to_m_digits_padded::<4, 6, u32>(modifiers.padding)(input)?;
29
30 Some(ParsedItem(
31 input,
32 match sign {
33 Sign::Negative => -year.cast_signed(),
34 Sign::Positive => year.cast_signed(),
35 },
36 ))
37 } else if modifiers.sign_is_mandatory {
38 None
39 } else {
40 let ParsedItem(input, year) = exactly_n_digits_padded::<4, u32>(modifiers.padding)(input)?;
41 Some(ParsedItem(input, year.cast_signed()))
42 }
43}
44
45#[inline]
50pub(crate) fn parse_calendar_year_full_standard_range(
51 input: &[u8],
52 modifiers: modifier::CalendarYearFullStandardRange,
53) -> Option<ParsedItem<'_, i32>> {
54 let ParsedItem(input, sign) = opt(sign)(input);
55
56 if let Some(sign) = sign {
57 let ParsedItem(input, year) = exactly_n_digits_padded::<4, u32>(modifiers.padding)(input)?;
58
59 Some(ParsedItem(
60 input,
61 match sign {
62 Sign::Negative => -year.cast_signed(),
63 Sign::Positive => year.cast_signed(),
64 },
65 ))
66 } else if modifiers.sign_is_mandatory {
67 None
68 } else {
69 let ParsedItem(input, year) = exactly_n_digits_padded::<4, u32>(modifiers.padding)(input)?;
70 Some(ParsedItem(input, year.cast_signed()))
71 }
72}
73
74#[inline]
79pub(crate) fn parse_iso_year_full_extended_range(
80 input: &[u8],
81 modifiers: modifier::IsoYearFullExtendedRange,
82) -> Option<ParsedItem<'_, i32>> {
83 let ParsedItem(input, sign) = opt(sign)(input);
84
85 if let Some(sign) = sign {
86 let ParsedItem(input, year) = n_to_m_digits_padded::<4, 6, u32>(modifiers.padding)(input)?;
87
88 Some(ParsedItem(
89 input,
90 match sign {
91 Sign::Negative => -year.cast_signed(),
92 Sign::Positive => year.cast_signed(),
93 },
94 ))
95 } else if modifiers.sign_is_mandatory {
96 None
97 } else {
98 let ParsedItem(input, year) = exactly_n_digits_padded::<4, u32>(modifiers.padding)(input)?;
99 Some(ParsedItem(input, year.cast_signed()))
100 }
101}
102
103#[inline]
108pub(crate) fn parse_iso_year_full_standard_range(
109 input: &[u8],
110 modifiers: modifier::IsoYearFullStandardRange,
111) -> Option<ParsedItem<'_, i32>> {
112 let ParsedItem(input, sign) = opt(sign)(input);
113
114 if let Some(sign) = sign {
115 let ParsedItem(input, year) = exactly_n_digits_padded::<4, u32>(modifiers.padding)(input)?;
116
117 Some(ParsedItem(
118 input,
119 match sign {
120 Sign::Negative => -year.cast_signed(),
121 Sign::Positive => year.cast_signed(),
122 },
123 ))
124 } else if modifiers.sign_is_mandatory {
125 None
126 } else {
127 let ParsedItem(input, year) = exactly_n_digits_padded::<4, u32>(modifiers.padding)(input)?;
128 Some(ParsedItem(input, year.cast_signed()))
129 }
130}
131
132#[inline]
137pub(crate) fn parse_calendar_year_century_extended_range(
138 input: &[u8],
139 modifiers: modifier::CalendarYearCenturyExtendedRange,
140) -> Option<ParsedItem<'_, (i16, bool)>> {
141 let ParsedItem(input, sign) = opt(sign)(input);
142
143 if let Some(sign) = sign {
144 let ParsedItem(input, year) = n_to_m_digits_padded::<2, 4, u16>(modifiers.padding)(input)?;
145
146 Some(ParsedItem(
147 input,
148 match sign {
149 Sign::Negative => (-year.cast_signed(), true),
150 Sign::Positive => (year.cast_signed(), false),
151 },
152 ))
153 } else if modifiers.sign_is_mandatory {
154 None
155 } else {
156 let ParsedItem(input, year) = n_to_m_digits_padded::<1, 2, u16>(modifiers.padding)(input)?;
157 Some(ParsedItem(input, (year.cast_signed(), false)))
158 }
159}
160
161#[inline]
166pub(crate) fn parse_calendar_year_century_standard_range(
167 input: &[u8],
168 modifiers: modifier::CalendarYearCenturyStandardRange,
169) -> Option<ParsedItem<'_, (i16, bool)>> {
170 let ParsedItem(input, sign) = opt(sign)(input);
171
172 if let Some(sign) = sign {
173 let ParsedItem(input, year) = exactly_n_digits_padded::<2, u16>(modifiers.padding)(input)?;
174
175 Some(ParsedItem(
176 input,
177 match sign {
178 Sign::Negative => (-year.cast_signed(), true),
179 Sign::Positive => (year.cast_signed(), false),
180 },
181 ))
182 } else if modifiers.sign_is_mandatory {
183 None
184 } else {
185 let ParsedItem(input, year) = n_to_m_digits_padded::<1, 2, u16>(modifiers.padding)(input)?;
186 Some(ParsedItem(input, (year.cast_signed(), false)))
187 }
188}
189
190#[inline]
195pub(crate) fn parse_iso_year_century_extended_range(
196 input: &[u8],
197 modifiers: modifier::IsoYearCenturyExtendedRange,
198) -> Option<ParsedItem<'_, (i16, bool)>> {
199 let ParsedItem(input, sign) = opt(sign)(input);
200
201 if let Some(sign) = sign {
202 let ParsedItem(input, year) = n_to_m_digits_padded::<2, 4, u16>(modifiers.padding)(input)?;
203
204 Some(ParsedItem(
205 input,
206 match sign {
207 Sign::Negative => (-year.cast_signed(), true),
208 Sign::Positive => (year.cast_signed(), false),
209 },
210 ))
211 } else if modifiers.sign_is_mandatory {
212 None
213 } else {
214 let ParsedItem(input, year) = n_to_m_digits_padded::<1, 2, u16>(modifiers.padding)(input)?;
215 Some(ParsedItem(input, (year.cast_signed(), false)))
216 }
217}
218
219#[inline]
224pub(crate) fn parse_iso_year_century_standard_range(
225 input: &[u8],
226 modifiers: modifier::IsoYearCenturyStandardRange,
227) -> Option<ParsedItem<'_, (i16, bool)>> {
228 let ParsedItem(input, sign) = opt(sign)(input);
229
230 if let Some(sign) = sign {
231 let ParsedItem(input, year) = exactly_n_digits_padded::<2, u16>(modifiers.padding)(input)?;
232
233 Some(ParsedItem(
234 input,
235 match sign {
236 Sign::Negative => (-year.cast_signed(), true),
237 Sign::Positive => (year.cast_signed(), false),
238 },
239 ))
240 } else if modifiers.sign_is_mandatory {
241 None
242 } else {
243 let ParsedItem(input, year) = n_to_m_digits_padded::<1, 2, u16>(modifiers.padding)(input)?;
244 Some(ParsedItem(input, (year.cast_signed(), false)))
245 }
246}
247
248#[inline]
250pub(crate) fn parse_calendar_year_last_two(
251 input: &[u8],
252 modifiers: modifier::CalendarYearLastTwo,
253) -> Option<ParsedItem<'_, u8>> {
254 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
255}
256
257#[inline]
259pub(crate) fn parse_iso_year_last_two(
260 input: &[u8],
261 modifiers: modifier::IsoYearLastTwo,
262) -> Option<ParsedItem<'_, u8>> {
263 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
264}
265
266#[inline]
268pub(crate) fn parse_month_short(
269 input: &[u8],
270 modifiers: modifier::MonthShort,
271) -> Option<ParsedItem<'_, Month>> {
272 let [first, second, third, rest @ ..] = input else {
273 return None;
274 };
275 let byte = if modifiers.case_sensitive {
276 u32::from_ne_bytes([0, *first, *second, *third])
277 } else {
278 u32::from_ne_bytes([
279 0,
280 first.to_ascii_uppercase(),
281 second.to_ascii_lowercase(),
282 third.to_ascii_lowercase(),
283 ])
284 };
285 const WEEKDAYS: [u32; 12] = [
286 u32::from_ne_bytes([0, b'J', b'a', b'n']),
287 u32::from_ne_bytes([0, b'F', b'e', b'b']),
288 u32::from_ne_bytes([0, b'M', b'a', b'r']),
289 u32::from_ne_bytes([0, b'A', b'p', b'r']),
290 u32::from_ne_bytes([0, b'M', b'a', b'y']),
291 u32::from_ne_bytes([0, b'J', b'u', b'n']),
292 u32::from_ne_bytes([0, b'J', b'u', b'l']),
293 u32::from_ne_bytes([0, b'A', b'u', b'g']),
294 u32::from_ne_bytes([0, b'S', b'e', b'p']),
295 u32::from_ne_bytes([0, b'O', b'c', b't']),
296 u32::from_ne_bytes([0, b'N', b'o', b'v']),
297 u32::from_ne_bytes([0, b'D', b'e', b'c']),
298 ];
299
300 let bitmask = ((WEEKDAYS[0] == byte) as u32) << 1
301 | ((WEEKDAYS[1] == byte) as u32) << 2
302 | ((WEEKDAYS[2] == byte) as u32) << 3
303 | ((WEEKDAYS[3] == byte) as u32) << 4
304 | ((WEEKDAYS[4] == byte) as u32) << 5
305 | ((WEEKDAYS[5] == byte) as u32) << 6
306 | ((WEEKDAYS[6] == byte) as u32) << 7
307 | ((WEEKDAYS[7] == byte) as u32) << 8
308 | ((WEEKDAYS[8] == byte) as u32) << 9
309 | ((WEEKDAYS[9] == byte) as u32) << 10
310 | ((WEEKDAYS[10] == byte) as u32) << 11
311 | ((WEEKDAYS[11] == byte) as u32) << 12;
312 if bitmask == 0 {
313 return None;
314 }
315 let index = if cfg!(target_endian = "little") {
316 bitmask.trailing_zeros() as u8
317 } else {
318 31 - bitmask.leading_zeros() as u8
319 };
320
321 let month = unsafe { Month::from_number(NonZero::new(index)?).unwrap_unchecked() };
325
326 Some(ParsedItem(rest, month))
327}
328
329#[inline]
331pub(crate) fn parse_month_long(
332 input: &[u8],
333 modifiers: modifier::MonthLong,
334) -> Option<ParsedItem<'_, Month>> {
335 use Month::*;
336
337 let ParsedItem(rest, month) = parse_month_short(
338 input,
339 modifier::MonthShort {
340 case_sensitive: modifiers.case_sensitive,
341 },
342 )?;
343
344 let expected_remaining = match month {
345 January => b"uary".as_slice(),
346 February => b"ruary".as_slice(),
347 March => b"ch".as_slice(),
348 April => b"il".as_slice(),
349 May => b"".as_slice(),
350 June => b"e".as_slice(),
351 July => b"y".as_slice(),
352 August => b"ust".as_slice(),
353 September => b"tember".as_slice(),
354 October => b"ober".as_slice(),
355 November | December => b"ember".as_slice(),
356 };
357
358 if modifiers.case_sensitive {
359 rest.strip_prefix(expected_remaining)
360 .map(|remaining| ParsedItem(remaining, month))
361 } else {
362 let (head, tail) = rest.split_at_checked(expected_remaining.len())?;
363 core::iter::zip(head, expected_remaining)
364 .all(|(a, b)| a.eq_ignore_ascii_case(b))
365 .then_some(ParsedItem(tail, month))
366 }
367}
368
369#[inline]
371pub(crate) fn parse_month_numerical(
372 input: &[u8],
373 modifiers: modifier::MonthNumerical,
374) -> Option<ParsedItem<'_, Month>> {
375 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)?
376 .flat_map(|n| Month::from_number(NonZero::new(n)?).ok())
377}
378
379#[inline]
382pub(crate) fn parse_week_number_iso(
383 input: &[u8],
384 modifiers: modifier::WeekNumberIso,
385) -> Option<ParsedItem<'_, u8>> {
386 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
387}
388
389#[inline]
392pub(crate) fn parse_week_number_sunday(
393 input: &[u8],
394 modifiers: modifier::WeekNumberSunday,
395) -> Option<ParsedItem<'_, u8>> {
396 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
397}
398
399#[inline]
402pub(crate) fn parse_week_number_monday(
403 input: &[u8],
404 modifiers: modifier::WeekNumberMonday,
405) -> Option<ParsedItem<'_, u8>> {
406 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
407}
408
409#[inline]
411pub(crate) fn parse_weekday_short(
412 input: &[u8],
413 modifiers: modifier::WeekdayShort,
414) -> Option<ParsedItem<'_, Weekday>> {
415 let [first, second, third, rest @ ..] = input else {
416 return None;
417 };
418 let byte = if modifiers.case_sensitive {
419 u32::from_ne_bytes([0, *first, *second, *third])
420 } else {
421 u32::from_ne_bytes([
422 0,
423 first.to_ascii_uppercase(),
424 second.to_ascii_lowercase(),
425 third.to_ascii_lowercase(),
426 ])
427 };
428 const WEEKDAYS: [u32; 7] = [
429 u32::from_ne_bytes([0, b'M', b'o', b'n']),
430 u32::from_ne_bytes([0, b'T', b'u', b'e']),
431 u32::from_ne_bytes([0, b'W', b'e', b'd']),
432 u32::from_ne_bytes([0, b'T', b'h', b'u']),
433 u32::from_ne_bytes([0, b'F', b'r', b'i']),
434 u32::from_ne_bytes([0, b'S', b'a', b't']),
435 u32::from_ne_bytes([0, b'S', b'u', b'n']),
436 ];
437
438 let bitmask = ((WEEKDAYS[0] == byte) as u32)
439 | ((WEEKDAYS[1] == byte) as u32) << 1
440 | ((WEEKDAYS[2] == byte) as u32) << 2
441 | ((WEEKDAYS[3] == byte) as u32) << 3
442 | ((WEEKDAYS[4] == byte) as u32) << 4
443 | ((WEEKDAYS[5] == byte) as u32) << 5
444 | ((WEEKDAYS[6] == byte) as u32) << 6;
445 if bitmask == 0 {
446 return None;
447 }
448 let index = if cfg!(target_endian = "little") {
449 bitmask.trailing_zeros()
450 } else {
451 31 - bitmask.leading_zeros()
452 };
453
454 if index > 6 {
455 return None;
456 }
457 let weekday = unsafe { core::mem::transmute::<u8, Weekday>(index.truncate()) };
461
462 Some(ParsedItem(rest, weekday))
463}
464
465#[inline]
467pub(crate) fn parse_weekday_long(
468 input: &[u8],
469 modifiers: modifier::WeekdayLong,
470) -> Option<ParsedItem<'_, Weekday>> {
471 let ParsedItem(rest, weekday) = parse_weekday_short(
472 input,
473 modifier::WeekdayShort {
474 case_sensitive: modifiers.case_sensitive,
475 },
476 )?;
477
478 let expected_remaining = match weekday {
479 Weekday::Monday | Weekday::Friday | Weekday::Sunday => b"day".as_slice(),
480 Weekday::Tuesday => b"sday".as_slice(),
481 Weekday::Wednesday => b"nesday".as_slice(),
482 Weekday::Thursday => b"rsday".as_slice(),
483 Weekday::Saturday => b"urday".as_slice(),
484 };
485
486 if modifiers.case_sensitive {
487 rest.strip_prefix(expected_remaining)
488 .map(|remaining| ParsedItem(remaining, weekday))
489 } else {
490 let (head, tail) = rest.split_at_checked(expected_remaining.len())?;
491 core::iter::zip(head, expected_remaining)
492 .all(|(a, b)| a.eq_ignore_ascii_case(b))
493 .then_some(ParsedItem(tail, weekday))
494 }
495}
496
497#[inline]
500pub(crate) fn parse_weekday_sunday(
501 input: &[u8],
502 modifiers: modifier::WeekdaySunday,
503) -> Option<ParsedItem<'_, Weekday>> {
504 let [digit, rest @ ..] = input else {
505 return None;
506 };
507 let mut digit = digit
508 .wrapping_sub(b'0')
509 .wrapping_sub(u8::from(modifiers.one_indexed));
510 if digit > 6 {
511 return None;
512 }
513
514 digit = (digit + 6) % 7;
516
517 let weekday = unsafe { core::mem::transmute::<u8, Weekday>(digit) };
519 Some(ParsedItem(rest, weekday))
520}
521
522#[inline]
525pub(crate) fn parse_weekday_monday(
526 input: &[u8],
527 modifiers: modifier::WeekdayMonday,
528) -> Option<ParsedItem<'_, Weekday>> {
529 let [digit, rest @ ..] = input else {
530 return None;
531 };
532 let digit = digit
533 .wrapping_sub(b'0')
534 .wrapping_sub(u8::from(modifiers.one_indexed));
535 if digit > 6 {
536 return None;
537 }
538
539 let weekday = unsafe { core::mem::transmute::<u8, Weekday>(digit) };
541 Some(ParsedItem(rest, weekday))
542}
543
544#[inline]
546pub(crate) fn parse_ordinal(
547 input: &[u8],
548 modifiers: modifier::Ordinal,
549) -> Option<ParsedItem<'_, NonZero<u16>>> {
550 exactly_n_digits_padded::<3, _>(modifiers.padding)(input)
551 .and_then(|parsed| parsed.flat_map(NonZero::new))
552}
553
554#[inline]
556pub(crate) fn parse_day(
557 input: &[u8],
558 modifiers: modifier::Day,
559) -> Option<ParsedItem<'_, NonZero<u8>>> {
560 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
561 .and_then(|parsed| parsed.flat_map(NonZero::new))
562}
563
564#[inline]
566pub(crate) fn parse_hour_12(
567 input: &[u8],
568 modifiers: modifier::Hour12,
569) -> Option<ParsedItem<'_, u8>> {
570 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
571}
572
573#[inline]
575pub(crate) fn parse_hour_24(
576 input: &[u8],
577 modifiers: modifier::Hour24,
578) -> Option<ParsedItem<'_, u8>> {
579 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
580}
581
582#[inline]
584pub(crate) fn parse_minute(
585 input: &[u8],
586 modifiers: modifier::Minute,
587) -> Option<ParsedItem<'_, u8>> {
588 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
589}
590
591#[inline]
593pub(crate) fn parse_second(
594 input: &[u8],
595 modifiers: modifier::Second,
596) -> Option<ParsedItem<'_, u8>> {
597 exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
598}
599
600#[inline]
602pub(crate) fn parse_period(
603 input: &[u8],
604 modifiers: modifier::Period,
605) -> Option<ParsedItem<'_, Period>> {
606 let [first, second, rest @ ..] = input else {
607 return None;
608 };
609 let mut first = *first;
610 let mut second = *second;
611
612 if modifiers.is_uppercase && modifiers.case_sensitive {
613 match [first, second].as_slice() {
614 b"AM" => Some(ParsedItem(rest, Period::Am)),
615 b"PM" => Some(ParsedItem(rest, Period::Pm)),
616 _ => None,
617 }
618 } else {
619 first = first.to_ascii_lowercase();
620 second = second.to_ascii_lowercase();
621
622 match &[first, second] {
623 b"am" => Some(ParsedItem(rest, Period::Am)),
624 b"pm" => Some(ParsedItem(rest, Period::Pm)),
625 _ => None,
626 }
627 }
628}
629
630pub(crate) fn parse_subsecond(
632 input: &[u8],
633 modifiers: modifier::Subsecond,
634) -> Option<ParsedItem<'_, u32>> {
635 use modifier::SubsecondDigits::*;
636 Some(match modifiers.digits {
637 One => ExactlyNDigits::<1>::parse(input)?.map(|v| v.extend::<u32>() * 100_000_000),
638 Two => ExactlyNDigits::<2>::parse(input)?.map(|v| v.extend::<u32>() * 10_000_000),
639 Three => ExactlyNDigits::<3>::parse(input)?.map(|v| v.extend::<u32>() * 1_000_000),
640 Four => ExactlyNDigits::<4>::parse(input)?.map(|v| v.extend::<u32>() * 100_000),
641 Five => ExactlyNDigits::<5>::parse(input)?.map(|v| v * 10_000),
642 Six => ExactlyNDigits::<6>::parse(input)?.map(|v| v * 1_000),
643 Seven => ExactlyNDigits::<7>::parse(input)?.map(|v| v * 100),
644 Eight => ExactlyNDigits::<8>::parse(input)?.map(|v| v * 10),
645 Nine => ExactlyNDigits::<9>::parse(input)?,
646 OneOrMore => {
647 let ParsedItem(mut input, mut value) =
648 any_digit(input)?.map(|v| (v - b'0').extend::<u32>() * 100_000_000);
649
650 let mut multiplier = 10_000_000;
651 while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
652 value += (digit - b'0').extend::<u32>() * multiplier;
653 input = new_input;
654 multiplier /= 10;
655 }
656
657 ParsedItem(input, value)
658 }
659 })
660}
661
662#[inline]
666pub(crate) fn parse_offset_hour(
667 input: &[u8],
668 modifiers: modifier::OffsetHour,
669) -> Option<ParsedItem<'_, (i8, bool)>> {
670 let ParsedItem(input, sign) = opt(sign)(input);
671 let ParsedItem(input, hour) = exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?;
672 match sign {
673 Some(Sign::Negative) => Some(ParsedItem(input, (-hour.cast_signed(), true))),
674 None if modifiers.sign_is_mandatory => None,
675 _ => Some(ParsedItem(input, (hour.cast_signed(), false))),
676 }
677}
678
679#[inline]
681pub(crate) fn parse_offset_minute(
682 input: &[u8],
683 modifiers: modifier::OffsetMinute,
684) -> Option<ParsedItem<'_, i8>> {
685 Some(
686 exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?
687 .map(|offset_minute| offset_minute.cast_signed()),
688 )
689}
690
691#[inline]
693pub(crate) fn parse_offset_second(
694 input: &[u8],
695 modifiers: modifier::OffsetSecond,
696) -> Option<ParsedItem<'_, i8>> {
697 Some(
698 exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?
699 .map(|offset_second| offset_second.cast_signed()),
700 )
701}
702
703#[inline]
705pub(crate) fn parse_ignore(
706 input: &[u8],
707 modifiers: modifier::Ignore,
708) -> Option<ParsedItem<'_, ()>> {
709 let modifier::Ignore { count } = modifiers;
710 let input = input.get((count.get().extend())..)?;
711 Some(ParsedItem(input, ()))
712}
713
714#[inline]
716pub(crate) fn parse_unix_timestamp_second(
717 input: &[u8],
718 modifiers: modifier::UnixTimestampSecond,
719) -> Option<ParsedItem<'_, i128>> {
720 let ParsedItem(input, sign) = opt(sign)(input);
721 let ParsedItem(input, nano_timestamp) =
722 n_to_m_digits::<1, 14, u128>(input)?.map(|val| val * Nanosecond::per_t::<u128>(Second));
723
724 match sign {
725 Some(Sign::Negative) => Some(ParsedItem(input, -nano_timestamp.cast_signed())),
726 None if modifiers.sign_is_mandatory => None,
727 _ => Some(ParsedItem(input, nano_timestamp.cast_signed())),
728 }
729}
730
731#[inline]
734pub(crate) fn parse_unix_timestamp_millisecond(
735 input: &[u8],
736 modifiers: modifier::UnixTimestampMillisecond,
737) -> Option<ParsedItem<'_, i128>> {
738 let ParsedItem(input, sign) = opt(sign)(input);
739 let ParsedItem(input, nano_timestamp) = n_to_m_digits::<1, 17, u128>(input)?
740 .map(|val| val * Nanosecond::per_t::<u128>(Millisecond));
741
742 match sign {
743 Some(Sign::Negative) => Some(ParsedItem(input, -nano_timestamp.cast_signed())),
744 None if modifiers.sign_is_mandatory => None,
745 _ => Some(ParsedItem(input, nano_timestamp.cast_signed())),
746 }
747}
748
749#[inline]
752pub(crate) fn parse_unix_timestamp_microsecond(
753 input: &[u8],
754 modifiers: modifier::UnixTimestampMicrosecond,
755) -> Option<ParsedItem<'_, i128>> {
756 let ParsedItem(input, sign) = opt(sign)(input);
757 let ParsedItem(input, nano_timestamp) = n_to_m_digits::<1, 20, u128>(input)?
758 .map(|val| val * Nanosecond::per_t::<u128>(Microsecond));
759
760 match sign {
761 Some(Sign::Negative) => Some(ParsedItem(input, -nano_timestamp.cast_signed())),
762 None if modifiers.sign_is_mandatory => None,
763 _ => Some(ParsedItem(input, nano_timestamp.cast_signed())),
764 }
765}
766
767#[inline]
769pub(crate) fn parse_unix_timestamp_nanosecond(
770 input: &[u8],
771 modifiers: modifier::UnixTimestampNanosecond,
772) -> Option<ParsedItem<'_, i128>> {
773 let ParsedItem(input, sign) = opt(sign)(input);
774 let ParsedItem(input, nano_timestamp) = n_to_m_digits::<1, 23, u128>(input)?;
775
776 match sign {
777 Some(Sign::Negative) => Some(ParsedItem(input, -nano_timestamp.cast_signed())),
778 None if modifiers.sign_is_mandatory => None,
779 _ => Some(ParsedItem(input, nano_timestamp.cast_signed())),
780 }
781}
782
783#[inline]
787pub(crate) fn parse_end(input: &[u8], end: modifier::End) -> Option<ParsedItem<'_, ()>> {
788 let modifier::End { trailing_input } = end;
789
790 if trailing_input == modifier::TrailingInput::Discard || input.is_empty() {
791 Some(ParsedItem(b"", ()))
792 } else {
793 None
794 }
795}