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::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
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 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)]
129pub 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]
177fn 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
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 [`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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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.
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.
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.
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.
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.
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.
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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).
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]
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]
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]
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]
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]
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.
1143fn 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)]
1166mod 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]
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]
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]
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]
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]
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]
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]
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]
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}