chrono/format/
parsed.rs

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