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