1use std::io;
4
5use crate::convert::*;
6use crate::error;
7use crate::format_description::well_known::Iso8601;
8use crate::format_description::well_known::iso8601::{
9 DateKind, EncodedConfig, OffsetPrecision, TimePrecision,
10};
11use crate::formatting::{
12 ComponentProvider, format_float, format_number_pad_zero, write, write_if, write_if_else,
13};
14
15pub(super) fn format_date<V, const CONFIG: EncodedConfig>(
17 output: &mut (impl io::Write + ?Sized),
18 value: &V,
19 state: &mut V::State,
20) -> Result<usize, error::Format>
21where
22 V: ComponentProvider,
23{
24 let mut bytes = 0;
25
26 match Iso8601::<CONFIG>::DATE_KIND {
27 DateKind::Calendar => {
28 let year = value.calendar_year(state);
29
30 if Iso8601::<CONFIG>::YEAR_IS_SIX_DIGITS {
31 bytes += write_if_else(output, year < 0, b"-", b"+")?;
32 bytes += format_number_pad_zero::<6>(output, year.unsigned_abs())?;
33 } else if !(0..=9999).contains(&year) {
34 return Err(error::Format::InvalidComponent("year"));
35 } else {
36 bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
37 }
38 bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
39 bytes += format_number_pad_zero::<2>(output, u8::from(value.month(state)))?;
40 bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
41 bytes += format_number_pad_zero::<2>(output, value.day(state))?;
42 }
43 DateKind::Week => {
44 let year = value.iso_year(state);
45
46 if Iso8601::<CONFIG>::YEAR_IS_SIX_DIGITS {
47 bytes += write_if_else(output, year < 0, b"-", b"+")?;
48 bytes += format_number_pad_zero::<6>(output, year.unsigned_abs())?;
49 } else if !(0..=9999).contains(&year) {
50 return Err(error::Format::InvalidComponent("year"));
51 } else {
52 bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
53 }
54 bytes += write_if_else(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-W", b"W")?;
55 bytes += format_number_pad_zero::<2>(output, value.iso_week_number(state))?;
56 bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
57 bytes +=
58 format_number_pad_zero::<1>(output, value.weekday(state).number_from_monday())?;
59 }
60 DateKind::Ordinal => {
61 let year = value.calendar_year(state);
62
63 if Iso8601::<CONFIG>::YEAR_IS_SIX_DIGITS {
64 bytes += write_if_else(output, year < 0, b"-", b"+")?;
65 bytes += format_number_pad_zero::<6>(output, year.unsigned_abs())?;
66 } else if !(0..=9999).contains(&year) {
67 return Err(error::Format::InvalidComponent("year"));
68 } else {
69 bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
70 }
71 bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
72 bytes += format_number_pad_zero::<3>(output, value.ordinal(state))?;
73 }
74 }
75
76 Ok(bytes)
77}
78
79#[inline]
81pub(super) fn format_time<V, const CONFIG: EncodedConfig>(
82 output: &mut (impl io::Write + ?Sized),
83 value: &V,
84 state: &mut V::State,
85) -> Result<usize, error::Format>
86where
87 V: ComponentProvider,
88{
89 let mut bytes = 0;
90
91 bytes += write_if(
93 output,
94 Iso8601::<CONFIG>::USE_SEPARATORS || Iso8601::<CONFIG>::FORMAT_DATE,
95 b"T",
96 )?;
97
98 match Iso8601::<CONFIG>::TIME_PRECISION {
99 TimePrecision::Hour { decimal_digits } => {
100 let hours = (value.hour(state) as f64)
101 + (value.minute(state) as f64) / Minute::per_t::<f64>(Hour)
102 + (value.second(state) as f64) / Second::per_t::<f64>(Hour)
103 + (value.nanosecond(state) as f64) / Nanosecond::per_t::<f64>(Hour);
104 format_float(output, hours, 2, decimal_digits)?;
105 }
106 TimePrecision::Minute { decimal_digits } => {
107 bytes += format_number_pad_zero::<2>(output, value.hour(state))?;
108 bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
109 let minutes = (value.minute(state) as f64)
110 + (value.second(state) as f64) / Second::per_t::<f64>(Minute)
111 + (value.nanosecond(state) as f64) / Nanosecond::per_t::<f64>(Minute);
112 bytes += format_float(output, minutes, 2, decimal_digits)?;
113 }
114 TimePrecision::Second { decimal_digits } => {
115 bytes += format_number_pad_zero::<2>(output, value.hour(state))?;
116 bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
117 bytes += format_number_pad_zero::<2>(output, value.minute(state))?;
118 bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
119 let seconds = (value.second(state) as f64)
120 + (value.nanosecond(state) as f64) / Nanosecond::per_t::<f64>(Second);
121 bytes += format_float(output, seconds, 2, decimal_digits)?;
122 }
123 }
124
125 Ok(bytes)
126}
127
128#[inline]
130pub(super) fn format_offset<V, const CONFIG: EncodedConfig>(
131 output: &mut (impl io::Write + ?Sized),
132 value: &V,
133 state: &mut V::State,
134) -> Result<usize, error::Format>
135where
136 V: ComponentProvider,
137{
138 if Iso8601::<CONFIG>::FORMAT_TIME && value.offset_is_utc(state) {
139 return Ok(write(output, b"Z")?);
140 }
141
142 let mut bytes = 0;
143
144 if value.offset_second(state) != 0 {
145 return Err(error::Format::InvalidComponent("offset_second"));
146 }
147 bytes += write_if_else(output, value.offset_is_negative(state), b"-", b"+")?;
148 bytes += format_number_pad_zero::<2>(output, value.offset_hour(state).unsigned_abs())?;
149
150 let minutes = value.offset_minute(state);
151
152 if Iso8601::<CONFIG>::OFFSET_PRECISION == OffsetPrecision::Hour && minutes != 0 {
153 return Err(error::Format::InvalidComponent("offset_minute"));
154 } else if Iso8601::<CONFIG>::OFFSET_PRECISION == OffsetPrecision::Minute {
155 bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
156 bytes += format_number_pad_zero::<2>(output, minutes.unsigned_abs())?;
157 }
158
159 Ok(bytes)
160}