/rust/registry/src/index.crates.io-1949cf8c6b5b557f/time-0.3.45/src/parsing/parsed.rs
Line | Count | Source |
1 | | //! Information parsed from an input and format description. |
2 | | |
3 | | use core::num::NonZero; |
4 | | |
5 | | use deranged::{ |
6 | | OptionRangedI128, OptionRangedI16, OptionRangedI32, OptionRangedI8, OptionRangedU16, |
7 | | OptionRangedU32, OptionRangedU8, RangedI128, RangedI16, RangedI32, RangedI8, RangedU16, |
8 | | RangedU32, RangedU8, |
9 | | }; |
10 | | use num_conv::prelude::*; |
11 | | |
12 | | use crate::convert::{Day, Hour, Minute, Nanosecond, Second}; |
13 | | use crate::date::{MAX_YEAR, MIN_YEAR}; |
14 | | use crate::error::TryFromParsed::InsufficientInformation; |
15 | | #[cfg(feature = "alloc")] |
16 | | use crate::format_description::OwnedFormatItem; |
17 | | use crate::format_description::{modifier, BorrowedFormatItem, Component}; |
18 | | use crate::internal_macros::{bug, const_try_opt}; |
19 | | use crate::parsing::component::{ |
20 | | parse_day, parse_end, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour, |
21 | | parse_offset_minute, parse_offset_second, parse_ordinal, parse_period, parse_second, |
22 | | parse_subsecond, parse_unix_timestamp, parse_week_number, parse_weekday, parse_year, Period, |
23 | | }; |
24 | | use crate::parsing::ParsedItem; |
25 | | use crate::{ |
26 | | error, Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday, |
27 | | }; |
28 | | |
29 | | /// Sealed to prevent downstream implementations. |
30 | | mod sealed { |
31 | | use super::*; |
32 | | |
33 | | /// A trait to allow `parse_item` to be generic. |
34 | | pub trait AnyFormatItem { |
35 | | /// Parse a single item, returning the remaining input on success. |
36 | | fn parse_item<'a>( |
37 | | &self, |
38 | | parsed: &mut Parsed, |
39 | | input: &'a [u8], |
40 | | ) -> Result<&'a [u8], error::ParseFromDescription>; |
41 | | } |
42 | | } |
43 | | |
44 | | impl sealed::AnyFormatItem for BorrowedFormatItem<'_> { |
45 | | #[inline] |
46 | 0 | fn parse_item<'a>( |
47 | 0 | &self, |
48 | 0 | parsed: &mut Parsed, |
49 | 0 | input: &'a [u8], |
50 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
51 | 0 | match self { |
52 | 0 | Self::Literal(literal) => Parsed::parse_literal(input, literal), |
53 | 0 | Self::Component(component) => parsed.parse_component(input, *component), |
54 | 0 | Self::Compound(compound) => parsed.parse_items(input, compound), |
55 | 0 | Self::Optional(item) => parsed.parse_item(input, *item).or(Ok(input)), |
56 | 0 | Self::First(items) => { |
57 | 0 | let mut first_err = None; |
58 | | |
59 | 0 | for item in items.iter() { |
60 | 0 | match parsed.parse_item(input, item) { |
61 | 0 | Ok(remaining_input) => return Ok(remaining_input), |
62 | 0 | Err(err) if first_err.is_none() => first_err = Some(err), |
63 | 0 | Err(_) => {} |
64 | | } |
65 | | } |
66 | | |
67 | 0 | match first_err { |
68 | 0 | Some(err) => Err(err), |
69 | | // This location will be reached if the slice is empty, skipping the `for` loop. |
70 | | // As this case is expected to be uncommon, there's no need to check up front. |
71 | 0 | None => Ok(input), |
72 | | } |
73 | | } |
74 | | } |
75 | 0 | } |
76 | | } |
77 | | |
78 | | #[cfg(feature = "alloc")] |
79 | | impl sealed::AnyFormatItem for OwnedFormatItem { |
80 | | #[inline] |
81 | 0 | fn parse_item<'a>( |
82 | 0 | &self, |
83 | 0 | parsed: &mut Parsed, |
84 | 0 | input: &'a [u8], |
85 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
86 | 0 | match self { |
87 | 0 | Self::Literal(literal) => Parsed::parse_literal(input, literal), |
88 | 0 | Self::Component(component) => parsed.parse_component(input, *component), |
89 | 0 | Self::Compound(compound) => parsed.parse_items(input, compound), |
90 | 0 | Self::Optional(item) => parsed.parse_item(input, item.as_ref()).or(Ok(input)), |
91 | 0 | Self::First(items) => { |
92 | 0 | let mut first_err = None; |
93 | | |
94 | 0 | for item in items.iter() { |
95 | 0 | match parsed.parse_item(input, item) { |
96 | 0 | Ok(remaining_input) => return Ok(remaining_input), |
97 | 0 | Err(err) if first_err.is_none() => first_err = Some(err), |
98 | 0 | Err(_) => {} |
99 | | } |
100 | | } |
101 | | |
102 | 0 | match first_err { |
103 | 0 | Some(err) => Err(err), |
104 | | // This location will be reached if the slice is empty, skipping the `for` loop. |
105 | | // As this case is expected to be uncommon, there's no need to check up front. |
106 | 0 | None => Ok(input), |
107 | | } |
108 | | } |
109 | | } |
110 | 0 | } |
111 | | } |
112 | | |
113 | | /// All information parsed. |
114 | | /// |
115 | | /// This information is directly used to construct the final values. |
116 | | /// |
117 | | /// Most users will not need think about this struct in any way. It is public to allow for manual |
118 | | /// control over values, in the instance that the default parser is insufficient. |
119 | | #[derive(Debug, Clone, Copy)] |
120 | | pub struct Parsed { |
121 | | /// Calendar year. |
122 | | year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>, |
123 | | /// All digits except the last two of the calendar year. |
124 | | year_century: OptionRangedI16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>, |
125 | | /// The last two digits of the calendar year. |
126 | | year_last_two: OptionRangedU8<0, 99>, |
127 | | /// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date). |
128 | | iso_year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>, |
129 | | /// All digits except the last two of the ISO week year. |
130 | | iso_year_century: OptionRangedI16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>, |
131 | | /// The last two digits of the ISO week year. |
132 | | iso_year_last_two: OptionRangedU8<0, 99>, |
133 | | /// Month of the year. |
134 | | month: Option<Month>, |
135 | | /// Week of the year, where week one begins on the first Sunday of the calendar year. |
136 | | sunday_week_number: OptionRangedU8<0, 53>, |
137 | | /// Week of the year, where week one begins on the first Monday of the calendar year. |
138 | | monday_week_number: OptionRangedU8<0, 53>, |
139 | | /// Week of the year, where week one is the Monday-to-Sunday period containing January 4. |
140 | | iso_week_number: OptionRangedU8<1, 53>, |
141 | | /// Day of the week. |
142 | | weekday: Option<Weekday>, |
143 | | /// Day of the year. |
144 | | ordinal: OptionRangedU16<1, 366>, |
145 | | /// Day of the month. |
146 | | day: OptionRangedU8<1, 31>, |
147 | | /// Hour within the day. |
148 | | hour_24: OptionRangedU8<0, { Hour::per_t::<u8>(Day) - 1 }>, |
149 | | /// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in |
150 | | /// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field. |
151 | | hour_12: OptionRangedU8<1, 12>, |
152 | | /// Whether the `hour_12` field indicates a time that "PM". |
153 | | hour_12_is_pm: Option<bool>, |
154 | | /// Minute within the hour. |
155 | | minute: OptionRangedU8<0, { Minute::per_t::<u8>(Hour) - 1 }>, |
156 | | /// Second within the minute. |
157 | | // do not subtract one, as leap seconds may be allowed |
158 | | second: OptionRangedU8<0, { Second::per_t::<u8>(Minute) }>, |
159 | | /// Nanosecond within the second. |
160 | | subsecond: OptionRangedU32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>, |
161 | | /// Whole hours of the UTC offset. |
162 | | offset_hour: OptionRangedI8<-23, 23>, |
163 | | /// Minutes within the hour of the UTC offset. |
164 | | offset_minute: |
165 | | OptionRangedI8<{ -Minute::per_t::<i8>(Hour) + 1 }, { Minute::per_t::<i8>(Hour) - 1 }>, |
166 | | /// Seconds within the minute of the UTC offset. |
167 | | offset_second: |
168 | | OptionRangedI8<{ -Second::per_t::<i8>(Minute) + 1 }, { Second::per_t::<i8>(Minute) - 1 }>, |
169 | | /// The Unix timestamp in nanoseconds. |
170 | | unix_timestamp_nanos: OptionRangedI128< |
171 | | { |
172 | | OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC) |
173 | | .unix_timestamp_nanos() |
174 | | }, |
175 | | { |
176 | | OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC) |
177 | | .unix_timestamp_nanos() |
178 | | }, |
179 | | >, |
180 | | /// Indicates whether the [`UtcOffset`] is negative. This information is obtained when parsing |
181 | | /// the offset hour, but may not otherwise be stored due to "-0" being equivalent to "0". |
182 | | offset_is_negative: bool, |
183 | | /// Indicates whether the `year_century` component is negative. This information is obtained |
184 | | /// when parsing, but may not otherwise be stored due to "-0" being equivalent to "0". |
185 | | year_century_is_negative: bool, |
186 | | /// Indicates whether the `iso_year_century` component is negative. This information is |
187 | | /// obtained when parsing, but may not otherwise be stored due to "-0" being equivalent to "0". |
188 | | iso_year_century_is_negative: bool, |
189 | | /// Indicates whether a leap second is permitted to be parsed. This is required by some |
190 | | /// well-known formats. |
191 | | pub(super) leap_second_allowed: bool, |
192 | | } |
193 | | |
194 | | impl Default for Parsed { |
195 | | #[inline] |
196 | 0 | fn default() -> Self { |
197 | 0 | Self::new() |
198 | 0 | } |
199 | | } |
200 | | |
201 | | impl Parsed { |
202 | | /// Create a new instance of `Parsed` with no information known. |
203 | | #[inline] |
204 | 0 | pub const fn new() -> Self { |
205 | 0 | Self { |
206 | 0 | year: OptionRangedI32::None, |
207 | 0 | year_century: OptionRangedI16::None, |
208 | 0 | year_last_two: OptionRangedU8::None, |
209 | 0 | iso_year: OptionRangedI32::None, |
210 | 0 | iso_year_century: OptionRangedI16::None, |
211 | 0 | iso_year_last_two: OptionRangedU8::None, |
212 | 0 | month: None, |
213 | 0 | sunday_week_number: OptionRangedU8::None, |
214 | 0 | monday_week_number: OptionRangedU8::None, |
215 | 0 | iso_week_number: OptionRangedU8::None, |
216 | 0 | weekday: None, |
217 | 0 | ordinal: OptionRangedU16::None, |
218 | 0 | day: OptionRangedU8::None, |
219 | 0 | hour_24: OptionRangedU8::None, |
220 | 0 | hour_12: OptionRangedU8::None, |
221 | 0 | hour_12_is_pm: None, |
222 | 0 | minute: OptionRangedU8::None, |
223 | 0 | second: OptionRangedU8::None, |
224 | 0 | subsecond: OptionRangedU32::None, |
225 | 0 | offset_hour: OptionRangedI8::None, |
226 | 0 | offset_minute: OptionRangedI8::None, |
227 | 0 | offset_second: OptionRangedI8::None, |
228 | 0 | unix_timestamp_nanos: OptionRangedI128::None, |
229 | 0 | offset_is_negative: false, |
230 | 0 | year_century_is_negative: false, |
231 | 0 | iso_year_century_is_negative: false, |
232 | 0 | leap_second_allowed: false, |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | | /// Parse a single [`BorrowedFormatItem`] or [`OwnedFormatItem`], mutating the struct. The |
237 | | /// remaining input is returned as the `Ok` value. |
238 | | /// |
239 | | /// If a [`BorrowedFormatItem::Optional`] or [`OwnedFormatItem::Optional`] is passed, parsing |
240 | | /// will not fail; the input will be returned as-is if the expected format is not present. |
241 | | #[inline] |
242 | 0 | pub fn parse_item<'a>( |
243 | 0 | &mut self, |
244 | 0 | input: &'a [u8], |
245 | 0 | item: &impl sealed::AnyFormatItem, |
246 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
247 | 0 | item.parse_item(self, input) |
248 | 0 | } |
249 | | |
250 | | /// Parse a sequence of [`BorrowedFormatItem`]s or [`OwnedFormatItem`]s, mutating the struct. |
251 | | /// The remaining input is returned as the `Ok` value. |
252 | | /// |
253 | | /// This method will fail if any of the contained [`BorrowedFormatItem`]s or |
254 | | /// [`OwnedFormatItem`]s fail to parse. `self` will not be mutated in this instance. |
255 | | #[inline] |
256 | 0 | pub fn parse_items<'a>( |
257 | 0 | &mut self, |
258 | 0 | mut input: &'a [u8], |
259 | 0 | items: &[impl sealed::AnyFormatItem], |
260 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
261 | | // Make a copy that we can mutate. It will only be set to the user's copy if everything |
262 | | // succeeds. |
263 | 0 | let mut this = *self; |
264 | 0 | for item in items { |
265 | 0 | input = this.parse_item(input, item)?; |
266 | | } |
267 | 0 | *self = this; |
268 | 0 | Ok(input) |
269 | 0 | } |
270 | | |
271 | | /// Parse a literal byte sequence. The remaining input is returned as the `Ok` value. |
272 | | #[inline] |
273 | 0 | pub fn parse_literal<'a>( |
274 | 0 | input: &'a [u8], |
275 | 0 | literal: &[u8], |
276 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
277 | 0 | input |
278 | 0 | .strip_prefix(literal) |
279 | 0 | .ok_or(error::ParseFromDescription::InvalidLiteral) |
280 | 0 | } |
281 | | |
282 | | /// Parse a single component, mutating the struct. The remaining input is returned as the `Ok` |
283 | | /// value. |
284 | 0 | pub fn parse_component<'a>( |
285 | 0 | &mut self, |
286 | 0 | input: &'a [u8], |
287 | 0 | component: Component, |
288 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
289 | | use error::ParseFromDescription::InvalidComponent; |
290 | | |
291 | 0 | match component { |
292 | 0 | Component::Day(modifiers) => parse_day(input, modifiers) |
293 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_day(value))) |
294 | 0 | .ok_or(InvalidComponent("day")), |
295 | 0 | Component::Month(modifiers) => parse_month(input, modifiers) |
296 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_month(value))) |
297 | 0 | .ok_or(InvalidComponent("month")), |
298 | 0 | Component::Ordinal(modifiers) => parse_ordinal(input, modifiers) |
299 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value))) |
300 | 0 | .ok_or(InvalidComponent("ordinal")), |
301 | 0 | Component::Weekday(modifiers) => parse_weekday(input, modifiers) |
302 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value))) |
303 | 0 | .ok_or(InvalidComponent("weekday")), |
304 | 0 | Component::WeekNumber(modifiers) => { |
305 | 0 | let ParsedItem(remaining, value) = |
306 | 0 | parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?; |
307 | 0 | match modifiers.repr { |
308 | | modifier::WeekNumberRepr::Iso => { |
309 | 0 | NonZero::new(value).and_then(|value| self.set_iso_week_number(value)) |
310 | | } |
311 | 0 | modifier::WeekNumberRepr::Sunday => self.set_sunday_week_number(value), |
312 | 0 | modifier::WeekNumberRepr::Monday => self.set_monday_week_number(value), |
313 | | } |
314 | 0 | .ok_or(InvalidComponent("week number"))?; |
315 | 0 | Ok(remaining) |
316 | | } |
317 | 0 | Component::Year(modifiers) => { |
318 | 0 | let ParsedItem(remaining, (value, is_negative)) = |
319 | 0 | parse_year(input, modifiers).ok_or(InvalidComponent("year"))?; |
320 | 0 | match (modifiers.iso_week_based, modifiers.repr) { |
321 | 0 | (false, modifier::YearRepr::Full) => self.set_year(value), |
322 | | (false, modifier::YearRepr::Century) => { |
323 | 0 | self.set_year_century(value.truncate(), is_negative) |
324 | | } |
325 | | (false, modifier::YearRepr::LastTwo) => { |
326 | 0 | self.set_year_last_two(value.cast_unsigned().truncate()) |
327 | | } |
328 | 0 | (true, modifier::YearRepr::Full) => self.set_iso_year(value), |
329 | | (true, modifier::YearRepr::Century) => { |
330 | 0 | self.set_iso_year_century(value.truncate(), is_negative) |
331 | | } |
332 | | (true, modifier::YearRepr::LastTwo) => { |
333 | 0 | self.set_iso_year_last_two(value.cast_unsigned().truncate()) |
334 | | } |
335 | | } |
336 | 0 | .ok_or(InvalidComponent("year"))?; |
337 | 0 | Ok(remaining) |
338 | | } |
339 | 0 | Component::Hour(modifiers) => { |
340 | 0 | let ParsedItem(remaining, value) = |
341 | 0 | parse_hour(input, modifiers).ok_or(InvalidComponent("hour"))?; |
342 | 0 | if modifiers.is_12_hour_clock { |
343 | 0 | NonZero::new(value).and_then(|value| self.set_hour_12(value)) |
344 | | } else { |
345 | 0 | self.set_hour_24(value) |
346 | | } |
347 | 0 | .ok_or(InvalidComponent("hour"))?; |
348 | 0 | Ok(remaining) |
349 | | } |
350 | 0 | Component::Minute(modifiers) => parse_minute(input, modifiers) |
351 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value))) |
352 | 0 | .ok_or(InvalidComponent("minute")), |
353 | 0 | Component::Period(modifiers) => parse_period(input, modifiers) |
354 | 0 | .and_then(|parsed| { |
355 | 0 | parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm)) |
356 | 0 | }) |
357 | 0 | .ok_or(InvalidComponent("period")), |
358 | 0 | Component::Second(modifiers) => parse_second(input, modifiers) |
359 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_second(value))) |
360 | 0 | .ok_or(InvalidComponent("second")), |
361 | 0 | Component::Subsecond(modifiers) => parse_subsecond(input, modifiers) |
362 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value))) |
363 | 0 | .ok_or(InvalidComponent("subsecond")), |
364 | 0 | Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers) |
365 | 0 | .and_then(|parsed| { |
366 | 0 | parsed.consume_value(|(value, is_negative)| { |
367 | 0 | self.set_offset_hour(value)?; |
368 | 0 | self.offset_is_negative = is_negative; |
369 | 0 | Some(()) |
370 | 0 | }) |
371 | 0 | }) |
372 | 0 | .ok_or(InvalidComponent("offset hour")), |
373 | 0 | Component::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers) |
374 | 0 | .and_then(|parsed| { |
375 | 0 | parsed.consume_value(|value| self.set_offset_minute_signed(value)) |
376 | 0 | }) |
377 | 0 | .ok_or(InvalidComponent("offset minute")), |
378 | 0 | Component::OffsetSecond(modifiers) => parse_offset_second(input, modifiers) |
379 | 0 | .and_then(|parsed| { |
380 | 0 | parsed.consume_value(|value| self.set_offset_second_signed(value)) |
381 | 0 | }) |
382 | 0 | .ok_or(InvalidComponent("offset second")), |
383 | 0 | Component::Ignore(modifiers) => parse_ignore(input, modifiers) |
384 | 0 | .map(ParsedItem::<()>::into_inner) |
385 | 0 | .ok_or(InvalidComponent("ignore")), |
386 | 0 | Component::UnixTimestamp(modifiers) => parse_unix_timestamp(input, modifiers) |
387 | 0 | .and_then(|parsed| { |
388 | 0 | parsed.consume_value(|value| self.set_unix_timestamp_nanos(value)) |
389 | 0 | }) |
390 | 0 | .ok_or(InvalidComponent("unix_timestamp")), |
391 | 0 | Component::End(modifiers) => parse_end(input, modifiers) |
392 | 0 | .map(ParsedItem::<()>::into_inner) |
393 | 0 | .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters), |
394 | | } |
395 | 0 | } |
396 | | } |
397 | | |
398 | | /// Getter methods |
399 | | impl Parsed { |
400 | | /// Obtain the `year` component. |
401 | | #[inline] |
402 | 0 | pub const fn year(&self) -> Option<i32> { |
403 | 0 | self.year.get_primitive() |
404 | 0 | } |
405 | | |
406 | | /// Obtain the `year_century` component. |
407 | | /// |
408 | | /// If the year is zero, the sign of the century is not stored. To differentiate between |
409 | | /// positive and negative zero, use `year_century_is_negative`. |
410 | | #[inline] |
411 | 0 | pub const fn year_century(&self) -> Option<i16> { |
412 | 0 | self.year_century.get_primitive() |
413 | 0 | } |
414 | | |
415 | | /// Obtain the `year_century_is_negative` component. |
416 | | /// |
417 | | /// This indicates whether the value returned from `year_century` is negative. If the year is |
418 | | /// zero, it is necessary to call this method for disambiguation. |
419 | | #[inline] |
420 | 0 | pub const fn year_century_is_negative(&self) -> Option<bool> { |
421 | 0 | match self.year_century() { |
422 | 0 | Some(_) => Some(self.year_century_is_negative), |
423 | 0 | None => None, |
424 | | } |
425 | 0 | } |
426 | | |
427 | | /// Obtain the `year_last_two` component. |
428 | | #[inline] |
429 | 0 | pub const fn year_last_two(&self) -> Option<u8> { |
430 | 0 | self.year_last_two.get_primitive() |
431 | 0 | } |
432 | | |
433 | | /// Obtain the `iso_year` component. |
434 | | #[inline] |
435 | 0 | pub const fn iso_year(&self) -> Option<i32> { |
436 | 0 | self.iso_year.get_primitive() |
437 | 0 | } |
438 | | |
439 | | /// Obtain the `iso_year_century` component. |
440 | | /// |
441 | | /// If the year is zero, the sign of the century is not stored. To differentiate between |
442 | | /// positive and negative zero, use `iso_year_century_is_negative`. |
443 | | #[inline] |
444 | 0 | pub const fn iso_year_century(&self) -> Option<i16> { |
445 | 0 | self.iso_year_century.get_primitive() |
446 | 0 | } |
447 | | |
448 | | /// Obtain the `iso_year_century_is_negative` component. |
449 | | /// |
450 | | /// This indicates whether the value returned from `iso_year_century` is negative. If the year |
451 | | /// is zero, it is necessary to call this method for disambiguation. |
452 | | #[inline] |
453 | 0 | pub const fn iso_year_century_is_negative(&self) -> Option<bool> { |
454 | 0 | match self.iso_year_century() { |
455 | 0 | Some(_) => Some(self.iso_year_century_is_negative), |
456 | 0 | None => None, |
457 | | } |
458 | 0 | } |
459 | | |
460 | | /// Obtain the `iso_year_last_two` component. |
461 | | #[inline] |
462 | 0 | pub const fn iso_year_last_two(&self) -> Option<u8> { |
463 | 0 | self.iso_year_last_two.get_primitive() |
464 | 0 | } |
465 | | |
466 | | /// Obtain the `month` component. |
467 | | #[inline] |
468 | 0 | pub const fn month(&self) -> Option<Month> { |
469 | 0 | self.month |
470 | 0 | } |
471 | | |
472 | | /// Obtain the `sunday_week_number` component. |
473 | | #[inline] |
474 | 0 | pub const fn sunday_week_number(&self) -> Option<u8> { |
475 | 0 | self.sunday_week_number.get_primitive() |
476 | 0 | } |
477 | | |
478 | | /// Obtain the `monday_week_number` component. |
479 | | #[inline] |
480 | 0 | pub const fn monday_week_number(&self) -> Option<u8> { |
481 | 0 | self.monday_week_number.get_primitive() |
482 | 0 | } |
483 | | |
484 | | /// Obtain the `iso_week_number` component. |
485 | | #[inline] |
486 | 0 | pub const fn iso_week_number(&self) -> Option<NonZero<u8>> { |
487 | 0 | NonZero::new(const_try_opt!(self.iso_week_number.get_primitive())) |
488 | 0 | } |
489 | | |
490 | | /// Obtain the `weekday` component. |
491 | | #[inline] |
492 | 0 | pub const fn weekday(&self) -> Option<Weekday> { |
493 | 0 | self.weekday |
494 | 0 | } |
495 | | |
496 | | /// Obtain the `ordinal` component. |
497 | | #[inline] |
498 | 0 | pub const fn ordinal(&self) -> Option<NonZero<u16>> { |
499 | 0 | NonZero::new(const_try_opt!(self.ordinal.get_primitive())) |
500 | 0 | } |
501 | | |
502 | | /// Obtain the `day` component. |
503 | | #[inline] |
504 | 0 | pub const fn day(&self) -> Option<NonZero<u8>> { |
505 | 0 | NonZero::new(const_try_opt!(self.day.get_primitive())) |
506 | 0 | } |
507 | | |
508 | | /// Obtain the `hour_24` component. |
509 | | #[inline] |
510 | 0 | pub const fn hour_24(&self) -> Option<u8> { |
511 | 0 | self.hour_24.get_primitive() |
512 | 0 | } |
513 | | |
514 | | /// Obtain the `hour_12` component. |
515 | | #[inline] |
516 | 0 | pub const fn hour_12(&self) -> Option<NonZero<u8>> { |
517 | 0 | NonZero::new(const_try_opt!(self.hour_12.get_primitive())) |
518 | 0 | } |
519 | | |
520 | | /// Obtain the `hour_12_is_pm` component. |
521 | | #[inline] |
522 | 0 | pub const fn hour_12_is_pm(&self) -> Option<bool> { |
523 | 0 | self.hour_12_is_pm |
524 | 0 | } |
525 | | |
526 | | /// Obtain the `minute` component. |
527 | | #[inline] |
528 | 0 | pub const fn minute(&self) -> Option<u8> { |
529 | 0 | self.minute.get_primitive() |
530 | 0 | } |
531 | | |
532 | | /// Obtain the `second` component. |
533 | | #[inline] |
534 | 0 | pub const fn second(&self) -> Option<u8> { |
535 | 0 | self.second.get_primitive() |
536 | 0 | } |
537 | | |
538 | | /// Obtain the `subsecond` component. |
539 | | #[inline] |
540 | 0 | pub const fn subsecond(&self) -> Option<u32> { |
541 | 0 | self.subsecond.get_primitive() |
542 | 0 | } |
543 | | |
544 | | /// Obtain the `offset_hour` component. |
545 | | #[inline] |
546 | 0 | pub const fn offset_hour(&self) -> Option<i8> { |
547 | 0 | self.offset_hour.get_primitive() |
548 | 0 | } |
549 | | |
550 | | /// Obtain the absolute value of the `offset_minute` component. |
551 | | #[doc(hidden)] |
552 | | #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")] |
553 | | #[inline] |
554 | 0 | pub const fn offset_minute(&self) -> Option<u8> { |
555 | 0 | Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs()) |
556 | 0 | } |
557 | | |
558 | | /// Obtain the `offset_minute` component. |
559 | | #[inline] |
560 | 0 | pub const fn offset_minute_signed(&self) -> Option<i8> { |
561 | 0 | match (self.offset_minute.get_primitive(), self.offset_is_negative) { |
562 | 0 | (Some(offset_minute), true) => Some(-offset_minute), |
563 | 0 | (Some(offset_minute), _) => Some(offset_minute), |
564 | 0 | (None, _) => None, |
565 | | } |
566 | 0 | } |
567 | | |
568 | | /// Obtain the absolute value of the `offset_second` component. |
569 | | #[doc(hidden)] |
570 | | #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")] |
571 | | #[inline] |
572 | 0 | pub const fn offset_second(&self) -> Option<u8> { |
573 | 0 | Some(const_try_opt!(self.offset_second_signed()).unsigned_abs()) |
574 | 0 | } |
575 | | |
576 | | /// Obtain the `offset_second` component. |
577 | | #[inline] |
578 | 0 | pub const fn offset_second_signed(&self) -> Option<i8> { |
579 | 0 | match (self.offset_second.get_primitive(), self.offset_is_negative) { |
580 | 0 | (Some(offset_second), true) => Some(-offset_second), |
581 | 0 | (Some(offset_second), _) => Some(offset_second), |
582 | 0 | (None, _) => None, |
583 | | } |
584 | 0 | } |
585 | | |
586 | | /// Obtain the `unix_timestamp_nanos` component. |
587 | | #[inline] |
588 | 0 | pub const fn unix_timestamp_nanos(&self) -> Option<i128> { |
589 | 0 | self.unix_timestamp_nanos.get_primitive() |
590 | 0 | } |
591 | | } |
592 | | |
593 | | /// Generate setters based on the builders. |
594 | | macro_rules! setters { |
595 | | ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$( |
596 | | #[doc = concat!("Set the `", stringify!($name), "` component.")] |
597 | | #[inline] |
598 | 0 | pub const fn $setter(&mut self, value: $type) -> Option<()> { |
599 | 0 | match self.$builder(value) { |
600 | 0 | Some(value) => { |
601 | 0 | *self = value; |
602 | 0 | Some(()) |
603 | | }, |
604 | 0 | None => None, |
605 | | } |
606 | 0 | } Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_minute Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_second Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_hour_12 Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_hour_24 Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_ordinal Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_weekday Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_iso_year Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_subsecond Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_offset_hour Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_hour_12_is_pm Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_year_last_two Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_iso_week_number Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_iso_year_last_two Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_monday_week_number Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_sunday_week_number Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_offset_minute_signed Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_offset_second_signed Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_unix_timestamp_nanos Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_day Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_year Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_month |
607 | | )*}; |
608 | | } |
609 | | |
610 | | /// Setter methods |
611 | | /// |
612 | | /// All setters return `Option<()>`, which is `Some` if the value was set, and `None` if not. The |
613 | | /// setters _may_ fail if the value is invalid, though behavior is not guaranteed. |
614 | | impl Parsed { |
615 | | setters! { |
616 | | year set_year with_year i32; |
617 | | } |
618 | | |
619 | | /// Set the `year_century` component. |
620 | | /// |
621 | | /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise |
622 | | /// the sign is inferred from the value. |
623 | | #[inline] |
624 | 0 | pub const fn set_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> { |
625 | 0 | self.year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value))); |
626 | 0 | if value != 0 { |
627 | 0 | self.year_century_is_negative = value.is_negative(); |
628 | 0 | } else { |
629 | 0 | self.year_century_is_negative = is_negative; |
630 | 0 | } |
631 | 0 | Some(()) |
632 | 0 | } |
633 | | |
634 | | setters! { |
635 | | year_last_two set_year_last_two with_year_last_two u8; |
636 | | iso_year set_iso_year with_iso_year i32; |
637 | | iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8; |
638 | | } |
639 | | |
640 | | /// Set the `iso_year_century` component. |
641 | | /// |
642 | | /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise |
643 | | /// the sign is inferred from the value. |
644 | | #[inline] |
645 | 0 | pub const fn set_iso_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> { |
646 | 0 | self.iso_year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value))); |
647 | 0 | if value != 0 { |
648 | 0 | self.iso_year_century_is_negative = value.is_negative(); |
649 | 0 | } else { |
650 | 0 | self.iso_year_century_is_negative = is_negative; |
651 | 0 | } |
652 | 0 | Some(()) |
653 | 0 | } |
654 | | |
655 | | setters! { |
656 | | month set_month with_month Month; |
657 | | sunday_week_number set_sunday_week_number with_sunday_week_number u8; |
658 | | monday_week_number set_monday_week_number with_monday_week_number u8; |
659 | | iso_week_number set_iso_week_number with_iso_week_number NonZero<u8>; |
660 | | weekday set_weekday with_weekday Weekday; |
661 | | ordinal set_ordinal with_ordinal NonZero<u16>; |
662 | | day set_day with_day NonZero<u8>; |
663 | | hour_24 set_hour_24 with_hour_24 u8; |
664 | | hour_12 set_hour_12 with_hour_12 NonZero<u8>; |
665 | | hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool; |
666 | | minute set_minute with_minute u8; |
667 | | second set_second with_second u8; |
668 | | subsecond set_subsecond with_subsecond u32; |
669 | | offset_hour set_offset_hour with_offset_hour i8; |
670 | | offset_minute set_offset_minute_signed with_offset_minute_signed i8; |
671 | | offset_second set_offset_second_signed with_offset_second_signed i8; |
672 | | unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128; |
673 | | } |
674 | | |
675 | | /// Set the `offset_minute` component. |
676 | | #[doc(hidden)] |
677 | | #[deprecated( |
678 | | since = "0.3.8", |
679 | | note = "use `parsed.set_offset_minute_signed()` instead" |
680 | | )] |
681 | | #[inline] |
682 | 0 | pub const fn set_offset_minute(&mut self, value: u8) -> Option<()> { |
683 | 0 | if value > i8::MAX as u8 { |
684 | 0 | None |
685 | | } else { |
686 | 0 | self.set_offset_minute_signed(value as i8) |
687 | | } |
688 | 0 | } |
689 | | |
690 | | /// Set the `offset_minute` component. |
691 | | #[doc(hidden)] |
692 | | #[deprecated( |
693 | | since = "0.3.8", |
694 | | note = "use `parsed.set_offset_second_signed()` instead" |
695 | | )] |
696 | | #[inline] |
697 | 0 | pub const fn set_offset_second(&mut self, value: u8) -> Option<()> { |
698 | 0 | if value > i8::MAX as u8 { |
699 | 0 | None |
700 | | } else { |
701 | 0 | self.set_offset_second_signed(value as i8) |
702 | | } |
703 | 0 | } |
704 | | } |
705 | | |
706 | | /// Builder methods |
707 | | /// |
708 | | /// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if |
709 | | /// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed. |
710 | | impl Parsed { |
711 | | /// Set the `year` component and return `self`. |
712 | | #[inline] |
713 | 0 | pub const fn with_year(mut self, value: i32) -> Option<Self> { |
714 | 0 | self.year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value))); |
715 | 0 | Some(self) |
716 | 0 | } |
717 | | |
718 | | /// Set the `year_century` component and return `self`. |
719 | | /// |
720 | | /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise |
721 | | /// the sign is inferred from the value. |
722 | | #[inline] |
723 | 0 | pub const fn with_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> { |
724 | 0 | self.year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value))); |
725 | 0 | if value != 0 { |
726 | 0 | self.year_century_is_negative = value.is_negative(); |
727 | 0 | } else { |
728 | 0 | self.year_century_is_negative = is_negative; |
729 | 0 | } |
730 | 0 | Some(self) |
731 | 0 | } |
732 | | |
733 | | /// Set the `year_last_two` component and return `self`. |
734 | | #[inline] |
735 | 0 | pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> { |
736 | 0 | self.year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value))); |
737 | 0 | Some(self) |
738 | 0 | } |
739 | | |
740 | | /// Set the `iso_year` component and return `self`. |
741 | | #[inline] |
742 | 0 | pub const fn with_iso_year(mut self, value: i32) -> Option<Self> { |
743 | 0 | self.iso_year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value))); |
744 | 0 | Some(self) |
745 | 0 | } |
746 | | |
747 | | /// Set the `iso_year_century` component and return `self`. |
748 | | /// |
749 | | /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise |
750 | | /// the sign is inferred from the value. |
751 | | #[inline] |
752 | 0 | pub const fn with_iso_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> { |
753 | 0 | self.iso_year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value))); |
754 | 0 | if value != 0 { |
755 | 0 | self.iso_year_century_is_negative = value.is_negative(); |
756 | 0 | } else { |
757 | 0 | self.iso_year_century_is_negative = is_negative; |
758 | 0 | } |
759 | 0 | Some(self) |
760 | 0 | } |
761 | | |
762 | | /// Set the `iso_year_last_two` component and return `self`. |
763 | | #[inline] |
764 | 0 | pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> { |
765 | 0 | self.iso_year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value))); |
766 | 0 | Some(self) |
767 | 0 | } |
768 | | |
769 | | /// Set the `month` component and return `self`. |
770 | | #[inline] |
771 | 0 | pub const fn with_month(mut self, value: Month) -> Option<Self> { |
772 | 0 | self.month = Some(value); |
773 | 0 | Some(self) |
774 | 0 | } |
775 | | |
776 | | /// Set the `sunday_week_number` component and return `self`. |
777 | | #[inline] |
778 | 0 | pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> { |
779 | 0 | self.sunday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value))); |
780 | 0 | Some(self) |
781 | 0 | } |
782 | | |
783 | | /// Set the `monday_week_number` component and return `self`. |
784 | | #[inline] |
785 | 0 | pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> { |
786 | 0 | self.monday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value))); |
787 | 0 | Some(self) |
788 | 0 | } |
789 | | |
790 | | /// Set the `iso_week_number` component and return `self`. |
791 | | #[inline] |
792 | 0 | pub const fn with_iso_week_number(mut self, value: NonZero<u8>) -> Option<Self> { |
793 | 0 | self.iso_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get()))); |
794 | 0 | Some(self) |
795 | 0 | } |
796 | | |
797 | | /// Set the `weekday` component and return `self`. |
798 | | #[inline] |
799 | 0 | pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> { |
800 | 0 | self.weekday = Some(value); |
801 | 0 | Some(self) |
802 | 0 | } |
803 | | |
804 | | /// Set the `ordinal` component and return `self`. |
805 | | #[inline] |
806 | 0 | pub const fn with_ordinal(mut self, value: NonZero<u16>) -> Option<Self> { |
807 | 0 | self.ordinal = OptionRangedU16::Some(const_try_opt!(RangedU16::new(value.get()))); |
808 | 0 | Some(self) |
809 | 0 | } |
810 | | |
811 | | /// Set the `day` component and return `self`. |
812 | | #[inline] |
813 | 0 | pub const fn with_day(mut self, value: NonZero<u8>) -> Option<Self> { |
814 | 0 | self.day = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get()))); |
815 | 0 | Some(self) |
816 | 0 | } |
817 | | |
818 | | /// Set the `hour_24` component and return `self`. |
819 | | #[inline] |
820 | 0 | pub const fn with_hour_24(mut self, value: u8) -> Option<Self> { |
821 | 0 | self.hour_24 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value))); |
822 | 0 | Some(self) |
823 | 0 | } |
824 | | |
825 | | /// Set the `hour_12` component and return `self`. |
826 | | #[inline] |
827 | 0 | pub const fn with_hour_12(mut self, value: NonZero<u8>) -> Option<Self> { |
828 | 0 | self.hour_12 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get()))); |
829 | 0 | Some(self) |
830 | 0 | } |
831 | | |
832 | | /// Set the `hour_12_is_pm` component and return `self`. |
833 | | #[inline] |
834 | 0 | pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> { |
835 | 0 | self.hour_12_is_pm = Some(value); |
836 | 0 | Some(self) |
837 | 0 | } |
838 | | |
839 | | /// Set the `minute` component and return `self`. |
840 | | #[inline] |
841 | 0 | pub const fn with_minute(mut self, value: u8) -> Option<Self> { |
842 | 0 | self.minute = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value))); |
843 | 0 | Some(self) |
844 | 0 | } |
845 | | |
846 | | /// Set the `second` component and return `self`. |
847 | | #[inline] |
848 | 0 | pub const fn with_second(mut self, value: u8) -> Option<Self> { |
849 | 0 | self.second = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value))); |
850 | 0 | Some(self) |
851 | 0 | } |
852 | | |
853 | | /// Set the `subsecond` component and return `self`. |
854 | | #[inline] |
855 | 0 | pub const fn with_subsecond(mut self, value: u32) -> Option<Self> { |
856 | 0 | self.subsecond = OptionRangedU32::Some(const_try_opt!(RangedU32::new(value))); |
857 | 0 | Some(self) |
858 | 0 | } |
859 | | |
860 | | /// Set the `offset_hour` component and return `self`. |
861 | | #[inline] |
862 | 0 | pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> { |
863 | 0 | self.offset_hour = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value))); |
864 | 0 | Some(self) |
865 | 0 | } |
866 | | |
867 | | /// Set the `offset_minute` component and return `self`. |
868 | | #[doc(hidden)] |
869 | | #[deprecated( |
870 | | since = "0.3.8", |
871 | | note = "use `parsed.with_offset_minute_signed()` instead" |
872 | | )] |
873 | | #[inline] |
874 | 0 | pub const fn with_offset_minute(self, value: u8) -> Option<Self> { |
875 | 0 | if value > i8::MAX as u8 { |
876 | 0 | None |
877 | | } else { |
878 | 0 | self.with_offset_minute_signed(value as i8) |
879 | | } |
880 | 0 | } |
881 | | |
882 | | /// Set the `offset_minute` component and return `self`. |
883 | | #[inline] |
884 | 0 | pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> { |
885 | 0 | self.offset_minute = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value))); |
886 | 0 | Some(self) |
887 | 0 | } |
888 | | |
889 | | /// Set the `offset_minute` component and return `self`. |
890 | | #[doc(hidden)] |
891 | | #[deprecated( |
892 | | since = "0.3.8", |
893 | | note = "use `parsed.with_offset_second_signed()` instead" |
894 | | )] |
895 | | #[inline] |
896 | 0 | pub const fn with_offset_second(self, value: u8) -> Option<Self> { |
897 | 0 | if value > i8::MAX as u8 { |
898 | 0 | None |
899 | | } else { |
900 | 0 | self.with_offset_second_signed(value as i8) |
901 | | } |
902 | 0 | } |
903 | | |
904 | | /// Set the `offset_second` component and return `self`. |
905 | | #[inline] |
906 | 0 | pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> { |
907 | 0 | self.offset_second = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value))); |
908 | 0 | Some(self) |
909 | 0 | } |
910 | | |
911 | | /// Set the `unix_timestamp_nanos` component and return `self`. |
912 | | #[inline] |
913 | 0 | pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> { |
914 | 0 | self.unix_timestamp_nanos = OptionRangedI128::Some(const_try_opt!(RangedI128::new(value))); |
915 | 0 | Some(self) |
916 | 0 | } |
917 | | } |
918 | | |
919 | | impl TryFrom<Parsed> for Date { |
920 | | type Error = error::TryFromParsed; |
921 | | |
922 | | #[inline] |
923 | 0 | fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> { |
924 | | /// Match on the components that need to be present. |
925 | | macro_rules! match_ { |
926 | | (_ => $catch_all:expr $(,)?) => { |
927 | | $catch_all |
928 | | }; |
929 | | (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => { |
930 | | if let ($(Some($name)),*) = ($(parsed.$name()),*) { |
931 | | $arm |
932 | | } else { |
933 | | match_!($($rest)*) |
934 | | } |
935 | | }; |
936 | | } |
937 | | |
938 | | /// Get the value needed to adjust the ordinal day for Sunday and Monday-based week |
939 | | /// numbering. |
940 | | #[inline] |
941 | 0 | const fn adjustment(year: i32) -> i16 { |
942 | | // Safety: `ordinal` is not zero. |
943 | 0 | match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() { |
944 | 0 | Weekday::Monday => 7, |
945 | 0 | Weekday::Tuesday => 1, |
946 | 0 | Weekday::Wednesday => 2, |
947 | 0 | Weekday::Thursday => 3, |
948 | 0 | Weekday::Friday => 4, |
949 | 0 | Weekday::Saturday => 5, |
950 | 0 | Weekday::Sunday => 6, |
951 | | } |
952 | 0 | } |
953 | | |
954 | | // If we do not have the year but we have *both* the century and the last two digits, we can |
955 | | // construct the year. Likewise for the ISO year. |
956 | 0 | if let (None, Some(century), Some(is_negative), Some(last_two)) = ( |
957 | 0 | parsed.year(), |
958 | 0 | parsed.year_century(), |
959 | 0 | parsed.year_century_is_negative(), |
960 | 0 | parsed.year_last_two(), |
961 | | ) { |
962 | 0 | let year = if is_negative { |
963 | 0 | 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>() |
964 | | } else { |
965 | 0 | 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>() |
966 | | }; |
967 | 0 | parsed.year = OptionRangedI32::from(RangedI32::new(year)); |
968 | 0 | } |
969 | 0 | if let (None, Some(century), Some(is_negative), Some(last_two)) = ( |
970 | 0 | parsed.iso_year(), |
971 | 0 | parsed.iso_year_century(), |
972 | 0 | parsed.iso_year_century_is_negative(), |
973 | 0 | parsed.iso_year_last_two(), |
974 | | ) { |
975 | 0 | let iso_year = if is_negative { |
976 | 0 | 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>() |
977 | | } else { |
978 | 0 | 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>() |
979 | | }; |
980 | 0 | parsed.iso_year = OptionRangedI32::from(RangedI32::new(iso_year)); |
981 | 0 | } |
982 | | |
983 | 0 | match_! { |
984 | 0 | (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?), |
985 | 0 | (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?), |
986 | 0 | (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date( |
987 | 0 | iso_year, |
988 | 0 | iso_week_number.get(), |
989 | 0 | weekday, |
990 | 0 | )?), |
991 | 0 | (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date( |
992 | 0 | year, |
993 | 0 | (sunday_week_number.cast_signed().extend::<i16>() * 7 |
994 | 0 | + weekday.number_days_from_sunday().cast_signed().extend::<i16>() |
995 | 0 | - adjustment(year) |
996 | 0 | + 1).cast_unsigned(), |
997 | 0 | )?), |
998 | 0 | (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date( |
999 | 0 | year, |
1000 | 0 | (monday_week_number.cast_signed().extend::<i16>() * 7 |
1001 | 0 | + weekday.number_days_from_monday().cast_signed().extend::<i16>() |
1002 | 0 | - adjustment(year) |
1003 | 0 | + 1).cast_unsigned(), |
1004 | 0 | )?), |
1005 | 0 | _ => Err(InsufficientInformation), |
1006 | | } |
1007 | 0 | } |
1008 | | } |
1009 | | |
1010 | | impl TryFrom<Parsed> for Time { |
1011 | | type Error = error::TryFromParsed; |
1012 | | |
1013 | | #[inline] |
1014 | 0 | fn try_from(parsed: Parsed) -> Result<Self, Self::Error> { |
1015 | 0 | let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) { |
1016 | 0 | (Some(hour), _, _) => hour, |
1017 | 0 | (_, Some(hour), Some(false)) if hour.get() == 12 => 0, |
1018 | 0 | (_, Some(hour), Some(true)) if hour.get() == 12 => 12, |
1019 | 0 | (_, Some(hour), Some(false)) => hour.get(), |
1020 | 0 | (_, Some(hour), Some(true)) => hour.get() + 12, |
1021 | 0 | _ => return Err(InsufficientInformation), |
1022 | | }; |
1023 | | |
1024 | 0 | if parsed.hour_24().is_none() |
1025 | 0 | && parsed.hour_12().is_some() |
1026 | 0 | && parsed.hour_12_is_pm().is_some() |
1027 | 0 | && parsed.minute().is_none() |
1028 | 0 | && parsed.second().is_none() |
1029 | 0 | && parsed.subsecond().is_none() |
1030 | | { |
1031 | 0 | return Ok(Self::from_hms_nano(hour, 0, 0, 0)?); |
1032 | 0 | } |
1033 | | |
1034 | | // Reject combinations such as hour-second with minute omitted. |
1035 | 0 | match (parsed.minute(), parsed.second(), parsed.subsecond()) { |
1036 | 0 | (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?), |
1037 | 0 | (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?), |
1038 | 0 | (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?), |
1039 | 0 | (Some(minute), Some(second), Some(subsecond)) => { |
1040 | 0 | Ok(Self::from_hms_nano(hour, minute, second, subsecond)?) |
1041 | | } |
1042 | 0 | _ => Err(InsufficientInformation), |
1043 | | } |
1044 | 0 | } |
1045 | | } |
1046 | | |
1047 | | #[inline] |
1048 | 0 | fn utc_offset_try_from_parsed<const REQUIRED: bool>( |
1049 | 0 | parsed: Parsed, |
1050 | 0 | ) -> Result<UtcOffset, error::TryFromParsed> { |
1051 | 0 | let hour = match (REQUIRED, parsed.offset_hour()) { |
1052 | | // An offset is required, but the hour is missing. Return an error. |
1053 | 0 | (true, None) => return Err(InsufficientInformation), |
1054 | | // An offset is not required (e.g. for `UtcDateTime`). As the hour is missing, minutes and |
1055 | | // seconds are not parsed. This is UTC. |
1056 | 0 | (false, None) => return Ok(UtcOffset::UTC), |
1057 | | // Any other situation has an hour present. |
1058 | 0 | (_, Some(hour)) => hour, |
1059 | | }; |
1060 | 0 | let minute = parsed.offset_minute_signed(); |
1061 | | // Force `second` to be `None` if `minute` is `None`. |
1062 | 0 | let second = minute.and_then(|_| parsed.offset_second_signed()); |
1063 | | |
1064 | 0 | let minute = minute.unwrap_or(0); |
1065 | 0 | let second = second.unwrap_or(0); |
1066 | | |
1067 | 0 | UtcOffset::from_hms(hour, minute, second).map_err(|mut err| { |
1068 | | // Provide the user a more accurate error. |
1069 | 0 | if err.name == "hours" { |
1070 | 0 | err.name = "offset hour"; |
1071 | 0 | } else if err.name == "minutes" { |
1072 | 0 | err.name = "offset minute"; |
1073 | 0 | } else if err.name == "seconds" { |
1074 | 0 | err.name = "offset second"; |
1075 | 0 | } |
1076 | 0 | err.into() |
1077 | 0 | }) |
1078 | 0 | } |
1079 | | |
1080 | | impl TryFrom<Parsed> for UtcOffset { |
1081 | | type Error = error::TryFromParsed; |
1082 | | |
1083 | | #[inline] |
1084 | 0 | fn try_from(parsed: Parsed) -> Result<Self, Self::Error> { |
1085 | 0 | utc_offset_try_from_parsed::<true>(parsed) |
1086 | 0 | } |
1087 | | } |
1088 | | |
1089 | | impl TryFrom<Parsed> for PrimitiveDateTime { |
1090 | | type Error = error::TryFromParsed; |
1091 | | |
1092 | | #[inline] |
1093 | 0 | fn try_from(parsed: Parsed) -> Result<Self, Self::Error> { |
1094 | 0 | Ok(Self::new(parsed.try_into()?, parsed.try_into()?)) |
1095 | 0 | } |
1096 | | } |
1097 | | |
1098 | | impl TryFrom<Parsed> for UtcDateTime { |
1099 | | type Error = error::TryFromParsed; |
1100 | | |
1101 | | #[inline] |
1102 | 0 | fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> { |
1103 | 0 | if let Some(timestamp) = parsed.unix_timestamp_nanos() { |
1104 | 0 | let mut value = Self::from_unix_timestamp_nanos(timestamp)?; |
1105 | 0 | if let Some(subsecond) = parsed.subsecond() { |
1106 | 0 | value = value.replace_nanosecond(subsecond)?; |
1107 | 0 | } |
1108 | 0 | return Ok(value); |
1109 | 0 | } |
1110 | | |
1111 | | // Some well-known formats explicitly allow leap seconds. We don't currently support them, |
1112 | | // so treat it as the nearest preceding moment that can be represented. Because leap seconds |
1113 | | // always fall at the end of a month UTC, reject any that are at other times. |
1114 | 0 | let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) { |
1115 | 0 | if parsed.set_second(59).is_none() { |
1116 | 0 | bug!("59 is a valid second"); |
1117 | 0 | } |
1118 | 0 | if parsed.set_subsecond(999_999_999).is_none() { |
1119 | 0 | bug!("999_999_999 is a valid subsecond"); |
1120 | 0 | } |
1121 | 0 | true |
1122 | | } else { |
1123 | 0 | false |
1124 | | }; |
1125 | | |
1126 | 0 | let dt = OffsetDateTime::new_in_offset( |
1127 | 0 | Date::try_from(parsed)?, |
1128 | 0 | Time::try_from(parsed)?, |
1129 | 0 | utc_offset_try_from_parsed::<false>(parsed)?, |
1130 | | ) |
1131 | 0 | .to_utc(); |
1132 | | |
1133 | 0 | if leap_second_input && !dt.is_valid_leap_second_stand_in() { |
1134 | 0 | return Err(error::TryFromParsed::ComponentRange( |
1135 | 0 | error::ComponentRange { |
1136 | 0 | name: "second", |
1137 | 0 | minimum: 0, |
1138 | 0 | maximum: 59, |
1139 | 0 | value: 60, |
1140 | 0 | conditional_message: Some("because leap seconds are not supported"), |
1141 | 0 | }, |
1142 | 0 | )); |
1143 | 0 | } |
1144 | 0 | Ok(dt) |
1145 | 0 | } |
1146 | | } |
1147 | | |
1148 | | impl TryFrom<Parsed> for OffsetDateTime { |
1149 | | type Error = error::TryFromParsed; |
1150 | | |
1151 | | #[inline] |
1152 | 0 | fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> { |
1153 | 0 | if let Some(timestamp) = parsed.unix_timestamp_nanos() { |
1154 | 0 | let mut value = Self::from_unix_timestamp_nanos(timestamp)?; |
1155 | 0 | if let Some(subsecond) = parsed.subsecond() { |
1156 | 0 | value = value.replace_nanosecond(subsecond)?; |
1157 | 0 | } |
1158 | 0 | return Ok(value); |
1159 | 0 | } |
1160 | | |
1161 | | // Some well-known formats explicitly allow leap seconds. We don't currently support them, |
1162 | | // so treat it as the nearest preceding moment that can be represented. Because leap seconds |
1163 | | // always fall at the end of a month UTC, reject any that are at other times. |
1164 | 0 | let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) { |
1165 | 0 | if parsed.set_second(59).is_none() { |
1166 | 0 | bug!("59 is a valid second"); |
1167 | 0 | } |
1168 | 0 | if parsed.set_subsecond(999_999_999).is_none() { |
1169 | 0 | bug!("999_999_999 is a valid subsecond"); |
1170 | 0 | } |
1171 | 0 | true |
1172 | | } else { |
1173 | 0 | false |
1174 | | }; |
1175 | | |
1176 | 0 | let dt = Self::new_in_offset( |
1177 | 0 | Date::try_from(parsed)?, |
1178 | 0 | Time::try_from(parsed)?, |
1179 | 0 | UtcOffset::try_from(parsed)?, |
1180 | | ); |
1181 | | |
1182 | 0 | if leap_second_input && !dt.is_valid_leap_second_stand_in() { |
1183 | 0 | return Err(error::TryFromParsed::ComponentRange( |
1184 | 0 | error::ComponentRange { |
1185 | 0 | name: "second", |
1186 | 0 | minimum: 0, |
1187 | 0 | maximum: 59, |
1188 | 0 | value: 60, |
1189 | 0 | conditional_message: Some("because leap seconds are not supported"), |
1190 | 0 | }, |
1191 | 0 | )); |
1192 | 0 | } |
1193 | 0 | Ok(dt) |
1194 | 0 | } |
1195 | | } |