• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This is a part of Chrono.
2 // See README.md and LICENSE.txt for details.
3 
4 //! A collection of parsed date and time items.
5 //! They can be constructed incrementally while being checked for consistency.
6 
7 use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
8 use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
9 use crate::offset::{FixedOffset, MappedLocalTime, Offset, TimeZone};
10 use crate::{DateTime, Datelike, TimeDelta, Timelike, Weekday};
11 
12 /// A type to hold parsed fields of date and time that can check all fields are consistent.
13 ///
14 /// There are three classes of methods:
15 ///
16 /// - `set_*` methods to set fields you have available. They do a basic range check, and if the
17 ///   same field is set more than once it is checked for consistency.
18 ///
19 /// - `to_*` methods try to make a concrete date and time value out of set fields.
20 ///   They fully check that all fields are consistent and whether the date/datetime exists.
21 ///
22 /// - Methods to inspect the parsed fields.
23 ///
24 /// `Parsed` is used internally by all parsing functions in chrono. It is a public type so that it
25 /// can be used to write custom parsers that reuse the resolving algorithm, or to inspect the
26 /// results of a string parsed with chrono without converting it to concrete types.
27 ///
28 /// # Resolving algorithm
29 ///
30 /// Resolving date/time parts is littered with lots of corner cases, which is why common date/time
31 /// parsers do not implement it correctly.
32 ///
33 /// Chrono provides a complete resolution algorithm that checks all fields for consistency via the
34 /// `Parsed` type.
35 ///
36 /// As an easy example, consider RFC 2822. The [RFC 2822 date and time format] has a day of the week
37 /// part, which should be consistent with the other date parts. But a `strptime`-based parse would
38 /// happily accept inconsistent input:
39 ///
40 /// ```python
41 /// >>> import time
42 /// >>> time.strptime('Wed, 31 Dec 2014 04:26:40 +0000',
43 ///                   '%a, %d %b %Y %H:%M:%S +0000')
44 /// time.struct_time(tm_year=2014, tm_mon=12, tm_mday=31,
45 ///                  tm_hour=4, tm_min=26, tm_sec=40,
46 ///                  tm_wday=2, tm_yday=365, tm_isdst=-1)
47 /// >>> time.strptime('Thu, 31 Dec 2014 04:26:40 +0000',
48 ///                   '%a, %d %b %Y %H:%M:%S +0000')
49 /// time.struct_time(tm_year=2014, tm_mon=12, tm_mday=31,
50 ///                  tm_hour=4, tm_min=26, tm_sec=40,
51 ///                  tm_wday=3, tm_yday=365, tm_isdst=-1)
52 /// ```
53 ///
54 /// [RFC 2822 date and time format]: https://tools.ietf.org/html/rfc2822#section-3.3
55 ///
56 /// # Example
57 ///
58 /// Let's see how `Parsed` correctly detects the second RFC 2822 string from before is inconsistent.
59 ///
60 /// ```
61 /// # #[cfg(feature = "alloc")] {
62 /// use chrono::format::{ParseErrorKind, Parsed};
63 /// use chrono::Weekday;
64 ///
65 /// let mut parsed = Parsed::new();
66 /// parsed.set_weekday(Weekday::Wed)?;
67 /// parsed.set_day(31)?;
68 /// parsed.set_month(12)?;
69 /// parsed.set_year(2014)?;
70 /// parsed.set_hour(4)?;
71 /// parsed.set_minute(26)?;
72 /// parsed.set_second(40)?;
73 /// parsed.set_offset(0)?;
74 /// let dt = parsed.to_datetime()?;
75 /// assert_eq!(dt.to_rfc2822(), "Wed, 31 Dec 2014 04:26:40 +0000");
76 ///
77 /// let mut parsed = Parsed::new();
78 /// parsed.set_weekday(Weekday::Thu)?; // changed to the wrong day
79 /// parsed.set_day(31)?;
80 /// parsed.set_month(12)?;
81 /// parsed.set_year(2014)?;
82 /// parsed.set_hour(4)?;
83 /// parsed.set_minute(26)?;
84 /// parsed.set_second(40)?;
85 /// parsed.set_offset(0)?;
86 /// let result = parsed.to_datetime();
87 ///
88 /// assert!(result.is_err());
89 /// if let Err(error) = result {
90 ///     assert_eq!(error.kind(), ParseErrorKind::Impossible);
91 /// }
92 /// # }
93 /// # Ok::<(), chrono::ParseError>(())
94 /// ```
95 ///
96 /// The same using chrono's build-in parser for RFC 2822 (the [RFC2822 formatting item]) and
97 /// [`format::parse()`] showing how to inspect a field on failure.
98 ///
99 /// [RFC2822 formatting item]: crate::format::Fixed::RFC2822
100 /// [`format::parse()`]: crate::format::parse()
101 ///
102 /// ```
103 /// # #[cfg(feature = "alloc")] {
104 /// use chrono::format::{parse, Fixed, Item, Parsed};
105 /// use chrono::Weekday;
106 ///
107 /// let rfc_2822 = [Item::Fixed(Fixed::RFC2822)];
108 ///
109 /// let mut parsed = Parsed::new();
110 /// parse(&mut parsed, "Wed, 31 Dec 2014 04:26:40 +0000", rfc_2822.iter())?;
111 /// let dt = parsed.to_datetime()?;
112 ///
113 /// assert_eq!(dt.to_rfc2822(), "Wed, 31 Dec 2014 04:26:40 +0000");
114 ///
115 /// let mut parsed = Parsed::new();
116 /// parse(&mut parsed, "Thu, 31 Dec 2014 04:26:40 +0000", rfc_2822.iter())?;
117 /// let result = parsed.to_datetime();
118 ///
119 /// assert!(result.is_err());
120 /// if result.is_err() {
121 ///     // What is the weekday?
122 ///     assert_eq!(parsed.weekday(), Some(Weekday::Thu));
123 /// }
124 /// # }
125 /// # Ok::<(), chrono::ParseError>(())
126 /// ```
127 #[allow(clippy::manual_non_exhaustive)]
128 #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
129 pub struct Parsed {
130     #[doc(hidden)]
131     pub year: Option<i32>,
132     #[doc(hidden)]
133     pub year_div_100: Option<i32>,
134     #[doc(hidden)]
135     pub year_mod_100: Option<i32>,
136     #[doc(hidden)]
137     pub isoyear: Option<i32>,
138     #[doc(hidden)]
139     pub isoyear_div_100: Option<i32>,
140     #[doc(hidden)]
141     pub isoyear_mod_100: Option<i32>,
142     #[doc(hidden)]
143     pub month: Option<u32>,
144     #[doc(hidden)]
145     pub week_from_sun: Option<u32>,
146     #[doc(hidden)]
147     pub week_from_mon: Option<u32>,
148     #[doc(hidden)]
149     pub isoweek: Option<u32>,
150     #[doc(hidden)]
151     pub weekday: Option<Weekday>,
152     #[doc(hidden)]
153     pub ordinal: Option<u32>,
154     #[doc(hidden)]
155     pub day: Option<u32>,
156     #[doc(hidden)]
157     pub hour_div_12: Option<u32>,
158     #[doc(hidden)]
159     pub hour_mod_12: Option<u32>,
160     #[doc(hidden)]
161     pub minute: Option<u32>,
162     #[doc(hidden)]
163     pub second: Option<u32>,
164     #[doc(hidden)]
165     pub nanosecond: Option<u32>,
166     #[doc(hidden)]
167     pub timestamp: Option<i64>,
168     #[doc(hidden)]
169     pub offset: Option<i32>,
170     #[doc(hidden)]
171     _dummy: (),
172 }
173 
174 /// Checks if `old` is either empty or has the same value as `new` (i.e. "consistent"),
175 /// and if it is empty, set `old` to `new` as well.
176 #[inline]
set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<()>177 fn set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<()> {
178     if let Some(ref old) = *old {
179         if *old == new {
180             Ok(())
181         } else {
182             Err(IMPOSSIBLE)
183         }
184     } else {
185         *old = Some(new);
186         Ok(())
187     }
188 }
189 
190 impl Parsed {
191     /// Returns the initial value of parsed parts.
192     #[must_use]
new() -> Parsed193     pub fn new() -> Parsed {
194         Parsed::default()
195     }
196 
197     /// Set the [`year`](Parsed::year) field to the given value.
198     ///
199     /// The value can be negative, unlike the [`year_div_100`](Parsed::year_div_100) and
200     /// [`year_mod_100`](Parsed::year_mod_100) fields.
201     ///
202     /// # Errors
203     ///
204     /// Returns `OUT_OF_RANGE` if `value` is outside the range of an `i32`.
205     ///
206     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
207     #[inline]
set_year(&mut self, value: i64) -> ParseResult<()>208     pub fn set_year(&mut self, value: i64) -> ParseResult<()> {
209         set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
210     }
211 
212     /// Set the [`year_div_100`](Parsed::year_div_100) field to the given value.
213     ///
214     /// # Errors
215     ///
216     /// Returns `OUT_OF_RANGE` if `value` is negative or if it is greater than `i32::MAX`.
217     ///
218     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
219     #[inline]
set_year_div_100(&mut self, value: i64) -> ParseResult<()>220     pub fn set_year_div_100(&mut self, value: i64) -> ParseResult<()> {
221         if !(0..=i32::MAX as i64).contains(&value) {
222             return Err(OUT_OF_RANGE);
223         }
224         set_if_consistent(&mut self.year_div_100, value as i32)
225     }
226 
227     /// Set the [`year_mod_100`](Parsed::year_mod_100) field to the given value.
228     ///
229     /// When set it implies that the year is not negative.
230     ///
231     /// If this field is set while the [`year_div_100`](Parsed::year_div_100) field is missing (and
232     /// the full [`year`](Parsed::year) field is also not set), it assumes a default value for the
233     /// [`year_div_100`](Parsed::year_div_100) field.
234     /// The default is 19 when `year_mod_100 >= 70` and 20 otherwise.
235     ///
236     /// # Errors
237     ///
238     /// Returns `OUT_OF_RANGE` if `value` is negative or if it is greater than 99.
239     ///
240     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
241     #[inline]
set_year_mod_100(&mut self, value: i64) -> ParseResult<()>242     pub fn set_year_mod_100(&mut self, value: i64) -> ParseResult<()> {
243         if !(0..100).contains(&value) {
244             return Err(OUT_OF_RANGE);
245         }
246         set_if_consistent(&mut self.year_mod_100, value as i32)
247     }
248 
249     /// Set the [`isoyear`](Parsed::isoyear) field, that is part of an [ISO 8601 week date], to the
250     /// given value.
251     ///
252     /// The value can be negative, unlike the [`isoyear_div_100`](Parsed::isoyear_div_100) and
253     /// [`isoyear_mod_100`](Parsed::isoyear_mod_100) fields.
254     ///
255     /// [ISO 8601 week date]: crate::NaiveDate#week-date
256     ///
257     /// # Errors
258     ///
259     /// Returns `OUT_OF_RANGE` if `value` is outside the range of an `i32`.
260     ///
261     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
262     #[inline]
set_isoyear(&mut self, value: i64) -> ParseResult<()>263     pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> {
264         set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
265     }
266 
267     /// Set the [`isoyear_div_100`](Parsed::isoyear_div_100) field, that is part of an
268     /// [ISO 8601 week date], to the given value.
269     ///
270     /// [ISO 8601 week date]: crate::NaiveDate#week-date
271     ///
272     /// # Errors
273     ///
274     /// Returns `OUT_OF_RANGE` if `value` is negative or if it is greater than `i32::MAX`.
275     ///
276     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
277     #[inline]
set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()>278     pub fn set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()> {
279         if !(0..=i32::MAX as i64).contains(&value) {
280             return Err(OUT_OF_RANGE);
281         }
282         set_if_consistent(&mut self.isoyear_div_100, value as i32)
283     }
284 
285     /// Set the [`isoyear_mod_100`](Parsed::isoyear_mod_100) field, that is part of an
286     /// [ISO 8601 week date], to the given value.
287     ///
288     /// When set it implies that the year is not negative.
289     ///
290     /// If this field is set while the [`isoyear_div_100`](Parsed::isoyear_div_100) field is missing
291     /// (and the full [`isoyear`](Parsed::isoyear) field is also not set), it assumes a default
292     /// value for the [`isoyear_div_100`](Parsed::isoyear_div_100) field.
293     /// The default is 19 when `year_mod_100 >= 70` and 20 otherwise.
294     ///
295     /// [ISO 8601 week date]: crate::NaiveDate#week-date
296     ///
297     /// # Errors
298     ///
299     /// Returns `OUT_OF_RANGE` if `value` is negative or if it is greater than 99.
300     ///
301     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
302     #[inline]
set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()>303     pub fn set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()> {
304         if !(0..100).contains(&value) {
305             return Err(OUT_OF_RANGE);
306         }
307         set_if_consistent(&mut self.isoyear_mod_100, value as i32)
308     }
309 
310     /// Set the [`month`](Parsed::month) field to the given value.
311     ///
312     /// # Errors
313     ///
314     /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-12.
315     ///
316     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
317     #[inline]
set_month(&mut self, value: i64) -> ParseResult<()>318     pub fn set_month(&mut self, value: i64) -> ParseResult<()> {
319         if !(1..=12).contains(&value) {
320             return Err(OUT_OF_RANGE);
321         }
322         set_if_consistent(&mut self.month, value as u32)
323     }
324 
325     /// Set the [`week_from_sun`](Parsed::week_from_sun) week number field to the given value.
326     ///
327     /// Week 1 starts at the first Sunday of January.
328     ///
329     /// # Errors
330     ///
331     /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-53.
332     ///
333     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
334     #[inline]
set_week_from_sun(&mut self, value: i64) -> ParseResult<()>335     pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> {
336         if !(0..=53).contains(&value) {
337             return Err(OUT_OF_RANGE);
338         }
339         set_if_consistent(&mut self.week_from_sun, value as u32)
340     }
341 
342     /// Set the [`week_from_mon`](Parsed::week_from_mon) week number field to the given value.
343     /// Set the 'week number starting with Monday' field to the given value.
344     ///
345     /// Week 1 starts at the first Monday of January.
346     ///
347     /// # Errors
348     ///
349     /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-53.
350     ///
351     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
352     #[inline]
set_week_from_mon(&mut self, value: i64) -> ParseResult<()>353     pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> {
354         if !(0..=53).contains(&value) {
355             return Err(OUT_OF_RANGE);
356         }
357         set_if_consistent(&mut self.week_from_mon, value as u32)
358     }
359 
360     /// Set the [`isoweek`](Parsed::isoweek) field for an [ISO 8601 week date] to the given value.
361     ///
362     /// [ISO 8601 week date]: crate::NaiveDate#week-date
363     ///
364     /// # Errors
365     ///
366     /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-53.
367     ///
368     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
369     #[inline]
set_isoweek(&mut self, value: i64) -> ParseResult<()>370     pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> {
371         if !(1..=53).contains(&value) {
372             return Err(OUT_OF_RANGE);
373         }
374         set_if_consistent(&mut self.isoweek, value as u32)
375     }
376 
377     /// Set the [`weekday`](Parsed::weekday) field to the given value.
378     ///
379     /// # Errors
380     ///
381     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
382     #[inline]
set_weekday(&mut self, value: Weekday) -> ParseResult<()>383     pub fn set_weekday(&mut self, value: Weekday) -> ParseResult<()> {
384         set_if_consistent(&mut self.weekday, value)
385     }
386 
387     /// Set the [`ordinal`](Parsed::ordinal) (day of the year) field to the given value.
388     ///
389     /// # Errors
390     ///
391     /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-366.
392     ///
393     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
394     #[inline]
set_ordinal(&mut self, value: i64) -> ParseResult<()>395     pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> {
396         if !(1..=366).contains(&value) {
397             return Err(OUT_OF_RANGE);
398         }
399         set_if_consistent(&mut self.ordinal, value as u32)
400     }
401 
402     /// Set the [`day`](Parsed::day) of the month field to the given value.
403     ///
404     /// # Errors
405     ///
406     /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-31.
407     ///
408     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
409     #[inline]
set_day(&mut self, value: i64) -> ParseResult<()>410     pub fn set_day(&mut self, value: i64) -> ParseResult<()> {
411         if !(1..=31).contains(&value) {
412             return Err(OUT_OF_RANGE);
413         }
414         set_if_consistent(&mut self.day, value as u32)
415     }
416 
417     /// Set the [`hour_div_12`](Parsed::hour_div_12) am/pm field to the given value.
418     ///
419     /// `false` indicates AM and `true` indicates PM.
420     ///
421     /// # Errors
422     ///
423     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
424     #[inline]
set_ampm(&mut self, value: bool) -> ParseResult<()>425     pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> {
426         set_if_consistent(&mut self.hour_div_12, value as u32)
427     }
428 
429     /// Set the [`hour_mod_12`](Parsed::hour_mod_12) field, for the hour number in 12-hour clocks,
430     /// to the given value.
431     ///
432     /// Value must be in the canonical range of 1-12.
433     /// It will internally be stored as 0-11 (`value % 12`).
434     ///
435     /// # Errors
436     ///
437     /// Returns `OUT_OF_RANGE` if `value` is not in the range 1-12.
438     ///
439     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
440     #[inline]
set_hour12(&mut self, mut value: i64) -> ParseResult<()>441     pub fn set_hour12(&mut self, mut value: i64) -> ParseResult<()> {
442         if !(1..=12).contains(&value) {
443             return Err(OUT_OF_RANGE);
444         }
445         if value == 12 {
446             value = 0
447         }
448         set_if_consistent(&mut self.hour_mod_12, value as u32)
449     }
450 
451     /// Set the [`hour_div_12`](Parsed::hour_div_12) and [`hour_mod_12`](Parsed::hour_mod_12)
452     /// fields to the given value for a 24-hour clock.
453     ///
454     /// # Errors
455     ///
456     /// May return `OUT_OF_RANGE` if `value` is not in the range 0-23.
457     /// Currently only checks the value is not out of range for a `u32`.
458     ///
459     /// Returns `IMPOSSIBLE` one of the fields was already set to a different value.
460     #[inline]
set_hour(&mut self, value: i64) -> ParseResult<()>461     pub fn set_hour(&mut self, value: i64) -> ParseResult<()> {
462         let (hour_div_12, hour_mod_12) = match value {
463             hour @ 0..=11 => (0, hour as u32),
464             hour @ 12..=23 => (1, hour as u32 - 12),
465             _ => return Err(OUT_OF_RANGE),
466         };
467         set_if_consistent(&mut self.hour_div_12, hour_div_12)?;
468         set_if_consistent(&mut self.hour_mod_12, hour_mod_12)
469     }
470 
471     /// Set the [`minute`](Parsed::minute) field to the given value.
472     ///
473     /// # Errors
474     ///
475     /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-59.
476     ///
477     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
478     #[inline]
set_minute(&mut self, value: i64) -> ParseResult<()>479     pub fn set_minute(&mut self, value: i64) -> ParseResult<()> {
480         if !(0..=59).contains(&value) {
481             return Err(OUT_OF_RANGE);
482         }
483         set_if_consistent(&mut self.minute, value as u32)
484     }
485 
486     /// Set the [`second`](Parsed::second) field to the given value.
487     ///
488     /// The value can be 60 in the case of a leap second.
489     ///
490     /// # Errors
491     ///
492     /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-60.
493     ///
494     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
495     #[inline]
set_second(&mut self, value: i64) -> ParseResult<()>496     pub fn set_second(&mut self, value: i64) -> ParseResult<()> {
497         if !(0..=60).contains(&value) {
498             return Err(OUT_OF_RANGE);
499         }
500         set_if_consistent(&mut self.second, value as u32)
501     }
502 
503     /// Set the [`nanosecond`](Parsed::nanosecond) field to the given value.
504     ///
505     /// This is the number of nanoseconds since the whole second.
506     ///
507     /// # Errors
508     ///
509     /// Returns `OUT_OF_RANGE` if `value` is not in the range 0-999,999,999.
510     ///
511     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
512     #[inline]
set_nanosecond(&mut self, value: i64) -> ParseResult<()>513     pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> {
514         if !(0..=999_999_999).contains(&value) {
515             return Err(OUT_OF_RANGE);
516         }
517         set_if_consistent(&mut self.nanosecond, value as u32)
518     }
519 
520     /// Set the [`timestamp`](Parsed::timestamp) field to the given value.
521     ///
522     /// A Unix timestamp is defined as the number of non-leap seconds since midnight UTC on
523     /// January 1, 1970.
524     ///
525     /// # Errors
526     ///
527     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
528     #[inline]
set_timestamp(&mut self, value: i64) -> ParseResult<()>529     pub fn set_timestamp(&mut self, value: i64) -> ParseResult<()> {
530         set_if_consistent(&mut self.timestamp, value)
531     }
532 
533     /// Set the [`offset`](Parsed::offset) field to the given value.
534     ///
535     /// The offset is in seconds from local time to UTC.
536     ///
537     /// # Errors
538     ///
539     /// Returns `OUT_OF_RANGE` if `value` is outside the range of an `i32`.
540     ///
541     /// Returns `IMPOSSIBLE` if this field was already set to a different value.
542     #[inline]
set_offset(&mut self, value: i64) -> ParseResult<()>543     pub fn set_offset(&mut self, value: i64) -> ParseResult<()> {
544         set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
545     }
546 
547     /// Returns a parsed naive date out of given fields.
548     ///
549     /// This method is able to determine the date from given subset of fields:
550     ///
551     /// - Year, month, day.
552     /// - Year, day of the year (ordinal).
553     /// - Year, week number counted from Sunday or Monday, day of the week.
554     /// - ISO week date.
555     ///
556     /// Gregorian year and ISO week date year can have their century number (`*_div_100`) omitted,
557     /// the two-digit year is used to guess the century number then.
558     ///
559     /// It checks all given date fields are consistent with each other.
560     ///
561     /// # Errors
562     ///
563     /// This method returns:
564     /// - `IMPOSSIBLE` if any of the date fields conflict.
565     /// - `NOT_ENOUGH` if there are not enough fields set in `Parsed` for a complete date.
566     /// - `OUT_OF_RANGE`
567     ///   - if any of the date fields of `Parsed` are set to a value beyond their acceptable range.
568     ///   - if the value would be outside the range of a [`NaiveDate`].
569     ///   - if the date does not exist.
to_naive_date(&self) -> ParseResult<NaiveDate>570     pub fn to_naive_date(&self) -> ParseResult<NaiveDate> {
571         fn resolve_year(
572             y: Option<i32>,
573             q: Option<i32>,
574             r: Option<i32>,
575         ) -> ParseResult<Option<i32>> {
576             match (y, q, r) {
577                 // if there is no further information, simply return the given full year.
578                 // this is a common case, so let's avoid division here.
579                 (y, None, None) => Ok(y),
580 
581                 // if there is a full year *and* also quotient and/or modulo,
582                 // check if present quotient and/or modulo is consistent to the full year.
583                 // since the presence of those fields means a positive full year,
584                 // we should filter a negative full year first.
585                 (Some(y), q, r @ Some(0..=99)) | (Some(y), q, r @ None) => {
586                     if y < 0 {
587                         return Err(IMPOSSIBLE);
588                     }
589                     let q_ = y / 100;
590                     let r_ = y % 100;
591                     if q.unwrap_or(q_) == q_ && r.unwrap_or(r_) == r_ {
592                         Ok(Some(y))
593                     } else {
594                         Err(IMPOSSIBLE)
595                     }
596                 }
597 
598                 // the full year is missing but we have quotient and modulo.
599                 // reconstruct the full year. make sure that the result is always positive.
600                 (None, Some(q), Some(r @ 0..=99)) => {
601                     if q < 0 {
602                         return Err(IMPOSSIBLE);
603                     }
604                     let y = q.checked_mul(100).and_then(|v| v.checked_add(r));
605                     Ok(Some(y.ok_or(OUT_OF_RANGE)?))
606                 }
607 
608                 // we only have modulo. try to interpret a modulo as a conventional two-digit year.
609                 // note: we are affected by Rust issue #18060. avoid multiple range patterns.
610                 (None, None, Some(r @ 0..=99)) => Ok(Some(r + if r < 70 { 2000 } else { 1900 })),
611 
612                 // otherwise it is an out-of-bound or insufficient condition.
613                 (None, Some(_), None) => Err(NOT_ENOUGH),
614                 (_, _, Some(_)) => Err(OUT_OF_RANGE),
615             }
616         }
617 
618         let given_year = resolve_year(self.year, self.year_div_100, self.year_mod_100)?;
619         let given_isoyear = resolve_year(self.isoyear, self.isoyear_div_100, self.isoyear_mod_100)?;
620 
621         // verify the normal year-month-day date.
622         let verify_ymd = |date: NaiveDate| {
623             let year = date.year();
624             let (year_div_100, year_mod_100) = if year >= 0 {
625                 (Some(year / 100), Some(year % 100))
626             } else {
627                 (None, None) // they should be empty to be consistent
628             };
629             let month = date.month();
630             let day = date.day();
631             self.year.unwrap_or(year) == year
632                 && self.year_div_100.or(year_div_100) == year_div_100
633                 && self.year_mod_100.or(year_mod_100) == year_mod_100
634                 && self.month.unwrap_or(month) == month
635                 && self.day.unwrap_or(day) == day
636         };
637 
638         // verify the ISO week date.
639         let verify_isoweekdate = |date: NaiveDate| {
640             let week = date.iso_week();
641             let isoyear = week.year();
642             let isoweek = week.week();
643             let weekday = date.weekday();
644             let (isoyear_div_100, isoyear_mod_100) = if isoyear >= 0 {
645                 (Some(isoyear / 100), Some(isoyear % 100))
646             } else {
647                 (None, None) // they should be empty to be consistent
648             };
649             self.isoyear.unwrap_or(isoyear) == isoyear
650                 && self.isoyear_div_100.or(isoyear_div_100) == isoyear_div_100
651                 && self.isoyear_mod_100.or(isoyear_mod_100) == isoyear_mod_100
652                 && self.isoweek.unwrap_or(isoweek) == isoweek
653                 && self.weekday.unwrap_or(weekday) == weekday
654         };
655 
656         // verify the ordinal and other (non-ISO) week dates.
657         let verify_ordinal = |date: NaiveDate| {
658             let ordinal = date.ordinal();
659             let week_from_sun = date.weeks_from(Weekday::Sun);
660             let week_from_mon = date.weeks_from(Weekday::Mon);
661             self.ordinal.unwrap_or(ordinal) == ordinal
662                 && self.week_from_sun.map_or(week_from_sun, |v| v as i32) == week_from_sun
663                 && self.week_from_mon.map_or(week_from_mon, |v| v as i32) == week_from_mon
664         };
665 
666         // test several possibilities.
667         // tries to construct a full `NaiveDate` as much as possible, then verifies that
668         // it is consistent with other given fields.
669         let (verified, parsed_date) = match (given_year, given_isoyear, self) {
670             (Some(year), _, &Parsed { month: Some(month), day: Some(day), .. }) => {
671                 // year, month, day
672                 let date = NaiveDate::from_ymd_opt(year, month, day).ok_or(OUT_OF_RANGE)?;
673                 (verify_isoweekdate(date) && verify_ordinal(date), date)
674             }
675 
676             (Some(year), _, &Parsed { ordinal: Some(ordinal), .. }) => {
677                 // year, day of the year
678                 let date = NaiveDate::from_yo_opt(year, ordinal).ok_or(OUT_OF_RANGE)?;
679                 (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
680             }
681 
682             (Some(year), _, &Parsed { week_from_sun: Some(week), weekday: Some(weekday), .. }) => {
683                 // year, week (starting at 1st Sunday), day of the week
684                 let date = resolve_week_date(year, week, weekday, Weekday::Sun)?;
685                 (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
686             }
687 
688             (Some(year), _, &Parsed { week_from_mon: Some(week), weekday: Some(weekday), .. }) => {
689                 // year, week (starting at 1st Monday), day of the week
690                 let date = resolve_week_date(year, week, weekday, Weekday::Mon)?;
691                 (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
692             }
693 
694             (_, Some(isoyear), &Parsed { isoweek: Some(isoweek), weekday: Some(weekday), .. }) => {
695                 // ISO year, week, day of the week
696                 let date = NaiveDate::from_isoywd_opt(isoyear, isoweek, weekday);
697                 let date = date.ok_or(OUT_OF_RANGE)?;
698                 (verify_ymd(date) && verify_ordinal(date), date)
699             }
700 
701             (_, _, _) => return Err(NOT_ENOUGH),
702         };
703 
704         if verified {
705             Ok(parsed_date)
706         } else {
707             Err(IMPOSSIBLE)
708         }
709     }
710 
711     /// Returns a parsed naive time out of given fields.
712     ///
713     /// This method is able to determine the time from given subset of fields:
714     ///
715     /// - Hour, minute. (second and nanosecond assumed to be 0)
716     /// - Hour, minute, second. (nanosecond assumed to be 0)
717     /// - Hour, minute, second, nanosecond.
718     ///
719     /// It is able to handle leap seconds when given second is 60.
720     ///
721     /// # Errors
722     ///
723     /// This method returns:
724     /// - `OUT_OF_RANGE` if any of the time fields of `Parsed` are set to a value beyond
725     ///   their acceptable range.
726     /// - `NOT_ENOUGH` if an hour field is missing, if AM/PM is missing in a 12-hour clock,
727     ///   if minutes are missing, or if seconds are missing while the nanosecond field is present.
to_naive_time(&self) -> ParseResult<NaiveTime>728     pub fn to_naive_time(&self) -> ParseResult<NaiveTime> {
729         let hour_div_12 = match self.hour_div_12 {
730             Some(v @ 0..=1) => v,
731             Some(_) => return Err(OUT_OF_RANGE),
732             None => return Err(NOT_ENOUGH),
733         };
734         let hour_mod_12 = match self.hour_mod_12 {
735             Some(v @ 0..=11) => v,
736             Some(_) => return Err(OUT_OF_RANGE),
737             None => return Err(NOT_ENOUGH),
738         };
739         let hour = hour_div_12 * 12 + hour_mod_12;
740 
741         let minute = match self.minute {
742             Some(v @ 0..=59) => v,
743             Some(_) => return Err(OUT_OF_RANGE),
744             None => return Err(NOT_ENOUGH),
745         };
746 
747         // we allow omitting seconds or nanoseconds, but they should be in the range.
748         let (second, mut nano) = match self.second.unwrap_or(0) {
749             v @ 0..=59 => (v, 0),
750             60 => (59, 1_000_000_000),
751             _ => return Err(OUT_OF_RANGE),
752         };
753         nano += match self.nanosecond {
754             Some(v @ 0..=999_999_999) if self.second.is_some() => v,
755             Some(0..=999_999_999) => return Err(NOT_ENOUGH), // second is missing
756             Some(_) => return Err(OUT_OF_RANGE),
757             None => 0,
758         };
759 
760         NaiveTime::from_hms_nano_opt(hour, minute, second, nano).ok_or(OUT_OF_RANGE)
761     }
762 
763     /// Returns a parsed naive date and time out of given fields, except for the offset field.
764     ///
765     /// The offset is assumed to have a given value. It is not compared against the offset field set
766     /// in the `Parsed` type, so it is allowed to be inconsistent.
767     ///
768     /// This method is able to determine the combined date and time from date and time fields or
769     /// from a single timestamp field. It checks all fields are consistent with each other.
770     ///
771     /// # Errors
772     ///
773     /// This method returns:
774     /// - `IMPOSSIBLE`  if any of the date fields conflict, or if a timestamp conflicts with any of
775     ///   the other fields.
776     /// - `NOT_ENOUGH` if there are not enough fields set in `Parsed` for a complete datetime.
777     /// - `OUT_OF_RANGE`
778     ///   - if any of the date or time fields of `Parsed` are set to a value beyond their acceptable
779     ///     range.
780     ///   - if the value would be outside the range of a [`NaiveDateTime`].
781     ///   - if the date does not exist.
to_naive_datetime_with_offset(&self, offset: i32) -> ParseResult<NaiveDateTime>782     pub fn to_naive_datetime_with_offset(&self, offset: i32) -> ParseResult<NaiveDateTime> {
783         let date = self.to_naive_date();
784         let time = self.to_naive_time();
785         if let (Ok(date), Ok(time)) = (date, time) {
786             let datetime = date.and_time(time);
787 
788             // verify the timestamp field if any
789             // the following is safe, `timestamp` is very limited in range
790             let timestamp = datetime.and_utc().timestamp() - i64::from(offset);
791             if let Some(given_timestamp) = self.timestamp {
792                 // if `datetime` represents a leap second, it might be off by one second.
793                 if given_timestamp != timestamp
794                     && !(datetime.nanosecond() >= 1_000_000_000 && given_timestamp == timestamp + 1)
795                 {
796                     return Err(IMPOSSIBLE);
797                 }
798             }
799 
800             Ok(datetime)
801         } else if let Some(timestamp) = self.timestamp {
802             use super::ParseError as PE;
803             use super::ParseErrorKind::{Impossible, OutOfRange};
804 
805             // if date and time is problematic already, there is no point proceeding.
806             // we at least try to give a correct error though.
807             match (date, time) {
808                 (Err(PE(OutOfRange)), _) | (_, Err(PE(OutOfRange))) => return Err(OUT_OF_RANGE),
809                 (Err(PE(Impossible)), _) | (_, Err(PE(Impossible))) => return Err(IMPOSSIBLE),
810                 (_, _) => {} // one of them is insufficient
811             }
812 
813             // reconstruct date and time fields from timestamp
814             let ts = timestamp.checked_add(i64::from(offset)).ok_or(OUT_OF_RANGE)?;
815             let mut datetime = DateTime::from_timestamp(ts, 0).ok_or(OUT_OF_RANGE)?.naive_utc();
816 
817             // fill year, ordinal, hour, minute and second fields from timestamp.
818             // if existing fields are consistent, this will allow the full date/time reconstruction.
819             let mut parsed = self.clone();
820             if parsed.second == Some(60) {
821                 // `datetime.second()` cannot be 60, so this is the only case for a leap second.
822                 match datetime.second() {
823                     // it's okay, just do not try to overwrite the existing field.
824                     59 => {}
825                     // `datetime` is known to be off by one second.
826                     0 => {
827                         datetime -= TimeDelta::try_seconds(1).unwrap();
828                     }
829                     // otherwise it is impossible.
830                     _ => return Err(IMPOSSIBLE),
831                 }
832             // ...and we have the correct candidates for other fields.
833             } else {
834                 parsed.set_second(i64::from(datetime.second()))?;
835             }
836             parsed.set_year(i64::from(datetime.year()))?;
837             parsed.set_ordinal(i64::from(datetime.ordinal()))?; // more efficient than ymd
838             parsed.set_hour(i64::from(datetime.hour()))?;
839             parsed.set_minute(i64::from(datetime.minute()))?;
840 
841             // validate other fields (e.g. week) and return
842             let date = parsed.to_naive_date()?;
843             let time = parsed.to_naive_time()?;
844             Ok(date.and_time(time))
845         } else {
846             // reproduce the previous error(s)
847             date?;
848             time?;
849             unreachable!()
850         }
851     }
852 
853     /// Returns a parsed fixed time zone offset out of given fields.
854     ///
855     /// # Errors
856     ///
857     /// This method returns:
858     /// - `OUT_OF_RANGE` if the offset is out of range for a `FixedOffset`.
859     /// - `NOT_ENOUGH` if the offset field is not set.
to_fixed_offset(&self) -> ParseResult<FixedOffset>860     pub fn to_fixed_offset(&self) -> ParseResult<FixedOffset> {
861         FixedOffset::east_opt(self.offset.ok_or(NOT_ENOUGH)?).ok_or(OUT_OF_RANGE)
862     }
863 
864     /// Returns a parsed timezone-aware date and time out of given fields.
865     ///
866     /// This method is able to determine the combined date and time from date, time and offset
867     /// fields, and/or from a single timestamp field. It checks all fields are consistent with each
868     /// other.
869     ///
870     /// # Errors
871     ///
872     /// This method returns:
873     /// - `IMPOSSIBLE`  if any of the date fields conflict, or if a timestamp conflicts with any of
874     ///   the other fields.
875     /// - `NOT_ENOUGH` if there are not enough fields set in `Parsed` for a complete datetime
876     ///   including offset from UTC.
877     /// - `OUT_OF_RANGE`
878     ///   - if any of the fields of `Parsed` are set to a value beyond their acceptable
879     ///     range.
880     ///   - if the value would be outside the range of a [`NaiveDateTime`] or [`FixedOffset`].
881     ///   - if the date does not exist.
to_datetime(&self) -> ParseResult<DateTime<FixedOffset>>882     pub fn to_datetime(&self) -> ParseResult<DateTime<FixedOffset>> {
883         // If there is no explicit offset, consider a timestamp value as indication of a UTC value.
884         let offset = match (self.offset, self.timestamp) {
885             (Some(off), _) => off,
886             (None, Some(_)) => 0, // UNIX timestamp may assume 0 offset
887             (None, None) => return Err(NOT_ENOUGH),
888         };
889         let datetime = self.to_naive_datetime_with_offset(offset)?;
890         let offset = FixedOffset::east_opt(offset).ok_or(OUT_OF_RANGE)?;
891 
892         match offset.from_local_datetime(&datetime) {
893             MappedLocalTime::None => Err(IMPOSSIBLE),
894             MappedLocalTime::Single(t) => Ok(t),
895             MappedLocalTime::Ambiguous(..) => Err(NOT_ENOUGH),
896         }
897     }
898 
899     /// Returns a parsed timezone-aware date and time out of given fields,
900     /// with an additional [`TimeZone`] used to interpret and validate the local date.
901     ///
902     /// This method is able to determine the combined date and time from date and time, and/or from
903     /// a single timestamp field. It checks all fields are consistent with each other.
904     ///
905     /// If the parsed fields include an UTC offset, it also has to be consistent with the offset in
906     /// the provided `tz` time zone for that datetime.
907     ///
908     /// # Errors
909     ///
910     /// This method returns:
911     /// - `IMPOSSIBLE`
912     ///   - if any of the date fields conflict, if a timestamp conflicts with any of the other
913     ///     fields, or if the offset field is set but differs from the offset at that time in the
914     ///     `tz` time zone.
915     ///   - if the local datetime does not exists in the provided time zone (because it falls in a
916     ///     transition due to for example DST).
917     /// - `NOT_ENOUGH` if there are not enough fields set in `Parsed` for a complete datetime, or if
918     ///   the local time in the provided time zone is ambiguous (because it falls in a transition
919     ///   due to for example DST) while there is no offset field or timestamp field set.
920     /// - `OUT_OF_RANGE`
921     ///   - if the value would be outside the range of a [`NaiveDateTime`] or [`FixedOffset`].
922     ///   - if any of the fields of `Parsed` are set to a value beyond their acceptable range.
923     ///   - if the date does not exist.
to_datetime_with_timezone<Tz: TimeZone>(&self, tz: &Tz) -> ParseResult<DateTime<Tz>>924     pub fn to_datetime_with_timezone<Tz: TimeZone>(&self, tz: &Tz) -> ParseResult<DateTime<Tz>> {
925         // if we have `timestamp` specified, guess an offset from that.
926         let mut guessed_offset = 0;
927         if let Some(timestamp) = self.timestamp {
928             // make a naive `DateTime` from given timestamp and (if any) nanosecond.
929             // an empty `nanosecond` is always equal to zero, so missing nanosecond is fine.
930             let nanosecond = self.nanosecond.unwrap_or(0);
931             let dt =
932                 DateTime::from_timestamp(timestamp, nanosecond).ok_or(OUT_OF_RANGE)?.naive_utc();
933             guessed_offset = tz.offset_from_utc_datetime(&dt).fix().local_minus_utc();
934         }
935 
936         // checks if the given `DateTime` has a consistent `Offset` with given `self.offset`.
937         let check_offset = |dt: &DateTime<Tz>| {
938             if let Some(offset) = self.offset {
939                 dt.offset().fix().local_minus_utc() == offset
940             } else {
941                 true
942             }
943         };
944 
945         // `guessed_offset` should be correct when `self.timestamp` is given.
946         // it will be 0 otherwise, but this is fine as the algorithm ignores offset for that case.
947         let datetime = self.to_naive_datetime_with_offset(guessed_offset)?;
948         match tz.from_local_datetime(&datetime) {
949             MappedLocalTime::None => Err(IMPOSSIBLE),
950             MappedLocalTime::Single(t) => {
951                 if check_offset(&t) {
952                     Ok(t)
953                 } else {
954                     Err(IMPOSSIBLE)
955                 }
956             }
957             MappedLocalTime::Ambiguous(min, max) => {
958                 // try to disambiguate two possible local dates by offset.
959                 match (check_offset(&min), check_offset(&max)) {
960                     (false, false) => Err(IMPOSSIBLE),
961                     (false, true) => Ok(max),
962                     (true, false) => Ok(min),
963                     (true, true) => Err(NOT_ENOUGH),
964                 }
965             }
966         }
967     }
968 
969     /// Get the `year` field if set.
970     ///
971     /// See also [`set_year()`](Parsed::set_year).
972     #[inline]
year(&self) -> Option<i32>973     pub fn year(&self) -> Option<i32> {
974         self.year
975     }
976 
977     /// Get the `year_div_100` field if set.
978     ///
979     /// See also [`set_year_div_100()`](Parsed::set_year_div_100).
980     #[inline]
year_div_100(&self) -> Option<i32>981     pub fn year_div_100(&self) -> Option<i32> {
982         self.year_div_100
983     }
984 
985     /// Get the `year_mod_100` field if set.
986     ///
987     /// See also [`set_year_mod_100()`](Parsed::set_year_mod_100).
988     #[inline]
year_mod_100(&self) -> Option<i32>989     pub fn year_mod_100(&self) -> Option<i32> {
990         self.year_mod_100
991     }
992 
993     /// Get the `isoyear` field that is part of an [ISO 8601 week date] if set.
994     ///
995     /// See also [`set_isoyear()`](Parsed::set_isoyear).
996     ///
997     /// [ISO 8601 week date]: crate::NaiveDate#week-date
998     #[inline]
isoyear(&self) -> Option<i32>999     pub fn isoyear(&self) -> Option<i32> {
1000         self.isoyear
1001     }
1002 
1003     /// Get the `isoyear_div_100` field that is part of an [ISO 8601 week date] if set.
1004     ///
1005     /// See also [`set_isoyear_div_100()`](Parsed::set_isoyear_div_100).
1006     ///
1007     /// [ISO 8601 week date]: crate::NaiveDate#week-date
1008     #[inline]
isoyear_div_100(&self) -> Option<i32>1009     pub fn isoyear_div_100(&self) -> Option<i32> {
1010         self.isoyear_div_100
1011     }
1012 
1013     /// Get the `isoyear_mod_100` field that is part of an [ISO 8601 week date] if set.
1014     ///
1015     /// See also [`set_isoyear_mod_100()`](Parsed::set_isoyear_mod_100).
1016     ///
1017     /// [ISO 8601 week date]: crate::NaiveDate#week-date
1018     #[inline]
isoyear_mod_100(&self) -> Option<i32>1019     pub fn isoyear_mod_100(&self) -> Option<i32> {
1020         self.isoyear_mod_100
1021     }
1022 
1023     /// Get the `month` field if set.
1024     ///
1025     /// See also [`set_month()`](Parsed::set_month).
1026     #[inline]
month(&self) -> Option<u32>1027     pub fn month(&self) -> Option<u32> {
1028         self.month
1029     }
1030 
1031     /// Get the `week_from_sun` field if set.
1032     ///
1033     /// See also [`set_week_from_sun()`](Parsed::set_week_from_sun).
1034     #[inline]
week_from_sun(&self) -> Option<u32>1035     pub fn week_from_sun(&self) -> Option<u32> {
1036         self.week_from_sun
1037     }
1038 
1039     /// Get the `week_from_mon` field if set.
1040     ///
1041     /// See also [`set_week_from_mon()`](Parsed::set_week_from_mon).
1042     #[inline]
week_from_mon(&self) -> Option<u32>1043     pub fn week_from_mon(&self) -> Option<u32> {
1044         self.week_from_mon
1045     }
1046 
1047     /// Get the `isoweek` field that is part of an [ISO 8601 week date] if set.
1048     ///
1049     /// See also [`set_isoweek()`](Parsed::set_isoweek).
1050     ///
1051     /// [ISO 8601 week date]: crate::NaiveDate#week-date
1052     #[inline]
isoweek(&self) -> Option<u32>1053     pub fn isoweek(&self) -> Option<u32> {
1054         self.isoweek
1055     }
1056 
1057     /// Get the `weekday` field if set.
1058     ///
1059     /// See also [`set_weekday()`](Parsed::set_weekday).
1060     #[inline]
weekday(&self) -> Option<Weekday>1061     pub fn weekday(&self) -> Option<Weekday> {
1062         self.weekday
1063     }
1064 
1065     /// Get the `ordinal` (day of the year) field if set.
1066     ///
1067     /// See also [`set_ordinal()`](Parsed::set_ordinal).
1068     #[inline]
ordinal(&self) -> Option<u32>1069     pub fn ordinal(&self) -> Option<u32> {
1070         self.ordinal
1071     }
1072 
1073     /// Get the `day` of the month field if set.
1074     ///
1075     /// See also [`set_day()`](Parsed::set_day).
1076     #[inline]
day(&self) -> Option<u32>1077     pub fn day(&self) -> Option<u32> {
1078         self.day
1079     }
1080 
1081     /// Get the `hour_div_12` field (am/pm) if set.
1082     ///
1083     /// 0 indicates AM and 1 indicates PM.
1084     ///
1085     /// See also [`set_ampm()`](Parsed::set_ampm) and [`set_hour()`](Parsed::set_hour).
1086     #[inline]
hour_div_12(&self) -> Option<u32>1087     pub fn hour_div_12(&self) -> Option<u32> {
1088         self.hour_div_12
1089     }
1090 
1091     /// Get the `hour_mod_12` field if set.
1092     ///
1093     /// See also [`set_hour12()`](Parsed::set_hour12) and [`set_hour()`](Parsed::set_hour).
hour_mod_12(&self) -> Option<u32>1094     pub fn hour_mod_12(&self) -> Option<u32> {
1095         self.hour_mod_12
1096     }
1097 
1098     /// Get the `minute` field if set.
1099     ///
1100     /// See also [`set_minute()`](Parsed::set_minute).
1101     #[inline]
minute(&self) -> Option<u32>1102     pub fn minute(&self) -> Option<u32> {
1103         self.minute
1104     }
1105 
1106     /// Get the `second` field if set.
1107     ///
1108     /// See also [`set_second()`](Parsed::set_second).
1109     #[inline]
second(&self) -> Option<u32>1110     pub fn second(&self) -> Option<u32> {
1111         self.second
1112     }
1113 
1114     /// Get the `nanosecond` field if set.
1115     ///
1116     /// See also [`set_nanosecond()`](Parsed::set_nanosecond).
1117     #[inline]
nanosecond(&self) -> Option<u32>1118     pub fn nanosecond(&self) -> Option<u32> {
1119         self.nanosecond
1120     }
1121 
1122     /// Get the `timestamp` field if set.
1123     ///
1124     /// See also [`set_timestamp()`](Parsed::set_timestamp).
1125     #[inline]
timestamp(&self) -> Option<i64>1126     pub fn timestamp(&self) -> Option<i64> {
1127         self.timestamp
1128     }
1129 
1130     /// Get the `offset` field if set.
1131     ///
1132     /// See also [`set_offset()`](Parsed::set_offset).
1133     #[inline]
offset(&self) -> Option<i32>1134     pub fn offset(&self) -> Option<i32> {
1135         self.offset
1136     }
1137 }
1138 
1139 /// Create a `NaiveDate` when given a year, week, weekday, and the definition at which day of the
1140 /// week a week starts.
1141 ///
1142 /// Returns `IMPOSSIBLE` if `week` is `0` or `53` and the `weekday` falls outside the year.
resolve_week_date( year: i32, week: u32, weekday: Weekday, week_start_day: Weekday, ) -> ParseResult<NaiveDate>1143 fn resolve_week_date(
1144     year: i32,
1145     week: u32,
1146     weekday: Weekday,
1147     week_start_day: Weekday,
1148 ) -> ParseResult<NaiveDate> {
1149     if week > 53 {
1150         return Err(OUT_OF_RANGE);
1151     }
1152 
1153     let first_day_of_year = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?;
1154     // Ordinal of the day at which week 1 starts.
1155     let first_week_start = 1 + week_start_day.days_since(first_day_of_year.weekday()) as i32;
1156     // Number of the `weekday`, which is 0 for the first day of the week.
1157     let weekday = weekday.days_since(week_start_day) as i32;
1158     let ordinal = first_week_start + (week as i32 - 1) * 7 + weekday;
1159     if ordinal <= 0 {
1160         return Err(IMPOSSIBLE);
1161     }
1162     first_day_of_year.with_ordinal(ordinal as u32).ok_or(IMPOSSIBLE)
1163 }
1164 
1165 #[cfg(test)]
1166 mod tests {
1167     use super::super::{IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
1168     use super::Parsed;
1169     use crate::naive::{NaiveDate, NaiveTime};
1170     use crate::offset::{FixedOffset, TimeZone, Utc};
1171     use crate::Datelike;
1172     use crate::Weekday::*;
1173 
1174     #[test]
test_parsed_set_fields()1175     fn test_parsed_set_fields() {
1176         // year*, isoyear*
1177         let mut p = Parsed::new();
1178         assert_eq!(p.set_year(1987), Ok(()));
1179         assert_eq!(p.set_year(1986), Err(IMPOSSIBLE));
1180         assert_eq!(p.set_year(1988), Err(IMPOSSIBLE));
1181         assert_eq!(p.set_year(1987), Ok(()));
1182         assert_eq!(p.set_year_div_100(20), Ok(())); // independent to `year`
1183         assert_eq!(p.set_year_div_100(21), Err(IMPOSSIBLE));
1184         assert_eq!(p.set_year_div_100(19), Err(IMPOSSIBLE));
1185         assert_eq!(p.set_year_mod_100(37), Ok(())); // ditto
1186         assert_eq!(p.set_year_mod_100(38), Err(IMPOSSIBLE));
1187         assert_eq!(p.set_year_mod_100(36), Err(IMPOSSIBLE));
1188 
1189         let mut p = Parsed::new();
1190         assert_eq!(p.set_year(0), Ok(()));
1191         assert_eq!(p.set_year_div_100(0), Ok(()));
1192         assert_eq!(p.set_year_mod_100(0), Ok(()));
1193 
1194         let mut p = Parsed::new();
1195         assert_eq!(p.set_year_div_100(-1), Err(OUT_OF_RANGE));
1196         assert_eq!(p.set_year_mod_100(-1), Err(OUT_OF_RANGE));
1197         assert_eq!(p.set_year(-1), Ok(()));
1198         assert_eq!(p.set_year(-2), Err(IMPOSSIBLE));
1199         assert_eq!(p.set_year(0), Err(IMPOSSIBLE));
1200 
1201         let mut p = Parsed::new();
1202         assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(OUT_OF_RANGE));
1203         assert_eq!(p.set_year_div_100(8), Ok(()));
1204         assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(OUT_OF_RANGE));
1205 
1206         // month, week*, isoweek, ordinal, day, minute, second, nanosecond, offset
1207         let mut p = Parsed::new();
1208         assert_eq!(p.set_month(7), Ok(()));
1209         assert_eq!(p.set_month(1), Err(IMPOSSIBLE));
1210         assert_eq!(p.set_month(6), Err(IMPOSSIBLE));
1211         assert_eq!(p.set_month(8), Err(IMPOSSIBLE));
1212         assert_eq!(p.set_month(12), Err(IMPOSSIBLE));
1213 
1214         let mut p = Parsed::new();
1215         assert_eq!(p.set_month(8), Ok(()));
1216         assert_eq!(p.set_month(0x1_0000_0008), Err(OUT_OF_RANGE));
1217 
1218         // hour
1219         let mut p = Parsed::new();
1220         assert_eq!(p.set_hour(12), Ok(()));
1221         assert_eq!(p.set_hour(11), Err(IMPOSSIBLE));
1222         assert_eq!(p.set_hour(13), Err(IMPOSSIBLE));
1223         assert_eq!(p.set_hour(12), Ok(()));
1224         assert_eq!(p.set_ampm(false), Err(IMPOSSIBLE));
1225         assert_eq!(p.set_ampm(true), Ok(()));
1226         assert_eq!(p.set_hour12(12), Ok(()));
1227         assert_eq!(p.set_hour12(0), Err(OUT_OF_RANGE)); // requires canonical representation
1228         assert_eq!(p.set_hour12(1), Err(IMPOSSIBLE));
1229         assert_eq!(p.set_hour12(11), Err(IMPOSSIBLE));
1230 
1231         let mut p = Parsed::new();
1232         assert_eq!(p.set_ampm(true), Ok(()));
1233         assert_eq!(p.set_hour12(7), Ok(()));
1234         assert_eq!(p.set_hour(7), Err(IMPOSSIBLE));
1235         assert_eq!(p.set_hour(18), Err(IMPOSSIBLE));
1236         assert_eq!(p.set_hour(19), Ok(()));
1237 
1238         // timestamp
1239         let mut p = Parsed::new();
1240         assert_eq!(p.set_timestamp(1_234_567_890), Ok(()));
1241         assert_eq!(p.set_timestamp(1_234_567_889), Err(IMPOSSIBLE));
1242         assert_eq!(p.set_timestamp(1_234_567_891), Err(IMPOSSIBLE));
1243     }
1244 
1245     #[test]
test_parsed_set_range()1246     fn test_parsed_set_range() {
1247         assert_eq!(Parsed::new().set_year(i32::MIN as i64 - 1), Err(OUT_OF_RANGE));
1248         assert!(Parsed::new().set_year(i32::MIN as i64).is_ok());
1249         assert!(Parsed::new().set_year(i32::MAX as i64).is_ok());
1250         assert_eq!(Parsed::new().set_year(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
1251 
1252         assert_eq!(Parsed::new().set_year_div_100(-1), Err(OUT_OF_RANGE));
1253         assert!(Parsed::new().set_year_div_100(0).is_ok());
1254         assert!(Parsed::new().set_year_div_100(i32::MAX as i64).is_ok());
1255         assert_eq!(Parsed::new().set_year_div_100(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
1256 
1257         assert_eq!(Parsed::new().set_year_mod_100(-1), Err(OUT_OF_RANGE));
1258         assert!(Parsed::new().set_year_mod_100(0).is_ok());
1259         assert!(Parsed::new().set_year_mod_100(99).is_ok());
1260         assert_eq!(Parsed::new().set_year_mod_100(100), Err(OUT_OF_RANGE));
1261 
1262         assert_eq!(Parsed::new().set_isoyear(i32::MIN as i64 - 1), Err(OUT_OF_RANGE));
1263         assert!(Parsed::new().set_isoyear(i32::MIN as i64).is_ok());
1264         assert!(Parsed::new().set_isoyear(i32::MAX as i64).is_ok());
1265         assert_eq!(Parsed::new().set_isoyear(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
1266 
1267         assert_eq!(Parsed::new().set_isoyear_div_100(-1), Err(OUT_OF_RANGE));
1268         assert!(Parsed::new().set_isoyear_div_100(0).is_ok());
1269         assert!(Parsed::new().set_isoyear_div_100(99).is_ok());
1270         assert_eq!(Parsed::new().set_isoyear_div_100(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
1271 
1272         assert_eq!(Parsed::new().set_isoyear_mod_100(-1), Err(OUT_OF_RANGE));
1273         assert!(Parsed::new().set_isoyear_mod_100(0).is_ok());
1274         assert!(Parsed::new().set_isoyear_mod_100(99).is_ok());
1275         assert_eq!(Parsed::new().set_isoyear_mod_100(100), Err(OUT_OF_RANGE));
1276 
1277         assert_eq!(Parsed::new().set_month(0), Err(OUT_OF_RANGE));
1278         assert!(Parsed::new().set_month(1).is_ok());
1279         assert!(Parsed::new().set_month(12).is_ok());
1280         assert_eq!(Parsed::new().set_month(13), Err(OUT_OF_RANGE));
1281 
1282         assert_eq!(Parsed::new().set_week_from_sun(-1), Err(OUT_OF_RANGE));
1283         assert!(Parsed::new().set_week_from_sun(0).is_ok());
1284         assert!(Parsed::new().set_week_from_sun(53).is_ok());
1285         assert_eq!(Parsed::new().set_week_from_sun(54), Err(OUT_OF_RANGE));
1286 
1287         assert_eq!(Parsed::new().set_week_from_mon(-1), Err(OUT_OF_RANGE));
1288         assert!(Parsed::new().set_week_from_mon(0).is_ok());
1289         assert!(Parsed::new().set_week_from_mon(53).is_ok());
1290         assert_eq!(Parsed::new().set_week_from_mon(54), Err(OUT_OF_RANGE));
1291 
1292         assert_eq!(Parsed::new().set_isoweek(0), Err(OUT_OF_RANGE));
1293         assert!(Parsed::new().set_isoweek(1).is_ok());
1294         assert!(Parsed::new().set_isoweek(53).is_ok());
1295         assert_eq!(Parsed::new().set_isoweek(54), Err(OUT_OF_RANGE));
1296 
1297         assert_eq!(Parsed::new().set_ordinal(0), Err(OUT_OF_RANGE));
1298         assert!(Parsed::new().set_ordinal(1).is_ok());
1299         assert!(Parsed::new().set_ordinal(366).is_ok());
1300         assert_eq!(Parsed::new().set_ordinal(367), Err(OUT_OF_RANGE));
1301 
1302         assert_eq!(Parsed::new().set_day(0), Err(OUT_OF_RANGE));
1303         assert!(Parsed::new().set_day(1).is_ok());
1304         assert!(Parsed::new().set_day(31).is_ok());
1305         assert_eq!(Parsed::new().set_day(32), Err(OUT_OF_RANGE));
1306 
1307         assert_eq!(Parsed::new().set_hour12(0), Err(OUT_OF_RANGE));
1308         assert!(Parsed::new().set_hour12(1).is_ok());
1309         assert!(Parsed::new().set_hour12(12).is_ok());
1310         assert_eq!(Parsed::new().set_hour12(13), Err(OUT_OF_RANGE));
1311 
1312         assert_eq!(Parsed::new().set_hour(-1), Err(OUT_OF_RANGE));
1313         assert!(Parsed::new().set_hour(0).is_ok());
1314         assert!(Parsed::new().set_hour(23).is_ok());
1315         assert_eq!(Parsed::new().set_hour(24), Err(OUT_OF_RANGE));
1316 
1317         assert_eq!(Parsed::new().set_minute(-1), Err(OUT_OF_RANGE));
1318         assert!(Parsed::new().set_minute(0).is_ok());
1319         assert!(Parsed::new().set_minute(59).is_ok());
1320         assert_eq!(Parsed::new().set_minute(60), Err(OUT_OF_RANGE));
1321 
1322         assert_eq!(Parsed::new().set_second(-1), Err(OUT_OF_RANGE));
1323         assert!(Parsed::new().set_second(0).is_ok());
1324         assert!(Parsed::new().set_second(60).is_ok());
1325         assert_eq!(Parsed::new().set_second(61), Err(OUT_OF_RANGE));
1326 
1327         assert_eq!(Parsed::new().set_nanosecond(-1), Err(OUT_OF_RANGE));
1328         assert!(Parsed::new().set_nanosecond(0).is_ok());
1329         assert!(Parsed::new().set_nanosecond(999_999_999).is_ok());
1330         assert_eq!(Parsed::new().set_nanosecond(1_000_000_000), Err(OUT_OF_RANGE));
1331 
1332         assert!(Parsed::new().set_timestamp(i64::MIN).is_ok());
1333         assert!(Parsed::new().set_timestamp(i64::MAX).is_ok());
1334 
1335         assert_eq!(Parsed::new().set_offset(i32::MIN as i64 - 1), Err(OUT_OF_RANGE));
1336         assert!(Parsed::new().set_offset(i32::MIN as i64).is_ok());
1337         assert!(Parsed::new().set_offset(i32::MAX as i64).is_ok());
1338         assert_eq!(Parsed::new().set_offset(i32::MAX as i64 + 1), Err(OUT_OF_RANGE));
1339     }
1340 
1341     #[test]
test_parsed_to_naive_date()1342     fn test_parsed_to_naive_date() {
1343         macro_rules! parse {
1344             ($($k:ident: $v:expr),*) => (
1345                 Parsed { $($k: Some($v),)* ..Parsed::new() }.to_naive_date()
1346             )
1347         }
1348 
1349         let ymd = |y, m, d| Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap());
1350 
1351         // ymd: omission of fields
1352         assert_eq!(parse!(), Err(NOT_ENOUGH));
1353         assert_eq!(parse!(year: 1984), Err(NOT_ENOUGH));
1354         assert_eq!(parse!(year: 1984, month: 1), Err(NOT_ENOUGH));
1355         assert_eq!(parse!(year: 1984, month: 1, day: 2), ymd(1984, 1, 2));
1356         assert_eq!(parse!(year: 1984, day: 2), Err(NOT_ENOUGH));
1357         assert_eq!(parse!(year_div_100: 19), Err(NOT_ENOUGH));
1358         assert_eq!(parse!(year_div_100: 19, year_mod_100: 84), Err(NOT_ENOUGH));
1359         assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 1), Err(NOT_ENOUGH));
1360         assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 1, day: 2), ymd(1984, 1, 2));
1361         assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, day: 2), Err(NOT_ENOUGH));
1362         assert_eq!(parse!(year_div_100: 19, month: 1, day: 2), Err(NOT_ENOUGH));
1363         assert_eq!(parse!(year_mod_100: 70, month: 1, day: 2), ymd(1970, 1, 2));
1364         assert_eq!(parse!(year_mod_100: 69, month: 1, day: 2), ymd(2069, 1, 2));
1365 
1366         // ymd: out-of-range conditions
1367         assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 2, day: 29), ymd(1984, 2, 29));
1368         assert_eq!(
1369             parse!(year_div_100: 19, year_mod_100: 83, month: 2, day: 29),
1370             Err(OUT_OF_RANGE)
1371         );
1372         assert_eq!(
1373             parse!(year_div_100: 19, year_mod_100: 83, month: 13, day: 1),
1374             Err(OUT_OF_RANGE)
1375         );
1376         assert_eq!(
1377             parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 31),
1378             ymd(1983, 12, 31)
1379         );
1380         assert_eq!(
1381             parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 32),
1382             Err(OUT_OF_RANGE)
1383         );
1384         assert_eq!(
1385             parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 0),
1386             Err(OUT_OF_RANGE)
1387         );
1388         assert_eq!(
1389             parse!(year_div_100: 19, year_mod_100: 100, month: 1, day: 1),
1390             Err(OUT_OF_RANGE)
1391         );
1392         assert_eq!(parse!(year_div_100: 19, year_mod_100: -1, month: 1, day: 1), Err(OUT_OF_RANGE));
1393         assert_eq!(parse!(year_div_100: 0, year_mod_100: 0, month: 1, day: 1), ymd(0, 1, 1));
1394         assert_eq!(parse!(year_div_100: -1, year_mod_100: 42, month: 1, day: 1), Err(IMPOSSIBLE));
1395         let max_year = NaiveDate::MAX.year();
1396         assert_eq!(
1397             parse!(year_div_100: max_year / 100,
1398                           year_mod_100: max_year % 100, month: 1, day: 1),
1399             ymd(max_year, 1, 1)
1400         );
1401         assert_eq!(
1402             parse!(year_div_100: (max_year + 1) / 100,
1403                           year_mod_100: (max_year + 1) % 100, month: 1, day: 1),
1404             Err(OUT_OF_RANGE)
1405         );
1406 
1407         // ymd: conflicting inputs
1408         assert_eq!(parse!(year: 1984, year_div_100: 19, month: 1, day: 1), ymd(1984, 1, 1));
1409         assert_eq!(parse!(year: 1984, year_div_100: 20, month: 1, day: 1), Err(IMPOSSIBLE));
1410         assert_eq!(parse!(year: 1984, year_mod_100: 84, month: 1, day: 1), ymd(1984, 1, 1));
1411         assert_eq!(parse!(year: 1984, year_mod_100: 83, month: 1, day: 1), Err(IMPOSSIBLE));
1412         assert_eq!(
1413             parse!(year: 1984, year_div_100: 19, year_mod_100: 84, month: 1, day: 1),
1414             ymd(1984, 1, 1)
1415         );
1416         assert_eq!(
1417             parse!(year: 1984, year_div_100: 18, year_mod_100: 94, month: 1, day: 1),
1418             Err(IMPOSSIBLE)
1419         );
1420         assert_eq!(
1421             parse!(year: 1984, year_div_100: 18, year_mod_100: 184, month: 1, day: 1),
1422             Err(OUT_OF_RANGE)
1423         );
1424         assert_eq!(
1425             parse!(year: -1, year_div_100: 0, year_mod_100: -1, month: 1, day: 1),
1426             Err(OUT_OF_RANGE)
1427         );
1428         assert_eq!(
1429             parse!(year: -1, year_div_100: -1, year_mod_100: 99, month: 1, day: 1),
1430             Err(IMPOSSIBLE)
1431         );
1432         assert_eq!(parse!(year: -1, year_div_100: 0, month: 1, day: 1), Err(IMPOSSIBLE));
1433         assert_eq!(parse!(year: -1, year_mod_100: 99, month: 1, day: 1), Err(IMPOSSIBLE));
1434 
1435         // weekdates
1436         assert_eq!(parse!(year: 2000, week_from_mon: 0), Err(NOT_ENOUGH));
1437         assert_eq!(parse!(year: 2000, week_from_sun: 0), Err(NOT_ENOUGH));
1438         assert_eq!(parse!(year: 2000, weekday: Sun), Err(NOT_ENOUGH));
1439         assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Fri), Err(IMPOSSIBLE));
1440         assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Fri), Err(IMPOSSIBLE));
1441         assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sat), ymd(2000, 1, 1));
1442         assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Sat), ymd(2000, 1, 1));
1443         assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sun), ymd(2000, 1, 2));
1444         assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sun), ymd(2000, 1, 2));
1445         assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Mon), ymd(2000, 1, 3));
1446         assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Mon), ymd(2000, 1, 3));
1447         assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sat), ymd(2000, 1, 8));
1448         assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sat), ymd(2000, 1, 8));
1449         assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sun), ymd(2000, 1, 9));
1450         assert_eq!(parse!(year: 2000, week_from_sun: 2, weekday: Sun), ymd(2000, 1, 9));
1451         assert_eq!(parse!(year: 2000, week_from_mon: 2, weekday: Mon), ymd(2000, 1, 10));
1452         assert_eq!(parse!(year: 2000, week_from_sun: 52, weekday: Sat), ymd(2000, 12, 30));
1453         assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Sun), ymd(2000, 12, 31));
1454         assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Mon), Err(IMPOSSIBLE));
1455         assert_eq!(parse!(year: 2000, week_from_sun: 0xffffffff, weekday: Mon), Err(OUT_OF_RANGE));
1456         assert_eq!(parse!(year: 2006, week_from_sun: 0, weekday: Sat), Err(IMPOSSIBLE));
1457         assert_eq!(parse!(year: 2006, week_from_sun: 1, weekday: Sun), ymd(2006, 1, 1));
1458 
1459         // weekdates: conflicting inputs
1460         assert_eq!(
1461             parse!(year: 2000, week_from_mon: 1, week_from_sun: 1, weekday: Sat),
1462             ymd(2000, 1, 8)
1463         );
1464         assert_eq!(
1465             parse!(year: 2000, week_from_mon: 1, week_from_sun: 2, weekday: Sun),
1466             ymd(2000, 1, 9)
1467         );
1468         assert_eq!(
1469             parse!(year: 2000, week_from_mon: 1, week_from_sun: 1, weekday: Sun),
1470             Err(IMPOSSIBLE)
1471         );
1472         assert_eq!(
1473             parse!(year: 2000, week_from_mon: 2, week_from_sun: 2, weekday: Sun),
1474             Err(IMPOSSIBLE)
1475         );
1476 
1477         // ISO weekdates
1478         assert_eq!(parse!(isoyear: 2004, isoweek: 53), Err(NOT_ENOUGH));
1479         assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Fri), ymd(2004, 12, 31));
1480         assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Sat), ymd(2005, 1, 1));
1481         assert_eq!(parse!(isoyear: 2004, isoweek: 0xffffffff, weekday: Sat), Err(OUT_OF_RANGE));
1482         assert_eq!(parse!(isoyear: 2005, isoweek: 0, weekday: Thu), Err(OUT_OF_RANGE));
1483         assert_eq!(parse!(isoyear: 2005, isoweek: 5, weekday: Thu), ymd(2005, 2, 3));
1484         assert_eq!(parse!(isoyear: 2005, weekday: Thu), Err(NOT_ENOUGH));
1485 
1486         // year and ordinal
1487         assert_eq!(parse!(ordinal: 123), Err(NOT_ENOUGH));
1488         assert_eq!(parse!(year: 2000, ordinal: 0), Err(OUT_OF_RANGE));
1489         assert_eq!(parse!(year: 2000, ordinal: 1), ymd(2000, 1, 1));
1490         assert_eq!(parse!(year: 2000, ordinal: 60), ymd(2000, 2, 29));
1491         assert_eq!(parse!(year: 2000, ordinal: 61), ymd(2000, 3, 1));
1492         assert_eq!(parse!(year: 2000, ordinal: 366), ymd(2000, 12, 31));
1493         assert_eq!(parse!(year: 2000, ordinal: 367), Err(OUT_OF_RANGE));
1494         assert_eq!(parse!(year: 2000, ordinal: 0xffffffff), Err(OUT_OF_RANGE));
1495         assert_eq!(parse!(year: 2100, ordinal: 0), Err(OUT_OF_RANGE));
1496         assert_eq!(parse!(year: 2100, ordinal: 1), ymd(2100, 1, 1));
1497         assert_eq!(parse!(year: 2100, ordinal: 59), ymd(2100, 2, 28));
1498         assert_eq!(parse!(year: 2100, ordinal: 60), ymd(2100, 3, 1));
1499         assert_eq!(parse!(year: 2100, ordinal: 365), ymd(2100, 12, 31));
1500         assert_eq!(parse!(year: 2100, ordinal: 366), Err(OUT_OF_RANGE));
1501         assert_eq!(parse!(year: 2100, ordinal: 0xffffffff), Err(OUT_OF_RANGE));
1502 
1503         // more complex cases
1504         assert_eq!(
1505             parse!(year: 2014, month: 12, day: 31, ordinal: 365, isoyear: 2015, isoweek: 1,
1506                           week_from_sun: 52, week_from_mon: 52, weekday: Wed),
1507             ymd(2014, 12, 31)
1508         );
1509         assert_eq!(
1510             parse!(year: 2014, month: 12, ordinal: 365, isoyear: 2015, isoweek: 1,
1511                           week_from_sun: 52, week_from_mon: 52),
1512             ymd(2014, 12, 31)
1513         );
1514         assert_eq!(
1515             parse!(year: 2014, month: 12, day: 31, ordinal: 365, isoyear: 2014, isoweek: 53,
1516                           week_from_sun: 52, week_from_mon: 52, weekday: Wed),
1517             Err(IMPOSSIBLE)
1518         ); // no ISO week date 2014-W53-3
1519         assert_eq!(
1520             parse!(year: 2012, isoyear: 2015, isoweek: 1,
1521                           week_from_sun: 52, week_from_mon: 52),
1522             Err(NOT_ENOUGH)
1523         ); // ambiguous (2014-12-29, 2014-12-30, 2014-12-31)
1524         assert_eq!(parse!(year_div_100: 20, isoyear_mod_100: 15, ordinal: 366), Err(NOT_ENOUGH));
1525         // technically unique (2014-12-31) but Chrono gives up
1526     }
1527 
1528     #[test]
test_parsed_to_naive_time()1529     fn test_parsed_to_naive_time() {
1530         macro_rules! parse {
1531             ($($k:ident: $v:expr),*) => (
1532                 Parsed { $($k: Some($v),)* ..Parsed::new() }.to_naive_time()
1533             )
1534         }
1535 
1536         let hms = |h, m, s| Ok(NaiveTime::from_hms_opt(h, m, s).unwrap());
1537         let hmsn = |h, m, s, n| Ok(NaiveTime::from_hms_nano_opt(h, m, s, n).unwrap());
1538 
1539         // omission of fields
1540         assert_eq!(parse!(), Err(NOT_ENOUGH));
1541         assert_eq!(parse!(hour_div_12: 0), Err(NOT_ENOUGH));
1542         assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1), Err(NOT_ENOUGH));
1543         assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23), hms(1, 23, 0));
1544         assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 45), hms(1, 23, 45));
1545         assert_eq!(
1546             parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 45,
1547                           nanosecond: 678_901_234),
1548             hmsn(1, 23, 45, 678_901_234)
1549         );
1550         assert_eq!(parse!(hour_div_12: 1, hour_mod_12: 11, minute: 45, second: 6), hms(23, 45, 6));
1551         assert_eq!(parse!(hour_mod_12: 1, minute: 23), Err(NOT_ENOUGH));
1552         assert_eq!(
1553             parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, nanosecond: 456_789_012),
1554             Err(NOT_ENOUGH)
1555         );
1556 
1557         // out-of-range conditions
1558         assert_eq!(parse!(hour_div_12: 2, hour_mod_12: 0, minute: 0), Err(OUT_OF_RANGE));
1559         assert_eq!(parse!(hour_div_12: 1, hour_mod_12: 12, minute: 0), Err(OUT_OF_RANGE));
1560         assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 60), Err(OUT_OF_RANGE));
1561         assert_eq!(
1562             parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 61),
1563             Err(OUT_OF_RANGE)
1564         );
1565         assert_eq!(
1566             parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 34,
1567                           nanosecond: 1_000_000_000),
1568             Err(OUT_OF_RANGE)
1569         );
1570 
1571         // leap seconds
1572         assert_eq!(
1573             parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 60),
1574             hmsn(1, 23, 59, 1_000_000_000)
1575         );
1576         assert_eq!(
1577             parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 60,
1578                           nanosecond: 999_999_999),
1579             hmsn(1, 23, 59, 1_999_999_999)
1580         );
1581     }
1582 
1583     #[test]
test_parsed_to_naive_datetime_with_offset()1584     fn test_parsed_to_naive_datetime_with_offset() {
1585         macro_rules! parse {
1586             (offset = $offset:expr; $($k:ident: $v:expr),*) => (
1587                 Parsed { $($k: Some($v),)* ..Parsed::new() }.to_naive_datetime_with_offset($offset)
1588             );
1589             ($($k:ident: $v:expr),*) => (parse!(offset = 0; $($k: $v),*))
1590         }
1591 
1592         let ymdhms = |y, m, d, h, n, s| {
1593             Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap())
1594         };
1595         let ymdhmsn = |y, m, d, h, n, s, nano| {
1596             Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_nano_opt(h, n, s, nano).unwrap())
1597         };
1598 
1599         // omission of fields
1600         assert_eq!(parse!(), Err(NOT_ENOUGH));
1601         assert_eq!(
1602             parse!(year: 2015, month: 1, day: 30,
1603                           hour_div_12: 1, hour_mod_12: 2, minute: 38),
1604             ymdhms(2015, 1, 30, 14, 38, 0)
1605         );
1606         assert_eq!(
1607             parse!(year: 1997, month: 1, day: 30,
1608                           hour_div_12: 1, hour_mod_12: 2, minute: 38, second: 5),
1609             ymdhms(1997, 1, 30, 14, 38, 5)
1610         );
1611         assert_eq!(
1612             parse!(year: 2012, ordinal: 34, hour_div_12: 0, hour_mod_12: 5,
1613                           minute: 6, second: 7, nanosecond: 890_123_456),
1614             ymdhmsn(2012, 2, 3, 5, 6, 7, 890_123_456)
1615         );
1616         assert_eq!(parse!(timestamp: 0), ymdhms(1970, 1, 1, 0, 0, 0));
1617         assert_eq!(parse!(timestamp: 1, nanosecond: 0), ymdhms(1970, 1, 1, 0, 0, 1));
1618         assert_eq!(parse!(timestamp: 1, nanosecond: 1), ymdhmsn(1970, 1, 1, 0, 0, 1, 1));
1619         assert_eq!(parse!(timestamp: 1_420_000_000), ymdhms(2014, 12, 31, 4, 26, 40));
1620         assert_eq!(parse!(timestamp: -0x1_0000_0000), ymdhms(1833, 11, 24, 17, 31, 44));
1621 
1622         // full fields
1623         assert_eq!(
1624             parse!(year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31,
1625                           ordinal: 365, isoyear: 2015, isoyear_div_100: 20, isoyear_mod_100: 15,
1626                           isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed,
1627                           hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40,
1628                           nanosecond: 12_345_678, timestamp: 1_420_000_000),
1629             ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678)
1630         );
1631         assert_eq!(
1632             parse!(year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31,
1633                           ordinal: 365, isoyear: 2015, isoyear_div_100: 20, isoyear_mod_100: 15,
1634                           isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed,
1635                           hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40,
1636                           nanosecond: 12_345_678, timestamp: 1_419_999_999),
1637             Err(IMPOSSIBLE)
1638         );
1639         assert_eq!(
1640             parse!(offset = 32400;
1641                           year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31,
1642                           ordinal: 365, isoyear: 2015, isoyear_div_100: 20, isoyear_mod_100: 15,
1643                           isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed,
1644                           hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40,
1645                           nanosecond: 12_345_678, timestamp: 1_419_967_600),
1646             ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678)
1647         );
1648 
1649         // more timestamps
1650         let max_days_from_year_1970 =
1651             NaiveDate::MAX.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
1652         let year_0_from_year_1970 = NaiveDate::from_ymd_opt(0, 1, 1)
1653             .unwrap()
1654             .signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
1655         let min_days_from_year_1970 =
1656             NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
1657         assert_eq!(
1658             parse!(timestamp: min_days_from_year_1970.num_seconds()),
1659             ymdhms(NaiveDate::MIN.year(), 1, 1, 0, 0, 0)
1660         );
1661         assert_eq!(
1662             parse!(timestamp: year_0_from_year_1970.num_seconds()),
1663             ymdhms(0, 1, 1, 0, 0, 0)
1664         );
1665         assert_eq!(
1666             parse!(timestamp: max_days_from_year_1970.num_seconds() + 86399),
1667             ymdhms(NaiveDate::MAX.year(), 12, 31, 23, 59, 59)
1668         );
1669 
1670         // leap seconds #1: partial fields
1671         assert_eq!(parse!(second: 59, timestamp: 1_341_100_798), Err(IMPOSSIBLE));
1672         assert_eq!(parse!(second: 59, timestamp: 1_341_100_799), ymdhms(2012, 6, 30, 23, 59, 59));
1673         assert_eq!(parse!(second: 59, timestamp: 1_341_100_800), Err(IMPOSSIBLE));
1674         assert_eq!(
1675             parse!(second: 60, timestamp: 1_341_100_799),
1676             ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
1677         );
1678         assert_eq!(
1679             parse!(second: 60, timestamp: 1_341_100_800),
1680             ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
1681         );
1682         assert_eq!(parse!(second: 0, timestamp: 1_341_100_800), ymdhms(2012, 7, 1, 0, 0, 0));
1683         assert_eq!(parse!(second: 1, timestamp: 1_341_100_800), Err(IMPOSSIBLE));
1684         assert_eq!(parse!(second: 60, timestamp: 1_341_100_801), Err(IMPOSSIBLE));
1685 
1686         // leap seconds #2: full fields
1687         // we need to have separate tests for them since it uses another control flow.
1688         assert_eq!(
1689             parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1690                           minute: 59, second: 59, timestamp: 1_341_100_798),
1691             Err(IMPOSSIBLE)
1692         );
1693         assert_eq!(
1694             parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1695                           minute: 59, second: 59, timestamp: 1_341_100_799),
1696             ymdhms(2012, 6, 30, 23, 59, 59)
1697         );
1698         assert_eq!(
1699             parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1700                           minute: 59, second: 59, timestamp: 1_341_100_800),
1701             Err(IMPOSSIBLE)
1702         );
1703         assert_eq!(
1704             parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1705                           minute: 59, second: 60, timestamp: 1_341_100_799),
1706             ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
1707         );
1708         assert_eq!(
1709             parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1710                           minute: 59, second: 60, timestamp: 1_341_100_800),
1711             ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
1712         );
1713         assert_eq!(
1714             parse!(year: 2012, ordinal: 183, hour_div_12: 0, hour_mod_12: 0,
1715                           minute: 0, second: 0, timestamp: 1_341_100_800),
1716             ymdhms(2012, 7, 1, 0, 0, 0)
1717         );
1718         assert_eq!(
1719             parse!(year: 2012, ordinal: 183, hour_div_12: 0, hour_mod_12: 0,
1720                           minute: 0, second: 1, timestamp: 1_341_100_800),
1721             Err(IMPOSSIBLE)
1722         );
1723         assert_eq!(
1724             parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1725                           minute: 59, second: 60, timestamp: 1_341_100_801),
1726             Err(IMPOSSIBLE)
1727         );
1728 
1729         // error codes
1730         assert_eq!(
1731             parse!(year: 2015, month: 1, day: 20, weekday: Tue,
1732                           hour_div_12: 2, hour_mod_12: 1, minute: 35, second: 20),
1733             Err(OUT_OF_RANGE)
1734         ); // `hour_div_12` is out of range
1735     }
1736 
1737     #[test]
test_parsed_to_datetime()1738     fn test_parsed_to_datetime() {
1739         macro_rules! parse {
1740             ($($k:ident: $v:expr),*) => (
1741                 Parsed { $($k: Some($v),)* ..Parsed::new() }.to_datetime()
1742             )
1743         }
1744 
1745         let ymdhmsn = |y, m, d, h, n, s, nano, off| {
1746             Ok(FixedOffset::east_opt(off)
1747                 .unwrap()
1748                 .from_local_datetime(
1749                     &NaiveDate::from_ymd_opt(y, m, d)
1750                         .unwrap()
1751                         .and_hms_nano_opt(h, n, s, nano)
1752                         .unwrap(),
1753                 )
1754                 .unwrap())
1755         };
1756 
1757         assert_eq!(parse!(offset: 0), Err(NOT_ENOUGH));
1758         assert_eq!(
1759             parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
1760                           minute: 26, second: 40, nanosecond: 12_345_678),
1761             Err(NOT_ENOUGH)
1762         );
1763         assert_eq!(
1764             parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
1765                           minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
1766             ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678, 0)
1767         );
1768         assert_eq!(
1769             parse!(year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1,
1770                           minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
1771             ymdhmsn(2014, 12, 31, 13, 26, 40, 12_345_678, 32400)
1772         );
1773         assert_eq!(
1774             parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 1,
1775                           minute: 42, second: 4, nanosecond: 12_345_678, offset: -9876),
1776             ymdhmsn(2014, 12, 31, 1, 42, 4, 12_345_678, -9876)
1777         );
1778         assert_eq!(
1779             parse!(year: 2015, ordinal: 1, hour_div_12: 0, hour_mod_12: 4,
1780                           minute: 26, second: 40, nanosecond: 12_345_678, offset: 86_400),
1781             Err(OUT_OF_RANGE)
1782         ); // `FixedOffset` does not support such huge offset
1783     }
1784 
1785     #[test]
test_parsed_to_datetime_with_timezone()1786     fn test_parsed_to_datetime_with_timezone() {
1787         macro_rules! parse {
1788             ($tz:expr; $($k:ident: $v:expr),*) => (
1789                 Parsed { $($k: Some($v),)* ..Parsed::new() }.to_datetime_with_timezone(&$tz)
1790             )
1791         }
1792 
1793         // single result from ymdhms
1794         assert_eq!(
1795             parse!(Utc;
1796                           year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
1797                           minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
1798             Ok(Utc
1799                 .from_local_datetime(
1800                     &NaiveDate::from_ymd_opt(2014, 12, 31)
1801                         .unwrap()
1802                         .and_hms_nano_opt(4, 26, 40, 12_345_678)
1803                         .unwrap()
1804                 )
1805                 .unwrap())
1806         );
1807         assert_eq!(
1808             parse!(Utc;
1809                           year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1,
1810                           minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
1811             Err(IMPOSSIBLE)
1812         );
1813         assert_eq!(
1814             parse!(FixedOffset::east_opt(32400).unwrap();
1815                           year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
1816                           minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
1817             Err(IMPOSSIBLE)
1818         );
1819         assert_eq!(
1820             parse!(FixedOffset::east_opt(32400).unwrap();
1821                           year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1,
1822                           minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
1823             Ok(FixedOffset::east_opt(32400)
1824                 .unwrap()
1825                 .from_local_datetime(
1826                     &NaiveDate::from_ymd_opt(2014, 12, 31)
1827                         .unwrap()
1828                         .and_hms_nano_opt(13, 26, 40, 12_345_678)
1829                         .unwrap()
1830                 )
1831                 .unwrap())
1832         );
1833 
1834         // single result from timestamp
1835         assert_eq!(
1836             parse!(Utc; timestamp: 1_420_000_000, offset: 0),
1837             Ok(Utc.with_ymd_and_hms(2014, 12, 31, 4, 26, 40).unwrap())
1838         );
1839         assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 32400), Err(IMPOSSIBLE));
1840         assert_eq!(
1841             parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 0),
1842             Err(IMPOSSIBLE)
1843         );
1844         assert_eq!(
1845             parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 32400),
1846             Ok(FixedOffset::east_opt(32400)
1847                 .unwrap()
1848                 .with_ymd_and_hms(2014, 12, 31, 13, 26, 40)
1849                 .unwrap())
1850         );
1851 
1852         // TODO test with a variable time zone (for None and Ambiguous cases)
1853     }
1854 
1855     #[test]
issue_551()1856     fn issue_551() {
1857         use crate::Weekday;
1858         let mut parsed = Parsed::new();
1859 
1860         parsed.year = Some(2002);
1861         parsed.week_from_mon = Some(22);
1862         parsed.weekday = Some(Weekday::Mon);
1863         assert_eq!(NaiveDate::from_ymd_opt(2002, 6, 3).unwrap(), parsed.to_naive_date().unwrap());
1864 
1865         parsed.year = Some(2001);
1866         assert_eq!(NaiveDate::from_ymd_opt(2001, 5, 28).unwrap(), parsed.to_naive_date().unwrap());
1867     }
1868 }
1869