1#[allow(unused_imports, reason = "MSRV of 1.87")]
4use num_conv::prelude::*;
5
6use crate::convert::*;
7use crate::error;
8use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
9use crate::format_description::well_known::iso8601::EncodedConfig;
10use crate::format_description::well_known::Iso8601;
11use crate::parsing::combinator::rfc::iso8601::{
12 day, dayk, dayo, float, hour, min, month, week, year, ExtendedKind,
13};
14use crate::parsing::combinator::{ascii_char, sign};
15use crate::parsing::{Parsed, ParsedItem};
16
17impl<const CONFIG: EncodedConfig> Iso8601<CONFIG> {
18 pub(crate) fn parse_date<'a>(
26 parsed: &'a mut Parsed,
27 extended_kind: &'a mut ExtendedKind,
28 ) -> impl FnMut(&[u8]) -> Result<&[u8], error::Parse> + 'a {
29 move |input| {
30 let ParsedItem(mut input, year) = year(input).ok_or(InvalidComponent("year"))?;
32 *extended_kind = match ascii_char::<b'-'>(input) {
33 Some(ParsedItem(new_input, ())) => {
34 input = new_input;
35 ExtendedKind::Extended
36 }
37 None => ExtendedKind::Basic, };
39
40 let parsed_month_day = (|| {
41 let ParsedItem(mut input, month) = month(input).ok_or(InvalidComponent("month"))?;
42 if extended_kind.is_extended() {
43 input = ascii_char::<b'-'>(input)
44 .ok_or(InvalidLiteral)?
45 .into_inner();
46 }
47 let ParsedItem(input, day) = day(input).ok_or(InvalidComponent("day"))?;
48 Ok(ParsedItem(input, (month, day)))
49 })();
50 let mut ret_error = match parsed_month_day {
51 Ok(ParsedItem(input, (month, day))) => {
52 *parsed = parsed
53 .with_year(year)
54 .ok_or(InvalidComponent("year"))?
55 .with_month(month)
56 .ok_or(InvalidComponent("month"))?
57 .with_day(day)
58 .ok_or(InvalidComponent("day"))?;
59 return Ok(input);
60 }
61 Err(err) => err,
62 };
63
64 if let Some(ParsedItem(input, ordinal)) = dayo(input) {
66 *parsed = parsed
67 .with_year(year)
68 .ok_or(InvalidComponent("year"))?
69 .with_ordinal(ordinal)
70 .ok_or(InvalidComponent("ordinal"))?;
71 return Ok(input);
72 }
73
74 let parsed_week_weekday = (|| {
75 let input = ascii_char::<b'W'>(input)
76 .ok_or((false, InvalidLiteral))?
77 .into_inner();
78 let ParsedItem(mut input, week) =
79 week(input).ok_or((true, InvalidComponent("week")))?;
80 if extended_kind.is_extended() {
81 input = ascii_char::<b'-'>(input)
82 .ok_or((true, InvalidLiteral))?
83 .into_inner();
84 }
85 let ParsedItem(input, weekday) =
86 dayk(input).ok_or((true, InvalidComponent("weekday")))?;
87 Ok(ParsedItem(input, (week, weekday)))
88 })();
89 match parsed_week_weekday {
90 Ok(ParsedItem(input, (week, weekday))) => {
91 *parsed = parsed
92 .with_iso_year(year)
93 .ok_or(InvalidComponent("year"))?
94 .with_iso_week_number(week)
95 .ok_or(InvalidComponent("week"))?
96 .with_weekday(weekday)
97 .ok_or(InvalidComponent("weekday"))?;
98 return Ok(input);
99 }
100 Err((false, _err)) => {}
101 Err((true, err)) => ret_error = err,
103 }
104
105 Err(ret_error.into())
106 }
107 }
108
109 pub(crate) fn parse_time<'a>(
115 parsed: &'a mut Parsed,
116 extended_kind: &'a mut ExtendedKind,
117 date_is_present: bool,
118 ) -> impl FnMut(&[u8]) -> Result<&[u8], error::Parse> + 'a {
119 move |mut input| {
120 if date_is_present {
121 input = ascii_char::<b'T'>(input)
122 .ok_or(InvalidLiteral)?
123 .into_inner();
124 }
125
126 let ParsedItem(mut input, hour) = float(input).ok_or(InvalidComponent("hour"))?;
127 match hour {
128 (hour, None) => parsed.set_hour_24(hour).ok_or(InvalidComponent("hour"))?,
129 (hour, Some(fractional_part)) => {
130 *parsed = parsed
131 .with_hour_24(hour)
132 .ok_or(InvalidComponent("hour"))?
133 .with_minute((fractional_part * Second::per_t::<f64>(Minute)) as u8)
134 .ok_or(InvalidComponent("minute"))?
135 .with_second(
136 (fractional_part * Second::per_t::<f64>(Hour)
137 % Minute::per_t::<f64>(Hour)) as u8,
138 )
139 .ok_or(InvalidComponent("second"))?
140 .with_subsecond(
141 (fractional_part * Nanosecond::per_t::<f64>(Hour)
142 % Nanosecond::per_t::<f64>(Second))
143 as u32,
144 )
145 .ok_or(InvalidComponent("subsecond"))?;
146 return Ok(input);
147 }
148 };
149
150 if let Some(ParsedItem(new_input, ())) = ascii_char::<b':'>(input) {
151 extended_kind
152 .coerce_extended()
153 .ok_or(InvalidComponent("minute"))?;
154 input = new_input;
155 };
156
157 let mut input = match float(input) {
158 Some(ParsedItem(input, (minute, None))) => {
159 extended_kind.coerce_basic();
160 parsed
161 .set_minute(minute)
162 .ok_or(InvalidComponent("minute"))?;
163 input
164 }
165 Some(ParsedItem(input, (minute, Some(fractional_part)))) => {
166 extended_kind.coerce_basic();
168 *parsed = parsed
169 .with_minute(minute)
170 .ok_or(InvalidComponent("minute"))?
171 .with_second((fractional_part * Second::per_t::<f64>(Minute)) as u8)
172 .ok_or(InvalidComponent("second"))?
173 .with_subsecond(
174 (fractional_part * Nanosecond::per_t::<f64>(Minute)
175 % Nanosecond::per_t::<f64>(Second))
176 as u32,
177 )
178 .ok_or(InvalidComponent("subsecond"))?;
179 return Ok(input);
180 }
181 None if extended_kind.is_extended() => {
183 return Err(error::Parse::ParseFromDescription(InvalidComponent(
184 "minute",
185 )));
186 }
187 None => {
188 *parsed = parsed
190 .with_minute(0)
191 .ok_or(InvalidComponent("minute"))?
192 .with_second(0)
193 .ok_or(InvalidComponent("second"))?
194 .with_subsecond(0)
195 .ok_or(InvalidComponent("subsecond"))?;
196 return Ok(input);
197 }
198 };
199
200 if extended_kind.is_extended() {
201 match ascii_char::<b':'>(input) {
202 Some(ParsedItem(new_input, ())) => input = new_input,
203 None => {
204 *parsed = parsed
205 .with_second(0)
206 .ok_or(InvalidComponent("second"))?
207 .with_subsecond(0)
208 .ok_or(InvalidComponent("subsecond"))?;
209 return Ok(input);
210 }
211 }
212 }
213
214 let (input, second, subsecond) = match float(input) {
215 Some(ParsedItem(input, (second, None))) => (input, second, 0),
216 Some(ParsedItem(input, (second, Some(fractional_part)))) => (
217 input,
218 second,
219 round(fractional_part * Nanosecond::per_t::<f64>(Second)) as u32,
220 ),
221 None if extended_kind.is_extended() => {
222 return Err(error::Parse::ParseFromDescription(InvalidComponent(
223 "second",
224 )));
225 }
226 None => (input, 0, 0),
228 };
229 *parsed = parsed
230 .with_second(second)
231 .ok_or(InvalidComponent("second"))?
232 .with_subsecond(subsecond)
233 .ok_or(InvalidComponent("subsecond"))?;
234
235 Ok(input)
236 }
237 }
238
239 pub(crate) fn parse_offset<'a>(
244 parsed: &'a mut Parsed,
245 extended_kind: &'a mut ExtendedKind,
246 ) -> impl FnMut(&[u8]) -> Result<&[u8], error::Parse> + 'a {
247 move |input| {
248 if let Some(ParsedItem(input, ())) = ascii_char::<b'Z'>(input) {
249 *parsed = parsed
250 .with_offset_hour(0)
251 .ok_or(InvalidComponent("offset hour"))?
252 .with_offset_minute_signed(0)
253 .ok_or(InvalidComponent("offset minute"))?
254 .with_offset_second_signed(0)
255 .ok_or(InvalidComponent("offset second"))?;
256 return Ok(input);
257 }
258
259 let ParsedItem(input, sign) = sign(input).ok_or(InvalidComponent("offset hour"))?;
260 let mut input = hour(input)
261 .and_then(|parsed_item| {
262 parsed_item.consume_value(|hour| {
263 parsed.set_offset_hour(if sign == b'-' {
264 -hour.cast_signed()
265 } else {
266 hour.cast_signed()
267 })
268 })
269 })
270 .ok_or(InvalidComponent("offset hour"))?;
271
272 if extended_kind.maybe_extended() {
273 if let Some(ParsedItem(new_input, ())) = ascii_char::<b':'>(input) {
274 extended_kind
275 .coerce_extended()
276 .ok_or(InvalidComponent("offset minute"))?;
277 input = new_input;
278 };
279 }
280
281 match min(input) {
282 Some(ParsedItem(new_input, min)) => {
283 input = new_input;
284 parsed
285 .set_offset_minute_signed(if sign == b'-' {
286 -min.cast_signed()
287 } else {
288 min.cast_signed()
289 })
290 .ok_or(InvalidComponent("offset minute"))?;
291 }
292 None => {
293 parsed.set_offset_minute_signed(0);
295 }
296 }
297
298 extended_kind.coerce_basic();
303
304 Ok(input)
305 }
306 }
307}
308
309#[inline]
312fn round(value: f64) -> f64 {
313 #[cfg(feature = "std")]
314 {
315 value.round()
316 }
317 #[cfg(not(feature = "std"))]
318 {
319 debug_assert!(value.is_sign_positive() && !value.is_nan());
320
321 let f = value % 1.;
322 if f < 0.5 {
323 value - f
324 } else {
325 value - f + 1.
326 }
327 }
328}