/rust/registry/src/index.crates.io-1949cf8c6b5b557f/time-0.3.13/src/parsing/parsed.rs
Line | Count | Source |
1 | | //! Information parsed from an input and format description. |
2 | | |
3 | | use core::num::{NonZeroU16, NonZeroU8}; |
4 | | |
5 | | use crate::error::TryFromParsed::InsufficientInformation; |
6 | | use crate::format_description::modifier::{WeekNumberRepr, YearRepr}; |
7 | | use crate::format_description::{Component, FormatItem}; |
8 | | use crate::parsing::component::{ |
9 | | parse_day, parse_hour, parse_minute, parse_month, parse_offset_hour, parse_offset_minute, |
10 | | parse_offset_second, parse_ordinal, parse_period, parse_second, parse_subsecond, |
11 | | parse_week_number, parse_weekday, parse_year, Period, |
12 | | }; |
13 | | use crate::parsing::ParsedItem; |
14 | | use crate::{error, Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday}; |
15 | | |
16 | | /// All information parsed. |
17 | | /// |
18 | | /// This information is directly used to construct the final values. |
19 | | /// |
20 | | /// Most users will not need think about this struct in any way. It is public to allow for manual |
21 | | /// control over values, in the instance that the default parser is insufficient. |
22 | | #[derive(Debug, Clone, Copy)] |
23 | | pub struct Parsed { |
24 | | /// Calendar year. |
25 | | year: Option<i32>, |
26 | | /// The last two digits of the calendar year. |
27 | | year_last_two: Option<u8>, |
28 | | /// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date). |
29 | | iso_year: Option<i32>, |
30 | | /// The last two digits of the ISO week year. |
31 | | iso_year_last_two: Option<u8>, |
32 | | /// Month of the year. |
33 | | month: Option<Month>, |
34 | | /// Week of the year, where week one begins on the first Sunday of the calendar year. |
35 | | sunday_week_number: Option<u8>, |
36 | | /// Week of the year, where week one begins on the first Monday of the calendar year. |
37 | | monday_week_number: Option<u8>, |
38 | | /// Week of the year, where week one is the Monday-to-Sunday period containing January 4. |
39 | | iso_week_number: Option<NonZeroU8>, |
40 | | /// Day of the week. |
41 | | weekday: Option<Weekday>, |
42 | | /// Day of the year. |
43 | | ordinal: Option<NonZeroU16>, |
44 | | /// Day of the month. |
45 | | day: Option<NonZeroU8>, |
46 | | /// Hour within the day. |
47 | | hour_24: Option<u8>, |
48 | | /// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in |
49 | | /// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field. |
50 | | hour_12: Option<NonZeroU8>, |
51 | | /// Whether the `hour_12` field indicates a time that "PM". |
52 | | hour_12_is_pm: Option<bool>, |
53 | | /// Minute within the hour. |
54 | | minute: Option<u8>, |
55 | | /// Second within the minute. |
56 | | second: Option<u8>, |
57 | | /// Nanosecond within the second. |
58 | | subsecond: Option<u32>, |
59 | | /// Whole hours of the UTC offset. |
60 | | offset_hour: Option<i8>, |
61 | | /// Minutes within the hour of the UTC offset. |
62 | | offset_minute: Option<i8>, |
63 | | /// Seconds within the minute of the UTC offset. |
64 | | offset_second: Option<i8>, |
65 | | /// Indicates whether a leap second is permitted to be parsed. This is required by some |
66 | | /// well-known formats. |
67 | | leap_second_allowed: bool, |
68 | | } |
69 | | |
70 | | impl Parsed { |
71 | | /// Create a new instance of `Parsed` with no information known. |
72 | 0 | pub const fn new() -> Self { |
73 | 0 | Self { |
74 | 0 | year: None, |
75 | 0 | year_last_two: None, |
76 | 0 | iso_year: None, |
77 | 0 | iso_year_last_two: None, |
78 | 0 | month: None, |
79 | 0 | sunday_week_number: None, |
80 | 0 | monday_week_number: None, |
81 | 0 | iso_week_number: None, |
82 | 0 | weekday: None, |
83 | 0 | ordinal: None, |
84 | 0 | day: None, |
85 | 0 | hour_24: None, |
86 | 0 | hour_12: None, |
87 | 0 | hour_12_is_pm: None, |
88 | 0 | minute: None, |
89 | 0 | second: None, |
90 | 0 | subsecond: None, |
91 | 0 | offset_hour: None, |
92 | 0 | offset_minute: None, |
93 | 0 | offset_second: None, |
94 | 0 | leap_second_allowed: false, |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | /// Parse a single [`FormatItem`], mutating the struct. The remaining input is returned as the |
99 | | /// `Ok` value. |
100 | | /// |
101 | | /// If a [`FormatItem::Optional`] is passed, parsing will not fail; the input will be returned |
102 | | /// as-is if the expected format is not present. |
103 | 0 | pub fn parse_item<'a>( |
104 | 0 | &mut self, |
105 | 0 | input: &'a [u8], |
106 | 0 | item: &FormatItem<'_>, |
107 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
108 | 0 | match item { |
109 | 0 | FormatItem::Literal(literal) => Self::parse_literal(input, literal), |
110 | 0 | FormatItem::Component(component) => self.parse_component(input, *component), |
111 | 0 | FormatItem::Compound(compound) => self.parse_items(input, compound), |
112 | 0 | FormatItem::Optional(item) => self.parse_item(input, item).or(Ok(input)), |
113 | 0 | FormatItem::First(items) => { |
114 | 0 | let mut first_err = None; |
115 | | |
116 | 0 | for item in items.iter() { |
117 | 0 | match self.parse_item(input, item) { |
118 | 0 | Ok(remaining_input) => return Ok(remaining_input), |
119 | 0 | Err(err) if first_err.is_none() => first_err = Some(err), |
120 | 0 | Err(_) => {} |
121 | | } |
122 | | } |
123 | | |
124 | 0 | match first_err { |
125 | 0 | Some(err) => Err(err), |
126 | | // This location will be reached if the slice is empty, skipping the `for` loop. |
127 | | // As this case is expected to be uncommon, there's no need to check up front. |
128 | 0 | None => Ok(input), |
129 | | } |
130 | | } |
131 | | } |
132 | 0 | } |
133 | | |
134 | | /// Parse a sequence of [`FormatItem`]s, mutating the struct. The remaining input is returned as |
135 | | /// the `Ok` value. |
136 | | /// |
137 | | /// This method will fail if any of the contained [`FormatItem`]s fail to parse. `self` will not |
138 | | /// be mutated in this instance. |
139 | 0 | pub fn parse_items<'a>( |
140 | 0 | &mut self, |
141 | 0 | mut input: &'a [u8], |
142 | 0 | items: &[FormatItem<'_>], |
143 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
144 | | // Make a copy that we can mutate. It will only be set to the user's copy if everything |
145 | | // succeeds. |
146 | 0 | let mut this = *self; |
147 | 0 | for item in items { |
148 | 0 | input = this.parse_item(input, item)?; |
149 | | } |
150 | 0 | *self = this; |
151 | 0 | Ok(input) |
152 | 0 | } |
153 | | |
154 | | /// Parse a literal byte sequence. The remaining input is returned as the `Ok` value. |
155 | 0 | pub fn parse_literal<'a>( |
156 | 0 | input: &'a [u8], |
157 | 0 | literal: &[u8], |
158 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
159 | 0 | input |
160 | 0 | .strip_prefix(literal) |
161 | 0 | .ok_or(error::ParseFromDescription::InvalidLiteral) |
162 | 0 | } |
163 | | |
164 | | /// Parse a single component, mutating the struct. The remaining input is returned as the `Ok` |
165 | | /// value. |
166 | 0 | pub fn parse_component<'a>( |
167 | 0 | &mut self, |
168 | 0 | input: &'a [u8], |
169 | 0 | component: Component, |
170 | 0 | ) -> Result<&'a [u8], error::ParseFromDescription> { |
171 | | use error::ParseFromDescription::InvalidComponent; |
172 | | |
173 | 0 | match component { |
174 | 0 | Component::Day(modifiers) => parse_day(input, modifiers) |
175 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_day(value))) |
176 | 0 | .ok_or(InvalidComponent("day")), |
177 | 0 | Component::Month(modifiers) => parse_month(input, modifiers) |
178 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_month(value))) |
179 | 0 | .ok_or(InvalidComponent("month")), |
180 | 0 | Component::Ordinal(modifiers) => parse_ordinal(input, modifiers) |
181 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value))) |
182 | 0 | .ok_or(InvalidComponent("ordinal")), |
183 | 0 | Component::Weekday(modifiers) => parse_weekday(input, modifiers) |
184 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value))) |
185 | 0 | .ok_or(InvalidComponent("weekday")), |
186 | 0 | Component::WeekNumber(modifiers) => { |
187 | 0 | let ParsedItem(remaining, value) = |
188 | 0 | parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?; |
189 | 0 | match modifiers.repr { |
190 | | WeekNumberRepr::Iso => { |
191 | 0 | NonZeroU8::new(value).and_then(|value| self.set_iso_week_number(value)) |
192 | | } |
193 | 0 | WeekNumberRepr::Sunday => self.set_sunday_week_number(value), |
194 | 0 | WeekNumberRepr::Monday => self.set_monday_week_number(value), |
195 | | } |
196 | 0 | .ok_or(InvalidComponent("week number"))?; |
197 | 0 | Ok(remaining) |
198 | | } |
199 | 0 | Component::Year(modifiers) => { |
200 | 0 | let ParsedItem(remaining, value) = |
201 | 0 | parse_year(input, modifiers).ok_or(InvalidComponent("year"))?; |
202 | 0 | match (modifiers.iso_week_based, modifiers.repr) { |
203 | 0 | (false, YearRepr::Full) => self.set_year(value), |
204 | 0 | (false, YearRepr::LastTwo) => self.set_year_last_two(value as _), |
205 | 0 | (true, YearRepr::Full) => self.set_iso_year(value), |
206 | 0 | (true, YearRepr::LastTwo) => self.set_iso_year_last_two(value as _), |
207 | | } |
208 | 0 | .ok_or(InvalidComponent("year"))?; |
209 | 0 | Ok(remaining) |
210 | | } |
211 | 0 | Component::Hour(modifiers) => { |
212 | 0 | let ParsedItem(remaining, value) = |
213 | 0 | parse_hour(input, modifiers).ok_or(InvalidComponent("hour"))?; |
214 | 0 | if modifiers.is_12_hour_clock { |
215 | 0 | NonZeroU8::new(value).and_then(|value| self.set_hour_12(value)) |
216 | | } else { |
217 | 0 | self.set_hour_24(value) |
218 | | } |
219 | 0 | .ok_or(InvalidComponent("hour"))?; |
220 | 0 | Ok(remaining) |
221 | | } |
222 | 0 | Component::Minute(modifiers) => parse_minute(input, modifiers) |
223 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value))) |
224 | 0 | .ok_or(InvalidComponent("minute")), |
225 | 0 | Component::Period(modifiers) => parse_period(input, modifiers) |
226 | 0 | .and_then(|parsed| { |
227 | 0 | parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm)) |
228 | 0 | }) |
229 | 0 | .ok_or(InvalidComponent("period")), |
230 | 0 | Component::Second(modifiers) => parse_second(input, modifiers) |
231 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_second(value))) |
232 | 0 | .ok_or(InvalidComponent("second")), |
233 | 0 | Component::Subsecond(modifiers) => parse_subsecond(input, modifiers) |
234 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value))) |
235 | 0 | .ok_or(InvalidComponent("subsecond")), |
236 | 0 | Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers) |
237 | 0 | .and_then(|parsed| parsed.consume_value(|value| self.set_offset_hour(value))) |
238 | 0 | .ok_or(InvalidComponent("offset hour")), |
239 | 0 | Component::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers) |
240 | 0 | .and_then(|parsed| { |
241 | 0 | parsed.consume_value(|value| self.set_offset_minute_signed(value)) |
242 | 0 | }) |
243 | 0 | .ok_or(InvalidComponent("offset minute")), |
244 | 0 | Component::OffsetSecond(modifiers) => parse_offset_second(input, modifiers) |
245 | 0 | .and_then(|parsed| { |
246 | 0 | parsed.consume_value(|value| self.set_offset_second_signed(value)) |
247 | 0 | }) |
248 | 0 | .ok_or(InvalidComponent("offset second")), |
249 | | } |
250 | 0 | } |
251 | | } |
252 | | |
253 | | /// Generate getters for each of the fields. |
254 | | macro_rules! getters { |
255 | | ($($name:ident: $ty:ty),+ $(,)?) => {$( |
256 | | /// Obtain the named component. |
257 | 0 | pub const fn $name(&self) -> Option<$ty> { |
258 | 0 | self.$name |
259 | 0 | } Unexecuted instantiation: <time::parsing::parsed::Parsed>::iso_week_number Unexecuted instantiation: <time::parsing::parsed::Parsed>::monday_week_number Unexecuted instantiation: <time::parsing::parsed::Parsed>::sunday_week_number Unexecuted instantiation: <time::parsing::parsed::Parsed>::day Unexecuted instantiation: <time::parsing::parsed::Parsed>::year Unexecuted instantiation: <time::parsing::parsed::Parsed>::month Unexecuted instantiation: <time::parsing::parsed::Parsed>::ordinal Unexecuted instantiation: <time::parsing::parsed::Parsed>::weekday Unexecuted instantiation: <time::parsing::parsed::Parsed>::iso_year Unexecuted instantiation: <time::parsing::parsed::Parsed>::offset_hour Unexecuted instantiation: <time::parsing::parsed::Parsed>::second Unexecuted instantiation: <time::parsing::parsed::Parsed>::year_last_two Unexecuted instantiation: <time::parsing::parsed::Parsed>::iso_year_last_two Unexecuted instantiation: <time::parsing::parsed::Parsed>::hour_12_is_pm Unexecuted instantiation: <time::parsing::parsed::Parsed>::minute Unexecuted instantiation: <time::parsing::parsed::Parsed>::hour_12 Unexecuted instantiation: <time::parsing::parsed::Parsed>::hour_24 Unexecuted instantiation: <time::parsing::parsed::Parsed>::subsecond |
260 | | )*} |
261 | | } |
262 | | |
263 | | /// Getter methods |
264 | | impl Parsed { |
265 | | getters! { |
266 | | year: i32, |
267 | | year_last_two: u8, |
268 | | iso_year: i32, |
269 | | iso_year_last_two: u8, |
270 | | month: Month, |
271 | | sunday_week_number: u8, |
272 | | monday_week_number: u8, |
273 | | iso_week_number: NonZeroU8, |
274 | | weekday: Weekday, |
275 | | ordinal: NonZeroU16, |
276 | | day: NonZeroU8, |
277 | | hour_24: u8, |
278 | | hour_12: NonZeroU8, |
279 | | hour_12_is_pm: bool, |
280 | | minute: u8, |
281 | | second: u8, |
282 | | subsecond: u32, |
283 | | offset_hour: i8, |
284 | | } |
285 | | |
286 | | /// Obtain the absolute value of the offset minute. |
287 | | #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")] |
288 | 0 | pub const fn offset_minute(&self) -> Option<u8> { |
289 | 0 | Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs()) |
290 | 0 | } |
291 | | |
292 | | /// Obtain the offset minute as an `i8`. |
293 | 0 | pub const fn offset_minute_signed(&self) -> Option<i8> { |
294 | 0 | self.offset_minute |
295 | 0 | } |
296 | | |
297 | | /// Obtain the absolute value of the offset second. |
298 | | #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")] |
299 | 0 | pub const fn offset_second(&self) -> Option<u8> { |
300 | 0 | Some(const_try_opt!(self.offset_second_signed()).unsigned_abs()) |
301 | 0 | } |
302 | | |
303 | | /// Obtain the offset second as an `i8`. |
304 | 0 | pub const fn offset_second_signed(&self) -> Option<i8> { |
305 | 0 | self.offset_second |
306 | 0 | } |
307 | | |
308 | | /// Obtain whether leap seconds are permitted in the current format. |
309 | 0 | pub(crate) const fn leap_second_allowed(&self) -> bool { |
310 | 0 | self.leap_second_allowed |
311 | 0 | } |
312 | | } |
313 | | |
314 | | /// Generate setters for each of the fields. |
315 | | /// |
316 | | /// This macro should only be used for fields where the value is not validated beyond its type. |
317 | | macro_rules! setters { |
318 | | ($($setter_name:ident $name:ident: $ty:ty),+ $(,)?) => {$( |
319 | | /// Set the named component. |
320 | 0 | pub fn $setter_name(&mut self, value: $ty) -> Option<()> { |
321 | 0 | self.$name = Some(value); |
322 | 0 | Some(()) |
323 | 0 | } Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_hour_12 Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_ordinal Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_iso_year 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_second Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_subsecond Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_minute Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_hour_24 Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_weekday Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_offset_hour Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_day Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_year Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_month |
324 | | )*} |
325 | | } |
326 | | |
327 | | /// Setter methods |
328 | | /// |
329 | | /// All setters return `Option<()>`, which is `Some` if the value was set, and `None` if not. The |
330 | | /// setters _may_ fail if the value is invalid, though behavior is not guaranteed. |
331 | | impl Parsed { |
332 | | setters! { |
333 | | set_year year: i32, |
334 | | set_year_last_two year_last_two: u8, |
335 | | set_iso_year iso_year: i32, |
336 | | set_iso_year_last_two iso_year_last_two: u8, |
337 | | set_month month: Month, |
338 | | set_sunday_week_number sunday_week_number: u8, |
339 | | set_monday_week_number monday_week_number: u8, |
340 | | set_iso_week_number iso_week_number: NonZeroU8, |
341 | | set_weekday weekday: Weekday, |
342 | | set_ordinal ordinal: NonZeroU16, |
343 | | set_day day: NonZeroU8, |
344 | | set_hour_24 hour_24: u8, |
345 | | set_hour_12 hour_12: NonZeroU8, |
346 | | set_hour_12_is_pm hour_12_is_pm: bool, |
347 | | set_minute minute: u8, |
348 | | set_second second: u8, |
349 | | set_subsecond subsecond: u32, |
350 | | set_offset_hour offset_hour: i8, |
351 | | } |
352 | | |
353 | | /// Set the named component. |
354 | | #[deprecated( |
355 | | since = "0.3.8", |
356 | | note = "use `parsed.set_offset_minute_signed()` instead" |
357 | | )] |
358 | 0 | pub fn set_offset_minute(&mut self, value: u8) -> Option<()> { |
359 | 0 | if value > i8::MAX as u8 { |
360 | 0 | None |
361 | | } else { |
362 | 0 | self.set_offset_minute_signed(value as _) |
363 | | } |
364 | 0 | } |
365 | | |
366 | | /// Set the `offset_minute` component. |
367 | 0 | pub fn set_offset_minute_signed(&mut self, value: i8) -> Option<()> { |
368 | 0 | self.offset_minute = Some(value); |
369 | 0 | Some(()) |
370 | 0 | } |
371 | | |
372 | | /// Set the named component. |
373 | | #[deprecated( |
374 | | since = "0.3.8", |
375 | | note = "use `parsed.set_offset_second_signed()` instead" |
376 | | )] |
377 | 0 | pub fn set_offset_second(&mut self, value: u8) -> Option<()> { |
378 | 0 | if value > i8::MAX as u8 { |
379 | 0 | None |
380 | | } else { |
381 | 0 | self.set_offset_second_signed(value as _) |
382 | | } |
383 | 0 | } |
384 | | |
385 | | /// Set the `offset_second` component. |
386 | 0 | pub fn set_offset_second_signed(&mut self, value: i8) -> Option<()> { |
387 | 0 | self.offset_second = Some(value); |
388 | 0 | Some(()) |
389 | 0 | } |
390 | | |
391 | | /// Set the leap second allowed flag. |
392 | 0 | pub(crate) fn set_leap_second_allowed(&mut self, value: bool) { |
393 | 0 | self.leap_second_allowed = value; |
394 | 0 | } |
395 | | } |
396 | | |
397 | | /// Generate build methods for each of the fields. |
398 | | /// |
399 | | /// This macro should only be used for fields where the value is not validated beyond its type. |
400 | | macro_rules! builders { |
401 | | ($($builder_name:ident $name:ident: $ty:ty),+ $(,)?) => {$( |
402 | | /// Set the named component and return `self`. |
403 | 0 | pub const fn $builder_name(mut self, value: $ty) -> Option<Self> { |
404 | 0 | self.$name = Some(value); |
405 | 0 | Some(self) |
406 | 0 | } Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_month Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_minute Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_second Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_hour_12 Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_hour_24 Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_ordinal Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_weekday Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_iso_year Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_subsecond Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_offset_hour Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_hour_12_is_pm Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_year_last_two Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_iso_week_number Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_iso_year_last_two Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_monday_week_number Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_sunday_week_number Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_day Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_year |
407 | | )*} |
408 | | } |
409 | | |
410 | | /// Builder methods |
411 | | /// |
412 | | /// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if |
413 | | /// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed. |
414 | | impl Parsed { |
415 | | builders! { |
416 | | with_year year: i32, |
417 | | with_year_last_two year_last_two: u8, |
418 | | with_iso_year iso_year: i32, |
419 | | with_iso_year_last_two iso_year_last_two: u8, |
420 | | with_month month: Month, |
421 | | with_sunday_week_number sunday_week_number: u8, |
422 | | with_monday_week_number monday_week_number: u8, |
423 | | with_iso_week_number iso_week_number: NonZeroU8, |
424 | | with_weekday weekday: Weekday, |
425 | | with_ordinal ordinal: NonZeroU16, |
426 | | with_day day: NonZeroU8, |
427 | | with_hour_24 hour_24: u8, |
428 | | with_hour_12 hour_12: NonZeroU8, |
429 | | with_hour_12_is_pm hour_12_is_pm: bool, |
430 | | with_minute minute: u8, |
431 | | with_second second: u8, |
432 | | with_subsecond subsecond: u32, |
433 | | with_offset_hour offset_hour: i8, |
434 | | } |
435 | | |
436 | | /// Set the named component and return `self`. |
437 | | #[deprecated( |
438 | | since = "0.3.8", |
439 | | note = "use `parsed.with_offset_minute_signed()` instead" |
440 | | )] |
441 | 0 | pub const fn with_offset_minute(self, value: u8) -> Option<Self> { |
442 | 0 | if value > i8::MAX as u8 { |
443 | 0 | None |
444 | | } else { |
445 | 0 | self.with_offset_minute_signed(value as _) |
446 | | } |
447 | 0 | } |
448 | | |
449 | | /// Set the `offset_minute` component and return `self`. |
450 | 0 | pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> { |
451 | 0 | self.offset_minute = Some(value); |
452 | 0 | Some(self) |
453 | 0 | } |
454 | | |
455 | | /// Set the named component and return `self`. |
456 | | #[deprecated( |
457 | | since = "0.3.8", |
458 | | note = "use `parsed.with_offset_second_signed()` instead" |
459 | | )] |
460 | 0 | pub const fn with_offset_second(self, value: u8) -> Option<Self> { |
461 | 0 | if value > i8::MAX as u8 { |
462 | 0 | None |
463 | | } else { |
464 | 0 | self.with_offset_second_signed(value as _) |
465 | | } |
466 | 0 | } |
467 | | |
468 | | /// Set the `offset_second` component and return `self`. |
469 | 0 | pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> { |
470 | 0 | self.offset_second = Some(value); |
471 | 0 | Some(self) |
472 | 0 | } |
473 | | } |
474 | | |
475 | | impl TryFrom<Parsed> for Date { |
476 | | type Error = error::TryFromParsed; |
477 | | |
478 | 0 | fn try_from(parsed: Parsed) -> Result<Self, Self::Error> { |
479 | | /// Match on the components that need to be present. |
480 | | macro_rules! match_ { |
481 | | (_ => $catch_all:expr $(,)?) => { |
482 | | $catch_all |
483 | | }; |
484 | | (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => { |
485 | | if let ($(Some($name)),*) = ($(parsed.$name()),*) { |
486 | | $arm |
487 | | } else { |
488 | | match_!($($rest)*) |
489 | | } |
490 | | }; |
491 | | } |
492 | | |
493 | | /// Get the value needed to adjust the ordinal day for Sunday and Monday-based week |
494 | | /// numbering. |
495 | 0 | const fn adjustment(year: i32) -> i16 { |
496 | 0 | match Date::__from_ordinal_date_unchecked(year, 1).weekday() { |
497 | 0 | Weekday::Monday => 7, |
498 | 0 | Weekday::Tuesday => 1, |
499 | 0 | Weekday::Wednesday => 2, |
500 | 0 | Weekday::Thursday => 3, |
501 | 0 | Weekday::Friday => 4, |
502 | 0 | Weekday::Saturday => 5, |
503 | 0 | Weekday::Sunday => 6, |
504 | | } |
505 | 0 | } |
506 | | |
507 | | // TODO Only the basics have been covered. There are many other valid values that are not |
508 | | // currently constructed from the information known. |
509 | | |
510 | 0 | match_! { |
511 | 0 | (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?), |
512 | 0 | (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?), |
513 | 0 | (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date( |
514 | 0 | iso_year, |
515 | 0 | iso_week_number.get(), |
516 | 0 | weekday, |
517 | 0 | )?), |
518 | 0 | (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date( |
519 | 0 | year, |
520 | 0 | (sunday_week_number as i16 * 7 + weekday.number_days_from_sunday() as i16 |
521 | 0 | - adjustment(year) |
522 | 0 | + 1) as u16, |
523 | 0 | )?), |
524 | 0 | (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date( |
525 | 0 | year, |
526 | 0 | (monday_week_number as i16 * 7 + weekday.number_days_from_monday() as i16 |
527 | 0 | - adjustment(year) |
528 | 0 | + 1) as u16, |
529 | 0 | )?), |
530 | 0 | _ => Err(InsufficientInformation), |
531 | | } |
532 | 0 | } |
533 | | } |
534 | | |
535 | | impl TryFrom<Parsed> for Time { |
536 | | type Error = error::TryFromParsed; |
537 | | |
538 | 0 | fn try_from(parsed: Parsed) -> Result<Self, Self::Error> { |
539 | 0 | let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) { |
540 | 0 | (Some(hour), _, _) => hour, |
541 | 0 | (_, Some(hour), Some(false)) if hour.get() == 12 => 0, |
542 | 0 | (_, Some(hour), Some(true)) if hour.get() == 12 => 12, |
543 | 0 | (_, Some(hour), Some(false)) => hour.get(), |
544 | 0 | (_, Some(hour), Some(true)) => hour.get() + 12, |
545 | 0 | _ => return Err(InsufficientInformation), |
546 | | }; |
547 | 0 | if parsed.hour_24().is_none() |
548 | 0 | && parsed.hour_12().is_some() |
549 | 0 | && parsed.hour_12_is_pm().is_some() |
550 | 0 | && parsed.minute().is_none() |
551 | 0 | && parsed.second().is_none() |
552 | 0 | && parsed.subsecond().is_none() |
553 | | { |
554 | 0 | return Ok(Self::from_hms_nano(hour, 0, 0, 0)?); |
555 | 0 | } |
556 | 0 | let minute = parsed.minute().ok_or(InsufficientInformation)?; |
557 | 0 | let second = parsed.second().unwrap_or(0); |
558 | 0 | let subsecond = parsed.subsecond().unwrap_or(0); |
559 | 0 | Ok(Self::from_hms_nano(hour, minute, second, subsecond)?) |
560 | 0 | } |
561 | | } |
562 | | |
563 | | impl TryFrom<Parsed> for UtcOffset { |
564 | | type Error = error::TryFromParsed; |
565 | | |
566 | 0 | fn try_from(parsed: Parsed) -> Result<Self, Self::Error> { |
567 | 0 | let hour = parsed.offset_hour().ok_or(InsufficientInformation)?; |
568 | 0 | let minute = parsed.offset_minute_signed().unwrap_or(0); |
569 | 0 | let second = parsed.offset_second_signed().unwrap_or(0); |
570 | | |
571 | 0 | Self::from_hms(hour, minute, second).map_err(|mut err| { |
572 | | // Provide the user a more accurate error. |
573 | 0 | if err.name == "hours" { |
574 | 0 | err.name = "offset hour"; |
575 | 0 | } else if err.name == "minutes" { |
576 | 0 | err.name = "offset minute"; |
577 | 0 | } else if err.name == "seconds" { |
578 | 0 | err.name = "offset second"; |
579 | 0 | } |
580 | 0 | err.into() |
581 | 0 | }) |
582 | 0 | } |
583 | | } |
584 | | |
585 | | impl TryFrom<Parsed> for PrimitiveDateTime { |
586 | | type Error = error::TryFromParsed; |
587 | | |
588 | 0 | fn try_from(parsed: Parsed) -> Result<Self, Self::Error> { |
589 | 0 | Ok(Self::new(parsed.try_into()?, parsed.try_into()?)) |
590 | 0 | } |
591 | | } |
592 | | |
593 | | impl TryFrom<Parsed> for OffsetDateTime { |
594 | | type Error = error::TryFromParsed; |
595 | | |
596 | | #[allow(clippy::unwrap_in_result)] // We know the values are valid. |
597 | 0 | fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> { |
598 | | // Some well-known formats explicitly allow leap seconds. We don't currently support them, |
599 | | // so treat it as the nearest preceding moment that can be represented. Because leap seconds |
600 | | // always fall at the end of a month UTC, reject any that are at other times. |
601 | 0 | let leap_second_input = if parsed.leap_second_allowed() && parsed.second() == Some(60) { |
602 | 0 | parsed.set_second(59).expect("59 is a valid second"); |
603 | 0 | parsed |
604 | 0 | .set_subsecond(999_999_999) |
605 | 0 | .expect("999_999_999 is a valid subsecond"); |
606 | 0 | true |
607 | | } else { |
608 | 0 | false |
609 | | }; |
610 | 0 | let dt = PrimitiveDateTime::try_from(parsed)?.assume_offset(parsed.try_into()?); |
611 | 0 | if leap_second_input && !dt.is_valid_leap_second_stand_in() { |
612 | 0 | return Err(error::TryFromParsed::ComponentRange( |
613 | 0 | error::ComponentRange { |
614 | 0 | name: "second", |
615 | 0 | minimum: 0, |
616 | 0 | maximum: 59, |
617 | 0 | value: 60, |
618 | 0 | conditional_range: true, |
619 | 0 | }, |
620 | 0 | )); |
621 | 0 | } |
622 | 0 | Ok(dt) |
623 | 0 | } |
624 | | } |