1mod component_provider;
4pub(crate) mod formattable;
5mod iso8601;
6mod metadata;
7
8use core::mem::MaybeUninit;
9use core::num::NonZero;
10use std::io;
11
12use deranged::{Option_ri32, Option_ru8, ri8, ri16, ri32, ru8, ru16, ru32};
13use num_conv::prelude::*;
14
15use self::component_provider::ComponentProvider;
16pub use self::formattable::Formattable;
17use crate::format_description::{Period, modifier};
18use crate::internal_macros::try_likely_ok;
19use crate::time::{Hours, Minutes, Nanoseconds, Seconds};
20use crate::utc_offset::{Hours as OffsetHours, Minutes as OffsetMinutes, Seconds as OffsetSeconds};
21use crate::{Month, Weekday, error, num_fmt};
22
23type Day = ru8<1, 31>;
24type OptionDay = Option_ru8<1, 31>;
25type Ordinal = ru16<1, 366>;
26type IsoWeekNumber = ru8<1, 53>;
27type OptionIsoWeekNumber = Option_ru8<1, 53>;
28type MondayBasedWeek = ru8<0, 53>;
29type SundayBasedWeek = ru8<0, 53>;
30type Year = ri32<-999_999, 999_999>;
31type StandardYear = ri16<-9_999, 9_999>;
32type OptionYear = Option_ri32<-999_999, 999_999>;
33type ExtendedCentury = ri16<-9_999, 9_999>;
34type StandardCentury = ri8<-99, 99>;
35type LastTwo = ru8<0, 99>;
36
37const MONTH_NAMES: [&str; 12] = [
38 "January",
39 "February",
40 "March",
41 "April",
42 "May",
43 "June",
44 "July",
45 "August",
46 "September",
47 "October",
48 "November",
49 "December",
50];
51
52const WEEKDAY_NAMES: [&str; 7] = [
53 "Monday",
54 "Tuesday",
55 "Wednesday",
56 "Thursday",
57 "Friday",
58 "Saturday",
59 "Sunday",
60];
61
62#[inline]
64pub(crate) fn write_bytes(
65 output: &mut (impl io::Write + ?Sized),
66 bytes: &[u8],
67) -> io::Result<usize> {
68 try_likely_ok!(output.write_all(bytes));
69 Ok(bytes.len())
70}
71
72#[inline]
74pub(crate) fn write(output: &mut (impl io::Write + ?Sized), s: &str) -> io::Result<usize> {
75 try_likely_ok!(output.write_all(s.as_bytes()));
76 Ok(s.len())
77}
78
79#[inline]
81pub(crate) fn write_many<const N: usize>(
82 output: &mut (impl io::Write + ?Sized),
83 arr: [&str; N],
84) -> io::Result<usize> {
85 let mut bytes = 0;
86 for s in arr {
87 try_likely_ok!(output.write_all(s.as_bytes()));
88 bytes += s.len();
89 }
90 Ok(bytes)
91}
92
93#[inline]
95pub(crate) fn write_if(
96 output: &mut (impl io::Write + ?Sized),
97 pred: bool,
98 s: &str,
99) -> io::Result<usize> {
100 if pred { write(output, s) } else { Ok(0) }
101}
102
103#[inline]
105pub(crate) fn write_if_else(
106 output: &mut (impl io::Write + ?Sized),
107 pred: bool,
108 true_str: &str,
109 false_str: &str,
110) -> io::Result<usize> {
111 write(output, if pred { true_str } else { false_str })
112}
113
114#[inline]
119fn f64_10_pow_x(x: NonZero<u8>) -> f64 {
120 match x.get() {
121 1 => 10.,
122 2 => 100.,
123 3 => 1_000.,
124 4 => 10_000.,
125 5 => 100_000.,
126 6 => 1_000_000.,
127 7 => 10_000_000.,
128 8 => 100_000_000.,
129 9 => 1_000_000_000.,
130 x => 10_f64.powi(x.cast_signed().extend()),
131 }
132}
133
134#[inline]
139pub(crate) fn format_float(
140 output: &mut (impl io::Write + ?Sized),
141 mut value: f64,
142 digits_before_decimal: u8,
143 digits_after_decimal: Option<NonZero<u8>>,
144) -> io::Result<usize> {
145 match digits_after_decimal {
146 Some(digits_after_decimal) => {
147 if digits_after_decimal.get() < 9 {
160 let trunc_num = f64_10_pow_x(digits_after_decimal);
161 value = f64::trunc(value * trunc_num) / trunc_num;
162 }
163
164 let digits_after_decimal = digits_after_decimal.get().extend();
165 let width = digits_before_decimal.extend::<usize>() + 1 + digits_after_decimal;
166 try_likely_ok!(write!(output, "{value:0>width$.digits_after_decimal$}"));
167 Ok(width)
168 }
169 None => {
170 let value = value.trunc() as u64;
171 let width = digits_before_decimal.extend();
172 try_likely_ok!(write!(output, "{value:0>width$}"));
173 Ok(width)
174 }
175 }
176}
177
178#[inline]
180pub(crate) fn format_single_digit(
181 output: &mut (impl io::Write + ?Sized),
182 value: ru8<0, 9>,
183) -> io::Result<usize> {
184 write(output, num_fmt::single_digit(value))
185}
186
187#[inline]
189pub(crate) fn format_two_digits(
190 output: &mut (impl io::Write + ?Sized),
191 value: ru8<0, 99>,
192 padding: modifier::Padding,
193) -> io::Result<usize> {
194 let s = match padding {
195 modifier::Padding::Space => num_fmt::two_digits_space_padded(value),
196 modifier::Padding::Zero => num_fmt::two_digits_zero_padded(value),
197 modifier::Padding::None => num_fmt::one_to_two_digits_no_padding(value),
198 };
199 write(output, s)
200}
201
202#[inline]
204pub(crate) fn format_three_digits(
205 output: &mut (impl io::Write + ?Sized),
206 value: ru16<0, 999>,
207 padding: modifier::Padding,
208) -> io::Result<usize> {
209 let [first, second_and_third] = match padding {
210 modifier::Padding::Space => num_fmt::three_digits_space_padded(value),
211 modifier::Padding::Zero => num_fmt::three_digits_zero_padded(value),
212 modifier::Padding::None => num_fmt::one_to_three_digits_no_padding(value),
213 };
214 write_many(output, [first, second_and_third])
215}
216
217#[inline]
219pub(crate) fn format_four_digits(
220 output: &mut (impl io::Write + ?Sized),
221 value: ru16<0, 9_999>,
222 padding: modifier::Padding,
223) -> io::Result<usize> {
224 let [first_and_second, third_and_fourth] = match padding {
225 modifier::Padding::Space => num_fmt::four_digits_space_padded(value),
226 modifier::Padding::Zero => num_fmt::four_digits_zero_padded(value),
227 modifier::Padding::None => num_fmt::one_to_four_digits_no_padding(value),
228 };
229 write_many(output, [first_and_second, third_and_fourth])
230}
231
232#[inline]
234pub(crate) fn format_four_digits_pad_zero(
235 output: &mut (impl io::Write + ?Sized),
236 value: ru16<0, 9_999>,
237) -> io::Result<usize> {
238 write_many(output, num_fmt::four_digits_zero_padded(value))
239}
240
241#[inline]
243pub(crate) fn format_five_digits_pad_zero(
244 output: &mut (impl io::Write + ?Sized),
245 value: ru32<0, 99_999>,
246) -> io::Result<usize> {
247 write_many(output, num_fmt::five_digits_zero_padded(value))
248}
249
250#[inline]
252pub(crate) fn format_six_digits_pad_zero(
253 output: &mut (impl io::Write + ?Sized),
254 value: ru32<0, 999_999>,
255) -> io::Result<usize> {
256 write_many(output, num_fmt::six_digits_zero_padded(value))
257}
258
259#[inline]
263pub(crate) fn format_u64_pad_none(
264 output: &mut (impl io::Write + ?Sized),
265 value: u64,
266) -> io::Result<usize> {
267 write(output, &num_fmt::u64_pad_none(value))
268}
269
270#[inline]
274pub(crate) fn format_u128_pad_none(
275 output: &mut (impl io::Write + ?Sized),
276 value: u128,
277) -> io::Result<usize> {
278 write(output, &num_fmt::u128_pad_none(value))
279}
280
281#[inline]
283fn fmt_day(
284 output: &mut (impl io::Write + ?Sized),
285 day: Day,
286 modifier::Day { padding }: modifier::Day,
287) -> Result<usize, io::Error> {
288 format_two_digits(output, day.expand(), padding)
289}
290
291#[inline]
293fn fmt_month_short(
294 output: &mut (impl io::Write + ?Sized),
295 month: Month,
296 modifier::MonthShort {
297 case_sensitive: _, }: modifier::MonthShort,
299) -> io::Result<usize> {
300 write(output, unsafe {
302 MONTH_NAMES[u8::from(month).extend::<usize>() - 1].get_unchecked(..3)
303 })
304}
305
306#[inline]
308fn fmt_month_long(
309 output: &mut (impl io::Write + ?Sized),
310 month: Month,
311 modifier::MonthLong {
312 case_sensitive: _, }: modifier::MonthLong,
314) -> io::Result<usize> {
315 write(output, MONTH_NAMES[u8::from(month).extend::<usize>() - 1])
316}
317
318#[inline]
320fn fmt_month_numerical(
321 output: &mut (impl io::Write + ?Sized),
322 month: Month,
323 modifier::MonthNumerical { padding }: modifier::MonthNumerical,
324) -> io::Result<usize> {
325 format_two_digits(
326 output,
327 unsafe { ru8::new_unchecked(u8::from(month)) },
329 padding,
330 )
331}
332
333#[inline]
335fn fmt_ordinal(
336 output: &mut (impl io::Write + ?Sized),
337 ordinal: Ordinal,
338 modifier::Ordinal { padding }: modifier::Ordinal,
339) -> Result<usize, io::Error> {
340 format_three_digits(output, ordinal.expand(), padding)
341}
342
343#[inline]
345fn fmt_weekday_short(
346 output: &mut (impl io::Write + ?Sized),
347 weekday: Weekday,
348 modifier::WeekdayShort {
349 case_sensitive: _, }: modifier::WeekdayShort,
351) -> io::Result<usize> {
352 write(output, unsafe {
354 WEEKDAY_NAMES[weekday.number_days_from_monday().extend::<usize>()].get_unchecked(..3)
355 })
356}
357
358#[inline]
360fn fmt_weekday_long(
361 output: &mut (impl io::Write + ?Sized),
362 weekday: Weekday,
363 modifier::WeekdayLong {
364 case_sensitive: _, }: modifier::WeekdayLong,
366) -> io::Result<usize> {
367 write(
368 output,
369 WEEKDAY_NAMES[weekday.number_days_from_monday().extend::<usize>()],
370 )
371}
372
373#[inline]
376fn fmt_weekday_sunday(
377 output: &mut (impl io::Write + ?Sized),
378 weekday: Weekday,
379 modifier::WeekdaySunday { one_indexed }: modifier::WeekdaySunday,
380) -> io::Result<usize> {
381 format_single_digit(output, unsafe {
383 ru8::new_unchecked(weekday.number_days_from_sunday() + u8::from(one_indexed))
384 })
385}
386
387#[inline]
390fn fmt_weekday_monday(
391 output: &mut (impl io::Write + ?Sized),
392 weekday: Weekday,
393 modifier::WeekdayMonday { one_indexed }: modifier::WeekdayMonday,
394) -> io::Result<usize> {
395 format_single_digit(output, unsafe {
397 ru8::new_unchecked(weekday.number_days_from_monday() + u8::from(one_indexed))
398 })
399}
400
401#[inline]
402fn fmt_week_number_iso(
403 output: &mut (impl io::Write + ?Sized),
404 week_number: IsoWeekNumber,
405 modifier::WeekNumberIso { padding }: modifier::WeekNumberIso,
406) -> io::Result<usize> {
407 format_two_digits(output, week_number.expand(), padding)
408}
409
410#[inline]
411fn fmt_week_number_sunday(
412 output: &mut (impl io::Write + ?Sized),
413 week_number: SundayBasedWeek,
414 modifier::WeekNumberSunday { padding }: modifier::WeekNumberSunday,
415) -> io::Result<usize> {
416 format_two_digits(output, week_number.expand(), padding)
417}
418
419#[inline]
420fn fmt_week_number_monday(
421 output: &mut (impl io::Write + ?Sized),
422 week_number: MondayBasedWeek,
423 modifier::WeekNumberMonday { padding }: modifier::WeekNumberMonday,
424) -> io::Result<usize> {
425 format_two_digits(output, week_number.expand(), padding)
426}
427
428#[inline]
429fn fmt_calendar_year_full_extended_range(
430 output: &mut (impl io::Write + ?Sized),
431 full_year: Year,
432 modifier::CalendarYearFullExtendedRange {
433 padding,
434 sign_is_mandatory,
435 }: modifier::CalendarYearFullExtendedRange,
436) -> io::Result<usize> {
437 let mut bytes = 0;
438 bytes += try_likely_ok!(fmt_sign(
439 output,
440 full_year.is_negative(),
441 sign_is_mandatory || full_year.get() >= 10_000
442 ));
443 let value: ru32<0, 999_999> =
446 unsafe { full_year.abs().narrow_unchecked::<0, 999_999>().into() };
447
448 bytes += if let Some(value) = value.narrow::<0, 9_999>() {
449 try_likely_ok!(format_four_digits(output, value.into(), padding))
450 } else if let Some(value) = value.narrow::<0, 99_999>() {
451 try_likely_ok!(format_five_digits_pad_zero(output, value))
452 } else {
453 try_likely_ok!(format_six_digits_pad_zero(output, value))
454 };
455 Ok(bytes)
456}
457
458#[inline]
459fn fmt_calendar_year_full_standard_range(
460 output: &mut (impl io::Write + ?Sized),
461 full_year: StandardYear,
462 modifier::CalendarYearFullStandardRange {
463 padding,
464 sign_is_mandatory,
465 }: modifier::CalendarYearFullStandardRange,
466) -> io::Result<usize> {
467 let mut bytes = 0;
468 bytes += try_likely_ok!(fmt_sign(output, full_year.is_negative(), sign_is_mandatory));
469 bytes += try_likely_ok!(format_four_digits(
471 output,
472 unsafe { full_year.abs().narrow_unchecked::<0, 9_999>().into() },
473 padding
474 ));
475 Ok(bytes)
476}
477
478#[inline]
479fn fmt_iso_year_full_extended_range(
480 output: &mut (impl io::Write + ?Sized),
481 full_year: Year,
482 modifier::IsoYearFullExtendedRange {
483 padding,
484 sign_is_mandatory,
485 }: modifier::IsoYearFullExtendedRange,
486) -> io::Result<usize> {
487 let mut bytes = 0;
488 bytes += try_likely_ok!(fmt_sign(
489 output,
490 full_year.is_negative(),
491 sign_is_mandatory || full_year.get() >= 10_000,
492 ));
493 let value: ru32<0, 999_999> =
495 unsafe { full_year.abs().narrow_unchecked::<0, 999_999>().into() };
496
497 bytes += if let Some(value) = value.narrow::<0, 9_999>() {
498 try_likely_ok!(format_four_digits(output, value.into(), padding))
499 } else if let Some(value) = value.narrow::<0, 99_999>() {
500 try_likely_ok!(format_five_digits_pad_zero(output, value))
501 } else {
502 try_likely_ok!(format_six_digits_pad_zero(output, value))
503 };
504 Ok(bytes)
505}
506
507#[inline]
508fn fmt_iso_year_full_standard_range(
509 output: &mut (impl io::Write + ?Sized),
510 year: StandardYear,
511 modifier::IsoYearFullStandardRange {
512 padding,
513 sign_is_mandatory,
514 }: modifier::IsoYearFullStandardRange,
515) -> io::Result<usize> {
516 let mut bytes = 0;
517 bytes += try_likely_ok!(fmt_sign(output, year.is_negative(), sign_is_mandatory));
518 bytes += try_likely_ok!(format_four_digits(
520 output,
521 unsafe { year.abs().narrow_unchecked::<0, 9_999>().into() },
522 padding
523 ));
524 Ok(bytes)
525}
526
527#[inline]
528fn fmt_calendar_year_century_extended_range(
529 output: &mut (impl io::Write + ?Sized),
530 century: ExtendedCentury,
531 is_negative: bool,
532 modifier::CalendarYearCenturyExtendedRange {
533 padding,
534 sign_is_mandatory,
535 }: modifier::CalendarYearCenturyExtendedRange,
536) -> io::Result<usize> {
537 let mut bytes = 0;
538 bytes += try_likely_ok!(fmt_sign(
539 output,
540 is_negative,
541 sign_is_mandatory || century.get() >= 100
542 ));
543 let century: ru16<0, 9_999> = unsafe { century.abs().narrow_unchecked::<0, 9_999>().into() };
545
546 bytes += if let Some(century) = century.narrow::<0, 99>() {
547 try_likely_ok!(format_two_digits(output, century.into(), padding))
548 } else if let Some(century) = century.narrow::<0, 999>() {
549 try_likely_ok!(format_three_digits(output, century, padding))
550 } else {
551 try_likely_ok!(format_four_digits(output, century, padding))
552 };
553 Ok(bytes)
554}
555
556#[inline]
557fn fmt_calendar_year_century_standard_range(
558 output: &mut (impl io::Write + ?Sized),
559 century: StandardCentury,
560 is_negative: bool,
561 modifier::CalendarYearCenturyStandardRange {
562 padding,
563 sign_is_mandatory,
564 }: modifier::CalendarYearCenturyStandardRange,
565) -> io::Result<usize> {
566 let mut bytes = 0;
567 bytes += try_likely_ok!(fmt_sign(output, is_negative, sign_is_mandatory));
568 let century = unsafe { century.abs().narrow_unchecked::<0, 99>() };
570 bytes += try_likely_ok!(format_two_digits(output, century.into(), padding));
571 Ok(bytes)
572}
573
574#[inline]
575fn fmt_iso_year_century_extended_range(
576 output: &mut (impl io::Write + ?Sized),
577 century: ExtendedCentury,
578 is_negative: bool,
579 modifier::IsoYearCenturyExtendedRange {
580 padding,
581 sign_is_mandatory,
582 }: modifier::IsoYearCenturyExtendedRange,
583) -> io::Result<usize> {
584 let mut bytes = 0;
585 bytes += try_likely_ok!(fmt_sign(
586 output,
587 is_negative,
588 sign_is_mandatory || century.get() >= 100,
589 ));
590 let century: ru16<0, 9_999> = unsafe { century.abs().narrow_unchecked::<0, 9_999>().into() };
592
593 bytes += if let Some(century) = century.narrow::<0, 99>() {
594 try_likely_ok!(format_two_digits(output, century.into(), padding))
595 } else if let Some(century) = century.narrow::<0, 999>() {
596 try_likely_ok!(format_three_digits(output, century, padding))
597 } else {
598 try_likely_ok!(format_four_digits(output, century, padding))
599 };
600 Ok(bytes)
601}
602
603#[inline]
604fn fmt_iso_year_century_standard_range(
605 output: &mut (impl io::Write + ?Sized),
606 century: StandardCentury,
607 is_negative: bool,
608 modifier::IsoYearCenturyStandardRange {
609 padding,
610 sign_is_mandatory,
611 }: modifier::IsoYearCenturyStandardRange,
612) -> io::Result<usize> {
613 let mut bytes = 0;
614 bytes += try_likely_ok!(fmt_sign(output, is_negative, sign_is_mandatory));
615 let century = unsafe { century.abs().narrow_unchecked::<0, 99>() };
617 bytes += try_likely_ok!(format_two_digits(output, century.into(), padding));
618 Ok(bytes)
619}
620
621#[inline]
622fn fmt_calendar_year_last_two(
623 output: &mut (impl io::Write + ?Sized),
624 last_two: LastTwo,
625 modifier::CalendarYearLastTwo { padding }: modifier::CalendarYearLastTwo,
626) -> io::Result<usize> {
627 format_two_digits(output, last_two, padding)
628}
629
630#[inline]
631fn fmt_iso_year_last_two(
632 output: &mut (impl io::Write + ?Sized),
633 last_two: LastTwo,
634 modifier::IsoYearLastTwo { padding }: modifier::IsoYearLastTwo,
635) -> io::Result<usize> {
636 format_two_digits(output, last_two, padding)
637}
638
639#[inline]
641fn fmt_hour_12(
642 output: &mut (impl io::Write + ?Sized),
643 hour: Hours,
644 modifier::Hour12 { padding }: modifier::Hour12,
645) -> io::Result<usize> {
646 format_two_digits(
648 output,
649 unsafe { ru8::new_unchecked((hour.get() + 11) % 12 + 1) },
650 padding,
651 )
652}
653
654#[inline]
656fn fmt_hour_24(
657 output: &mut (impl io::Write + ?Sized),
658 hour: Hours,
659 modifier::Hour24 { padding }: modifier::Hour24,
660) -> io::Result<usize> {
661 format_two_digits(output, hour.expand(), padding)
662}
663
664#[inline]
666fn fmt_minute(
667 output: &mut (impl io::Write + ?Sized),
668 minute: Minutes,
669 modifier::Minute { padding }: modifier::Minute,
670) -> Result<usize, io::Error> {
671 format_two_digits(output, minute.expand(), padding)
672}
673
674#[inline]
676fn fmt_period(
677 output: &mut (impl io::Write + ?Sized),
678 period: Period,
679 modifier::Period {
680 is_uppercase,
681 case_sensitive: _, }: modifier::Period,
683) -> Result<usize, io::Error> {
684 write(
685 output,
686 match (period, is_uppercase) {
687 (Period::Am, false) => "am",
688 (Period::Am, true) => "AM",
689 (Period::Pm, false) => "pm",
690 (Period::Pm, true) => "PM",
691 },
692 )
693}
694
695#[inline]
697fn fmt_second(
698 output: &mut (impl io::Write + ?Sized),
699 second: Seconds,
700 modifier::Second { padding }: modifier::Second,
701) -> Result<usize, io::Error> {
702 format_two_digits(output, second.expand(), padding)
703}
704
705#[inline]
707fn fmt_subsecond(
708 output: &mut (impl io::Write + ?Sized),
709 nanos: Nanoseconds,
710 modifier::Subsecond { digits }: modifier::Subsecond,
711) -> Result<usize, io::Error> {
712 use modifier::SubsecondDigits::*;
713
714 #[repr(C, align(8))]
715 #[derive(Clone, Copy)]
716 struct Digits {
717 _padding: MaybeUninit<[u8; 7]>,
718 digit_1: u8,
719 digits_2_thru_9: [u8; 8],
720 }
721
722 let [
723 digit_1,
724 digits_2_and_3,
725 digits_4_and_5,
726 digits_6_and_7,
727 digits_8_and_9,
728 ] = num_fmt::subsecond_from_nanos(nanos);
729
730 let buf = Digits {
733 _padding: MaybeUninit::uninit(),
734 digit_1: digit_1.as_bytes()[0],
735 digits_2_thru_9: [
736 digits_2_and_3.as_bytes()[0],
737 digits_2_and_3.as_bytes()[1],
738 digits_4_and_5.as_bytes()[0],
739 digits_4_and_5.as_bytes()[1],
740 digits_6_and_7.as_bytes()[0],
741 digits_6_and_7.as_bytes()[1],
742 digits_8_and_9.as_bytes()[0],
743 digits_8_and_9.as_bytes()[1],
744 ],
745 };
746
747 let len = match digits {
748 One => 1,
749 Two => 2,
750 Three => 3,
751 Four => 4,
752 Five => 5,
753 Six => 6,
754 Seven => 7,
755 Eight => 8,
756 Nine => 9,
757 OneOrMore => {
758 let bitmask = u64::from_le_bytes(buf.digits_2_thru_9) ^ u64::from_le_bytes([b'0'; 8]);
762 let digits_to_truncate = bitmask.leading_zeros() / 8;
763 9 - digits_to_truncate as usize
764 }
765 };
766
767 let s = unsafe {
771 num_fmt::StackStr::new(
772 *(&raw const buf)
773 .byte_add(core::mem::offset_of!(Digits, digit_1))
774 .cast::<[MaybeUninit<u8>; 9]>(),
775 len,
776 )
777 };
778 write(output, &s)
779}
780
781#[inline]
782fn fmt_sign(
783 output: &mut (impl io::Write + ?Sized),
784 is_negative: bool,
785 sign_is_mandatory: bool,
786) -> Result<usize, io::Error> {
787 if is_negative {
788 write(output, "-")
789 } else if sign_is_mandatory {
790 write(output, "+")
791 } else {
792 Ok(0)
793 }
794}
795
796#[inline]
798fn fmt_offset_hour(
799 output: &mut (impl io::Write + ?Sized),
800 is_negative: bool,
801 hour: OffsetHours,
802 modifier::OffsetHour {
803 padding,
804 sign_is_mandatory,
805 }: modifier::OffsetHour,
806) -> Result<usize, io::Error> {
807 let mut bytes = 0;
808 bytes += try_likely_ok!(fmt_sign(output, is_negative, sign_is_mandatory));
809 bytes += try_likely_ok!(format_two_digits(
811 output,
812 unsafe { ru8::new_unchecked(hour.get().unsigned_abs()) },
813 padding,
814 ));
815 Ok(bytes)
816}
817
818#[inline]
820fn fmt_offset_minute(
821 output: &mut (impl io::Write + ?Sized),
822 offset_minute: OffsetMinutes,
823 modifier::OffsetMinute { padding }: modifier::OffsetMinute,
824) -> Result<usize, io::Error> {
825 format_two_digits(
826 output,
827 unsafe { ru8::new_unchecked(offset_minute.get().unsigned_abs()) },
830 padding,
831 )
832}
833
834#[inline]
836fn fmt_offset_second(
837 output: &mut (impl io::Write + ?Sized),
838 offset_second: OffsetSeconds,
839 modifier::OffsetSecond { padding }: modifier::OffsetSecond,
840) -> Result<usize, io::Error> {
841 format_two_digits(
842 output,
843 unsafe { ru8::new_unchecked(offset_second.get().unsigned_abs()) },
846 padding,
847 )
848}
849
850#[inline]
852fn fmt_unix_timestamp_second(
853 output: &mut (impl io::Write + ?Sized),
854 timestamp: i64,
855 modifier::UnixTimestampSecond { sign_is_mandatory }: modifier::UnixTimestampSecond,
856) -> Result<usize, io::Error> {
857 let mut bytes = 0;
858 bytes += try_likely_ok!(fmt_sign(output, timestamp < 0, sign_is_mandatory));
859 bytes += try_likely_ok!(format_u64_pad_none(output, timestamp.unsigned_abs()));
860 Ok(bytes)
861}
862
863#[inline]
865fn fmt_unix_timestamp_millisecond(
866 output: &mut (impl io::Write + ?Sized),
867 timestamp_millis: i64,
868 modifier::UnixTimestampMillisecond { sign_is_mandatory }: modifier::UnixTimestampMillisecond,
869) -> Result<usize, io::Error> {
870 let mut bytes = 0;
871 bytes += try_likely_ok!(fmt_sign(output, timestamp_millis < 0, sign_is_mandatory));
872 bytes += try_likely_ok!(format_u64_pad_none(output, timestamp_millis.unsigned_abs()));
873 Ok(bytes)
874}
875
876#[inline]
878fn fmt_unix_timestamp_microsecond(
879 output: &mut (impl io::Write + ?Sized),
880 timestamp_micros: i128,
881 modifier::UnixTimestampMicrosecond { sign_is_mandatory }: modifier::UnixTimestampMicrosecond,
882) -> Result<usize, io::Error> {
883 let mut bytes = 0;
884 bytes += try_likely_ok!(fmt_sign(output, timestamp_micros < 0, sign_is_mandatory));
885 bytes += try_likely_ok!(format_u128_pad_none(
886 output,
887 timestamp_micros.unsigned_abs()
888 ));
889 Ok(bytes)
890}
891
892#[inline]
894fn fmt_unix_timestamp_nanosecond(
895 output: &mut (impl io::Write + ?Sized),
896 timestamp_nanos: i128,
897 modifier::UnixTimestampNanosecond { sign_is_mandatory }: modifier::UnixTimestampNanosecond,
898) -> Result<usize, io::Error> {
899 let mut bytes = 0;
900 bytes += try_likely_ok!(fmt_sign(output, timestamp_nanos < 0, sign_is_mandatory));
901 bytes += try_likely_ok!(format_u128_pad_none(output, timestamp_nanos.unsigned_abs()));
902 Ok(bytes)
903}