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, LocalResult, Offset, TimeZone};
10use crate::{DateTime, Datelike, TimeDelta, Timelike, Weekday};
11
12/// Parsed parts of date and time. There are two classes of methods:
13///
14/// - `set_*` methods try to set given field(s) while checking for the consistency.
15///   It may or may not check for the range constraint immediately (for efficiency reasons).
16///
17/// - `to_*` methods try to make a concrete date and time value out of set fields.
18///   It fully checks any remaining out-of-range conditions and inconsistent/impossible fields.
19#[allow(clippy::manual_non_exhaustive)]
20#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
21pub struct Parsed {
22    /// Year.
23    ///
24    /// This can be negative unlike [`year_div_100`](#structfield.year_div_100)
25    /// and [`year_mod_100`](#structfield.year_mod_100) fields.
26    pub year: Option<i32>,
27
28    /// Year divided by 100. Implies that the year is >= 1 BCE when set.
29    ///
30    /// Due to the common usage, if this field is missing but
31    /// [`year_mod_100`](#structfield.year_mod_100) is present,
32    /// it is inferred to 19 when `year_mod_100 >= 70` and 20 otherwise.
33    pub year_div_100: Option<i32>,
34
35    /// Year modulo 100. Implies that the year is >= 1 BCE when set.
36    pub year_mod_100: Option<i32>,
37
38    /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date).
39    ///
40    /// This can be negative unlike [`isoyear_div_100`](#structfield.isoyear_div_100) and
41    /// [`isoyear_mod_100`](#structfield.isoyear_mod_100) fields.
42    pub isoyear: Option<i32>,
43
44    /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), divided by 100.
45    /// Implies that the year is >= 1 BCE when set.
46    ///
47    /// Due to the common usage, if this field is missing but
48    /// [`isoyear_mod_100`](#structfield.isoyear_mod_100) is present,
49    /// it is inferred to 19 when `isoyear_mod_100 >= 70` and 20 otherwise.
50    pub isoyear_div_100: Option<i32>,
51
52    /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), modulo 100.
53    /// Implies that the year is >= 1 BCE when set.
54    pub isoyear_mod_100: Option<i32>,
55
56    /// Month (1--12).
57    pub month: Option<u32>,
58
59    /// Week number, where the week 1 starts at the first Sunday of January
60    /// (0--53, 1--53 or 1--52 depending on the year).
61    pub week_from_sun: Option<u32>,
62
63    /// Week number, where the week 1 starts at the first Monday of January
64    /// (0--53, 1--53 or 1--52 depending on the year).
65    pub week_from_mon: Option<u32>,
66
67    /// [ISO week number](../naive/struct.NaiveDate.html#week-date)
68    /// (1--52 or 1--53 depending on the year).
69    pub isoweek: Option<u32>,
70
71    /// Day of the week.
72    pub weekday: Option<Weekday>,
73
74    /// Day of the year (1--365 or 1--366 depending on the year).
75    pub ordinal: Option<u32>,
76
77    /// Day of the month (1--28, 1--29, 1--30 or 1--31 depending on the month).
78    pub day: Option<u32>,
79
80    /// Hour number divided by 12 (0--1). 0 indicates AM and 1 indicates PM.
81    pub hour_div_12: Option<u32>,
82
83    /// Hour number modulo 12 (0--11).
84    pub hour_mod_12: Option<u32>,
85
86    /// Minute number (0--59).
87    pub minute: Option<u32>,
88
89    /// Second number (0--60, accounting for leap seconds).
90    pub second: Option<u32>,
91
92    /// The number of nanoseconds since the whole second (0--999,999,999).
93    pub nanosecond: Option<u32>,
94
95    /// The number of non-leap seconds since the midnight UTC on January 1, 1970.
96    ///
97    /// This can be off by one if [`second`](#structfield.second) is 60 (a leap second).
98    pub timestamp: Option<i64>,
99
100    /// Offset from the local time to UTC, in seconds.
101    pub offset: Option<i32>,
102
103    /// A dummy field to make this type not fully destructible (required for API stability).
104    // TODO: Change this to `#[non_exhaustive]` (on the enum) with the next breaking release.
105    _dummy: (),
106}
107
108/// Checks if `old` is either empty or has the same value as `new` (i.e. "consistent"),
109/// and if it is empty, set `old` to `new` as well.
110#[inline]
111fn set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<()> {
112    if let Some(ref old) = *old {
113        if *old == new {
114            Ok(())
115        } else {
116            Err(IMPOSSIBLE)
117        }
118    } else {
119        *old = Some(new);
120        Ok(())
121    }
122}
123
124impl Parsed {
125    /// Returns the initial value of parsed parts.
126    #[must_use]
127    pub fn new() -> Parsed {
128        Parsed::default()
129    }
130
131    /// Tries to set the [`year`](#structfield.year) field from given value.
132    #[inline]
133    pub fn set_year(&mut self, value: i64) -> ParseResult<()> {
134        set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
135    }
136
137    /// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value.
138    #[inline]
139    pub fn set_year_div_100(&mut self, value: i64) -> ParseResult<()> {
140        if value < 0 {
141            return Err(OUT_OF_RANGE);
142        }
143        set_if_consistent(&mut self.year_div_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
144    }
145
146    /// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value.
147    #[inline]
148    pub fn set_year_mod_100(&mut self, value: i64) -> ParseResult<()> {
149        if value < 0 {
150            return Err(OUT_OF_RANGE);
151        }
152        set_if_consistent(&mut self.year_mod_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
153    }
154
155    /// Tries to set the [`isoyear`](#structfield.isoyear) field from given value.
156    #[inline]
157    pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> {
158        set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
159    }
160
161    /// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value.
162    #[inline]
163    pub fn set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()> {
164        if value < 0 {
165            return Err(OUT_OF_RANGE);
166        }
167        set_if_consistent(
168            &mut self.isoyear_div_100,
169            i32::try_from(value).map_err(|_| OUT_OF_RANGE)?,
170        )
171    }
172
173    /// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value.
174    #[inline]
175    pub fn set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()> {
176        if value < 0 {
177            return Err(OUT_OF_RANGE);
178        }
179        set_if_consistent(
180            &mut self.isoyear_mod_100,
181            i32::try_from(value).map_err(|_| OUT_OF_RANGE)?,
182        )
183    }
184
185    /// Tries to set the [`month`](#structfield.month) field from given value.
186    #[inline]
187    pub fn set_month(&mut self, value: i64) -> ParseResult<()> {
188        set_if_consistent(&mut self.month, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
189    }
190
191    /// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value.
192    #[inline]
193    pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> {
194        set_if_consistent(&mut self.week_from_sun, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
195    }
196
197    /// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value.
198    #[inline]
199    pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> {
200        set_if_consistent(&mut self.week_from_mon, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
201    }
202
203    /// Tries to set the [`isoweek`](#structfield.isoweek) field from given value.
204    #[inline]
205    pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> {
206        set_if_consistent(&mut self.isoweek, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
207    }
208
209    /// Tries to set the [`weekday`](#structfield.weekday) field from given value.
210    #[inline]
211    pub fn set_weekday(&mut self, value: Weekday) -> ParseResult<()> {
212        set_if_consistent(&mut self.weekday, value)
213    }
214
215    /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value.
216    #[inline]
217    pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> {
218        set_if_consistent(&mut self.ordinal, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
219    }
220
221    /// Tries to set the [`day`](#structfield.day) field from given value.
222    #[inline]
223    pub fn set_day(&mut self, value: i64) -> ParseResult<()> {
224        set_if_consistent(&mut self.day, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
225    }
226
227    /// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value.
228    /// (`false` for AM, `true` for PM)
229    #[inline]
230    pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> {
231        set_if_consistent(&mut self.hour_div_12, u32::from(value))
232    }
233
234    /// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from
235    /// given hour number in 12-hour clocks.
236    #[inline]
237    pub fn set_hour12(&mut self, value: i64) -> ParseResult<()> {
238        if !(1..=12).contains(&value) {
239            return Err(OUT_OF_RANGE);
240        }
241        set_if_consistent(&mut self.hour_mod_12, value as u32 % 12)
242    }
243
244    /// Tries to set both [`hour_div_12`](#structfield.hour_div_12) and
245    /// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value.
246    #[inline]
247    pub fn set_hour(&mut self, value: i64) -> ParseResult<()> {
248        let v = u32::try_from(value).map_err(|_| OUT_OF_RANGE)?;
249        set_if_consistent(&mut self.hour_div_12, v / 12)?;
250        set_if_consistent(&mut self.hour_mod_12, v % 12)?;
251        Ok(())
252    }
253
254    /// Tries to set the [`minute`](#structfield.minute) field from given value.
255    #[inline]
256    pub fn set_minute(&mut self, value: i64) -> ParseResult<()> {
257        set_if_consistent(&mut self.minute, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
258    }
259
260    /// Tries to set the [`second`](#structfield.second) field from given value.
261    #[inline]
262    pub fn set_second(&mut self, value: i64) -> ParseResult<()> {
263        set_if_consistent(&mut self.second, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
264    }
265
266    /// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value.
267    #[inline]
268    pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> {
269        set_if_consistent(&mut self.nanosecond, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
270    }
271
272    /// Tries to set the [`timestamp`](#structfield.timestamp) field from given value.
273    #[inline]
274    pub fn set_timestamp(&mut self, value: i64) -> ParseResult<()> {
275        set_if_consistent(&mut self.timestamp, value)
276    }
277
278    /// Tries to set the [`offset`](#structfield.offset) field from given value.
279    #[inline]
280    pub fn set_offset(&mut self, value: i64) -> ParseResult<()> {
281        set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
282    }
283
284    /// Returns a parsed naive date out of given fields.
285    ///
286    /// This method is able to determine the date from given subset of fields:
287    ///
288    /// - Year, month, day.
289    /// - Year, day of the year (ordinal).
290    /// - Year, week number counted from Sunday or Monday, day of the week.
291    /// - ISO week date.
292    ///
293    /// Gregorian year and ISO week date year can have their century number (`*_div_100`) omitted,
294    /// the two-digit year is used to guess the century number then.
295    pub fn to_naive_date(&self) -> ParseResult<NaiveDate> {
296        fn resolve_year(
297            y: Option<i32>,
298            q: Option<i32>,
299            r: Option<i32>,
300        ) -> ParseResult<Option<i32>> {
301            match (y, q, r) {
302                // if there is no further information, simply return the given full year.
303                // this is a common case, so let's avoid division here.
304                (y, None, None) => Ok(y),
305
306                // if there is a full year *and* also quotient and/or modulo,
307                // check if present quotient and/or modulo is consistent to the full year.
308                // since the presence of those fields means a positive full year,
309                // we should filter a negative full year first.
310                (Some(y), q, r @ Some(0..=99)) | (Some(y), q, r @ None) => {
311                    if y < 0 {
312                        return Err(OUT_OF_RANGE);
313                    }
314                    let q_ = y / 100;
315                    let r_ = y % 100;
316                    if q.unwrap_or(q_) == q_ && r.unwrap_or(r_) == r_ {
317                        Ok(Some(y))
318                    } else {
319                        Err(IMPOSSIBLE)
320                    }
321                }
322
323                // the full year is missing but we have quotient and modulo.
324                // reconstruct the full year. make sure that the result is always positive.
325                (None, Some(q), Some(r @ 0..=99)) => {
326                    if q < 0 {
327                        return Err(OUT_OF_RANGE);
328                    }
329                    let y = q.checked_mul(100).and_then(|v| v.checked_add(r));
330                    Ok(Some(y.ok_or(OUT_OF_RANGE)?))
331                }
332
333                // we only have modulo. try to interpret a modulo as a conventional two-digit year.
334                // note: we are affected by Rust issue #18060. avoid multiple range patterns.
335                (None, None, Some(r @ 0..=99)) => Ok(Some(r + if r < 70 { 2000 } else { 1900 })),
336
337                // otherwise it is an out-of-bound or insufficient condition.
338                (None, Some(_), None) => Err(NOT_ENOUGH),
339                (_, _, Some(_)) => Err(OUT_OF_RANGE),
340            }
341        }
342
343        let given_year = resolve_year(self.year, self.year_div_100, self.year_mod_100)?;
344        let given_isoyear = resolve_year(self.isoyear, self.isoyear_div_100, self.isoyear_mod_100)?;
345
346        // verify the normal year-month-day date.
347        let verify_ymd = |date: NaiveDate| {
348            let year = date.year();
349            let (year_div_100, year_mod_100) = if year >= 0 {
350                (Some(year / 100), Some(year % 100))
351            } else {
352                (None, None) // they should be empty to be consistent
353            };
354            let month = date.month();
355            let day = date.day();
356            self.year.unwrap_or(year) == year
357                && self.year_div_100.or(year_div_100) == year_div_100
358                && self.year_mod_100.or(year_mod_100) == year_mod_100
359                && self.month.unwrap_or(month) == month
360                && self.day.unwrap_or(day) == day
361        };
362
363        // verify the ISO week date.
364        let verify_isoweekdate = |date: NaiveDate| {
365            let week = date.iso_week();
366            let isoyear = week.year();
367            let isoweek = week.week();
368            let weekday = date.weekday();
369            let (isoyear_div_100, isoyear_mod_100) = if isoyear >= 0 {
370                (Some(isoyear / 100), Some(isoyear % 100))
371            } else {
372                (None, None) // they should be empty to be consistent
373            };
374            self.isoyear.unwrap_or(isoyear) == isoyear
375                && self.isoyear_div_100.or(isoyear_div_100) == isoyear_div_100
376                && self.isoyear_mod_100.or(isoyear_mod_100) == isoyear_mod_100
377                && self.isoweek.unwrap_or(isoweek) == isoweek
378                && self.weekday.unwrap_or(weekday) == weekday
379        };
380
381        // verify the ordinal and other (non-ISO) week dates.
382        let verify_ordinal = |date: NaiveDate| {
383            let ordinal = date.ordinal();
384            let week_from_sun = date.weeks_from(Weekday::Sun);
385            let week_from_mon = date.weeks_from(Weekday::Mon);
386            self.ordinal.unwrap_or(ordinal) == ordinal
387                && self.week_from_sun.map_or(week_from_sun, |v| v as i32) == week_from_sun
388                && self.week_from_mon.map_or(week_from_mon, |v| v as i32) == week_from_mon
389        };
390
391        // test several possibilities.
392        // tries to construct a full `NaiveDate` as much as possible, then verifies that
393        // it is consistent with other given fields.
394        let (verified, parsed_date) = match (given_year, given_isoyear, self) {
395            (Some(year), _, &Parsed { month: Some(month), day: Some(day), .. }) => {
396                // year, month, day
397                let date = NaiveDate::from_ymd_opt(year, month, day).ok_or(OUT_OF_RANGE)?;
398                (verify_isoweekdate(date) && verify_ordinal(date), date)
399            }
400
401            (Some(year), _, &Parsed { ordinal: Some(ordinal), .. }) => {
402                // year, day of the year
403                let date = NaiveDate::from_yo_opt(year, ordinal).ok_or(OUT_OF_RANGE)?;
404                (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
405            }
406
407            (
408                Some(year),
409                _,
410                &Parsed { week_from_sun: Some(week_from_sun), weekday: Some(weekday), .. },
411            ) => {
412                // year, week (starting at 1st Sunday), day of the week
413                let newyear = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?;
414                let firstweek = match newyear.weekday() {
415                    Weekday::Sun => 0,
416                    Weekday::Mon => 6,
417                    Weekday::Tue => 5,
418                    Weekday::Wed => 4,
419                    Weekday::Thu => 3,
420                    Weekday::Fri => 2,
421                    Weekday::Sat => 1,
422                };
423
424                // `firstweek+1`-th day of January is the beginning of the week 1.
425                if week_from_sun > 53 {
426                    return Err(OUT_OF_RANGE);
427                } // can it overflow?
428                let ndays = firstweek
429                    + (week_from_sun as i32 - 1) * 7
430                    + weekday.num_days_from_sunday() as i32;
431                let date = newyear
432                    .checked_add_signed(TimeDelta::days(i64::from(ndays)))
433                    .ok_or(OUT_OF_RANGE)?;
434                if date.year() != year {
435                    return Err(OUT_OF_RANGE);
436                } // early exit for correct error
437
438                (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
439            }
440
441            (
442                Some(year),
443                _,
444                &Parsed { week_from_mon: Some(week_from_mon), weekday: Some(weekday), .. },
445            ) => {
446                // year, week (starting at 1st Monday), day of the week
447                let newyear = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?;
448                let firstweek = match newyear.weekday() {
449                    Weekday::Sun => 1,
450                    Weekday::Mon => 0,
451                    Weekday::Tue => 6,
452                    Weekday::Wed => 5,
453                    Weekday::Thu => 4,
454                    Weekday::Fri => 3,
455                    Weekday::Sat => 2,
456                };
457
458                // `firstweek+1`-th day of January is the beginning of the week 1.
459                if week_from_mon > 53 {
460                    return Err(OUT_OF_RANGE);
461                } // can it overflow?
462                let ndays = firstweek
463                    + (week_from_mon as i32 - 1) * 7
464                    + weekday.num_days_from_monday() as i32;
465                let date = newyear
466                    .checked_add_signed(TimeDelta::days(i64::from(ndays)))
467                    .ok_or(OUT_OF_RANGE)?;
468                if date.year() != year {
469                    return Err(OUT_OF_RANGE);
470                } // early exit for correct error
471
472                (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
473            }
474
475            (_, Some(isoyear), &Parsed { isoweek: Some(isoweek), weekday: Some(weekday), .. }) => {
476                // ISO year, week, day of the week
477                let date = NaiveDate::from_isoywd_opt(isoyear, isoweek, weekday);
478                let date = date.ok_or(OUT_OF_RANGE)?;
479                (verify_ymd(date) && verify_ordinal(date), date)
480            }
481
482            (_, _, _) => return Err(NOT_ENOUGH),
483        };
484
485        if verified {
486            Ok(parsed_date)
487        } else {
488            Err(IMPOSSIBLE)
489        }
490    }
491
492    /// Returns a parsed naive time out of given fields.
493    ///
494    /// This method is able to determine the time from given subset of fields:
495    ///
496    /// - Hour, minute. (second and nanosecond assumed to be 0)
497    /// - Hour, minute, second. (nanosecond assumed to be 0)
498    /// - Hour, minute, second, nanosecond.
499    ///
500    /// It is able to handle leap seconds when given second is 60.
501    pub fn to_naive_time(&self) -> ParseResult<NaiveTime> {
502        let hour_div_12 = match self.hour_div_12 {
503            Some(v @ 0..=1) => v,
504            Some(_) => return Err(OUT_OF_RANGE),
505            None => return Err(NOT_ENOUGH),
506        };
507        let hour_mod_12 = match self.hour_mod_12 {
508            Some(v @ 0..=11) => v,
509            Some(_) => return Err(OUT_OF_RANGE),
510            None => return Err(NOT_ENOUGH),
511        };
512        let hour = hour_div_12 * 12 + hour_mod_12;
513
514        let minute = match self.minute {
515            Some(v @ 0..=59) => v,
516            Some(_) => return Err(OUT_OF_RANGE),
517            None => return Err(NOT_ENOUGH),
518        };
519
520        // we allow omitting seconds or nanoseconds, but they should be in the range.
521        let (second, mut nano) = match self.second.unwrap_or(0) {
522            v @ 0..=59 => (v, 0),
523            60 => (59, 1_000_000_000),
524            _ => return Err(OUT_OF_RANGE),
525        };
526        nano += match self.nanosecond {
527            Some(v @ 0..=999_999_999) if self.second.is_some() => v,
528            Some(0..=999_999_999) => return Err(NOT_ENOUGH), // second is missing
529            Some(_) => return Err(OUT_OF_RANGE),
530            None => 0,
531        };
532
533        NaiveTime::from_hms_nano_opt(hour, minute, second, nano).ok_or(OUT_OF_RANGE)
534    }
535
536    /// Returns a parsed naive date and time out of given fields,
537    /// except for the [`offset`](#structfield.offset) field (assumed to have a given value).
538    /// This is required for parsing a local time or other known-timezone inputs.
539    ///
540    /// This method is able to determine the combined date and time
541    /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field.
542    /// Either way those fields have to be consistent to each other.
543    pub fn to_naive_datetime_with_offset(&self, offset: i32) -> ParseResult<NaiveDateTime> {
544        let date = self.to_naive_date();
545        let time = self.to_naive_time();
546        if let (Ok(date), Ok(time)) = (date, time) {
547            let datetime = date.and_time(time);
548
549            // verify the timestamp field if any
550            // the following is safe, `timestamp` is very limited in range
551            let timestamp = datetime.timestamp() - i64::from(offset);
552            if let Some(given_timestamp) = self.timestamp {
553                // if `datetime` represents a leap second, it might be off by one second.
554                if given_timestamp != timestamp
555                    && !(datetime.nanosecond() >= 1_000_000_000 && given_timestamp == timestamp + 1)
556                {
557                    return Err(IMPOSSIBLE);
558                }
559            }
560
561            Ok(datetime)
562        } else if let Some(timestamp) = self.timestamp {
563            use super::ParseError as PE;
564            use super::ParseErrorKind::{Impossible, OutOfRange};
565
566            // if date and time is problematic already, there is no point proceeding.
567            // we at least try to give a correct error though.
568            match (date, time) {
569                (Err(PE(OutOfRange)), _) | (_, Err(PE(OutOfRange))) => return Err(OUT_OF_RANGE),
570                (Err(PE(Impossible)), _) | (_, Err(PE(Impossible))) => return Err(IMPOSSIBLE),
571                (_, _) => {} // one of them is insufficient
572            }
573
574            // reconstruct date and time fields from timestamp
575            let ts = timestamp.checked_add(i64::from(offset)).ok_or(OUT_OF_RANGE)?;
576            let datetime = NaiveDateTime::from_timestamp_opt(ts, 0);
577            let mut datetime = datetime.ok_or(OUT_OF_RANGE)?;
578
579            // fill year, ordinal, hour, minute and second fields from timestamp.
580            // if existing fields are consistent, this will allow the full date/time reconstruction.
581            let mut parsed = self.clone();
582            if parsed.second == Some(60) {
583                // `datetime.second()` cannot be 60, so this is the only case for a leap second.
584                match datetime.second() {
585                    // it's okay, just do not try to overwrite the existing field.
586                    59 => {}
587                    // `datetime` is known to be off by one second.
588                    0 => {
589                        datetime -= TimeDelta::seconds(1);
590                    }
591                    // otherwise it is impossible.
592                    _ => return Err(IMPOSSIBLE),
593                }
594            // ...and we have the correct candidates for other fields.
595            } else {
596                parsed.set_second(i64::from(datetime.second()))?;
597            }
598            parsed.set_year(i64::from(datetime.year()))?;
599            parsed.set_ordinal(i64::from(datetime.ordinal()))?; // more efficient than ymd
600            parsed.set_hour(i64::from(datetime.hour()))?;
601            parsed.set_minute(i64::from(datetime.minute()))?;
602
603            // validate other fields (e.g. week) and return
604            let date = parsed.to_naive_date()?;
605            let time = parsed.to_naive_time()?;
606            Ok(date.and_time(time))
607        } else {
608            // reproduce the previous error(s)
609            date?;
610            time?;
611            unreachable!()
612        }
613    }
614
615    /// Returns a parsed fixed time zone offset out of given fields.
616    pub fn to_fixed_offset(&self) -> ParseResult<FixedOffset> {
617        self.offset.and_then(FixedOffset::east_opt).ok_or(OUT_OF_RANGE)
618    }
619
620    /// Returns a parsed timezone-aware date and time out of given fields.
621    ///
622    /// This method is able to determine the combined date and time
623    /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field,
624    /// plus a time zone offset.
625    /// Either way those fields have to be consistent to each other.
626    pub fn to_datetime(&self) -> ParseResult<DateTime<FixedOffset>> {
627        // If there is no explicit offset, consider a timestamp value as indication of a UTC value.
628        let offset = match (self.offset, self.timestamp) {
629            (Some(off), _) => off,
630            (None, Some(_)) => 0, // UNIX timestamp may assume 0 offset
631            (None, None) => return Err(NOT_ENOUGH),
632        };
633        let datetime = self.to_naive_datetime_with_offset(offset)?;
634        let offset = FixedOffset::east_opt(offset).ok_or(OUT_OF_RANGE)?;
635
636        match offset.from_local_datetime(&datetime) {
637            LocalResult::None => Err(IMPOSSIBLE),
638            LocalResult::Single(t) => Ok(t),
639            LocalResult::Ambiguous(..) => Err(NOT_ENOUGH),
640        }
641    }
642
643    /// Returns a parsed timezone-aware date and time out of given fields,
644    /// with an additional `TimeZone` used to interpret and validate the local date.
645    ///
646    /// This method is able to determine the combined date and time
647    /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field,
648    /// plus a time zone offset.
649    /// Either way those fields have to be consistent to each other.
650    /// If parsed fields include an UTC offset, it also has to be consistent to
651    /// [`offset`](#structfield.offset).
652    pub fn to_datetime_with_timezone<Tz: TimeZone>(&self, tz: &Tz) -> ParseResult<DateTime<Tz>> {
653        // if we have `timestamp` specified, guess an offset from that.
654        let mut guessed_offset = 0;
655        if let Some(timestamp) = self.timestamp {
656            // make a naive `DateTime` from given timestamp and (if any) nanosecond.
657            // an empty `nanosecond` is always equal to zero, so missing nanosecond is fine.
658            let nanosecond = self.nanosecond.unwrap_or(0);
659            let dt = NaiveDateTime::from_timestamp_opt(timestamp, nanosecond);
660            let dt = dt.ok_or(OUT_OF_RANGE)?;
661            guessed_offset = tz.offset_from_utc_datetime(&dt).fix().local_minus_utc();
662        }
663
664        // checks if the given `DateTime` has a consistent `Offset` with given `self.offset`.
665        let check_offset = |dt: &DateTime<Tz>| {
666            if let Some(offset) = self.offset {
667                dt.offset().fix().local_minus_utc() == offset
668            } else {
669                true
670            }
671        };
672
673        // `guessed_offset` should be correct when `self.timestamp` is given.
674        // it will be 0 otherwise, but this is fine as the algorithm ignores offset for that case.
675        let datetime = self.to_naive_datetime_with_offset(guessed_offset)?;
676        match tz.from_local_datetime(&datetime) {
677            LocalResult::None => Err(IMPOSSIBLE),
678            LocalResult::Single(t) => {
679                if check_offset(&t) {
680                    Ok(t)
681                } else {
682                    Err(IMPOSSIBLE)
683                }
684            }
685            LocalResult::Ambiguous(min, max) => {
686                // try to disambiguate two possible local dates by offset.
687                match (check_offset(&min), check_offset(&max)) {
688                    (false, false) => Err(IMPOSSIBLE),
689                    (false, true) => Ok(max),
690                    (true, false) => Ok(min),
691                    (true, true) => Err(NOT_ENOUGH),
692                }
693            }
694        }
695    }
696}
697
698#[cfg(test)]
699mod tests {
700    use super::super::{IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
701    use super::Parsed;
702    use crate::naive::{NaiveDate, NaiveTime};
703    use crate::offset::{FixedOffset, TimeZone, Utc};
704    use crate::Datelike;
705    use crate::Weekday::*;
706
707    #[test]
708    fn test_parsed_set_fields() {
709        // year*, isoyear*
710        let mut p = Parsed::new();
711        assert_eq!(p.set_year(1987), Ok(()));
712        assert_eq!(p.set_year(1986), Err(IMPOSSIBLE));
713        assert_eq!(p.set_year(1988), Err(IMPOSSIBLE));
714        assert_eq!(p.set_year(1987), Ok(()));
715        assert_eq!(p.set_year_div_100(20), Ok(())); // independent to `year`
716        assert_eq!(p.set_year_div_100(21), Err(IMPOSSIBLE));
717        assert_eq!(p.set_year_div_100(19), Err(IMPOSSIBLE));
718        assert_eq!(p.set_year_mod_100(37), Ok(())); // ditto
719        assert_eq!(p.set_year_mod_100(38), Err(IMPOSSIBLE));
720        assert_eq!(p.set_year_mod_100(36), Err(IMPOSSIBLE));
721
722        let mut p = Parsed::new();
723        assert_eq!(p.set_year(0), Ok(()));
724        assert_eq!(p.set_year_div_100(0), Ok(()));
725        assert_eq!(p.set_year_mod_100(0), Ok(()));
726
727        let mut p = Parsed::new();
728        assert_eq!(p.set_year_div_100(-1), Err(OUT_OF_RANGE));
729        assert_eq!(p.set_year_mod_100(-1), Err(OUT_OF_RANGE));
730        assert_eq!(p.set_year(-1), Ok(()));
731        assert_eq!(p.set_year(-2), Err(IMPOSSIBLE));
732        assert_eq!(p.set_year(0), Err(IMPOSSIBLE));
733
734        let mut p = Parsed::new();
735        assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(OUT_OF_RANGE));
736        assert_eq!(p.set_year_div_100(8), Ok(()));
737        assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(OUT_OF_RANGE));
738
739        // month, week*, isoweek, ordinal, day, minute, second, nanosecond, offset
740        let mut p = Parsed::new();
741        assert_eq!(p.set_month(7), Ok(()));
742        assert_eq!(p.set_month(1), Err(IMPOSSIBLE));
743        assert_eq!(p.set_month(6), Err(IMPOSSIBLE));
744        assert_eq!(p.set_month(8), Err(IMPOSSIBLE));
745        assert_eq!(p.set_month(12), Err(IMPOSSIBLE));
746
747        let mut p = Parsed::new();
748        assert_eq!(p.set_month(8), Ok(()));
749        assert_eq!(p.set_month(0x1_0000_0008), Err(OUT_OF_RANGE));
750
751        // hour
752        let mut p = Parsed::new();
753        assert_eq!(p.set_hour(12), Ok(()));
754        assert_eq!(p.set_hour(11), Err(IMPOSSIBLE));
755        assert_eq!(p.set_hour(13), Err(IMPOSSIBLE));
756        assert_eq!(p.set_hour(12), Ok(()));
757        assert_eq!(p.set_ampm(false), Err(IMPOSSIBLE));
758        assert_eq!(p.set_ampm(true), Ok(()));
759        assert_eq!(p.set_hour12(12), Ok(()));
760        assert_eq!(p.set_hour12(0), Err(OUT_OF_RANGE)); // requires canonical representation
761        assert_eq!(p.set_hour12(1), Err(IMPOSSIBLE));
762        assert_eq!(p.set_hour12(11), Err(IMPOSSIBLE));
763
764        let mut p = Parsed::new();
765        assert_eq!(p.set_ampm(true), Ok(()));
766        assert_eq!(p.set_hour12(7), Ok(()));
767        assert_eq!(p.set_hour(7), Err(IMPOSSIBLE));
768        assert_eq!(p.set_hour(18), Err(IMPOSSIBLE));
769        assert_eq!(p.set_hour(19), Ok(()));
770
771        // timestamp
772        let mut p = Parsed::new();
773        assert_eq!(p.set_timestamp(1_234_567_890), Ok(()));
774        assert_eq!(p.set_timestamp(1_234_567_889), Err(IMPOSSIBLE));
775        assert_eq!(p.set_timestamp(1_234_567_891), Err(IMPOSSIBLE));
776    }
777
778    #[test]
779    fn test_parsed_to_naive_date() {
780        macro_rules! parse {
781            ($($k:ident: $v:expr),*) => (
782                Parsed { $($k: Some($v),)* ..Parsed::new() }.to_naive_date()
783            )
784        }
785
786        let ymd = |y, m, d| Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap());
787
788        // ymd: omission of fields
789        assert_eq!(parse!(), Err(NOT_ENOUGH));
790        assert_eq!(parse!(year: 1984), Err(NOT_ENOUGH));
791        assert_eq!(parse!(year: 1984, month: 1), Err(NOT_ENOUGH));
792        assert_eq!(parse!(year: 1984, month: 1, day: 2), ymd(1984, 1, 2));
793        assert_eq!(parse!(year: 1984, day: 2), Err(NOT_ENOUGH));
794        assert_eq!(parse!(year_div_100: 19), Err(NOT_ENOUGH));
795        assert_eq!(parse!(year_div_100: 19, year_mod_100: 84), Err(NOT_ENOUGH));
796        assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 1), Err(NOT_ENOUGH));
797        assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 1, day: 2), ymd(1984, 1, 2));
798        assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, day: 2), Err(NOT_ENOUGH));
799        assert_eq!(parse!(year_div_100: 19, month: 1, day: 2), Err(NOT_ENOUGH));
800        assert_eq!(parse!(year_mod_100: 70, month: 1, day: 2), ymd(1970, 1, 2));
801        assert_eq!(parse!(year_mod_100: 69, month: 1, day: 2), ymd(2069, 1, 2));
802
803        // ymd: out-of-range conditions
804        assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 2, day: 29), ymd(1984, 2, 29));
805        assert_eq!(
806            parse!(year_div_100: 19, year_mod_100: 83, month: 2, day: 29),
807            Err(OUT_OF_RANGE)
808        );
809        assert_eq!(
810            parse!(year_div_100: 19, year_mod_100: 83, month: 13, day: 1),
811            Err(OUT_OF_RANGE)
812        );
813        assert_eq!(
814            parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 31),
815            ymd(1983, 12, 31)
816        );
817        assert_eq!(
818            parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 32),
819            Err(OUT_OF_RANGE)
820        );
821        assert_eq!(
822            parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 0),
823            Err(OUT_OF_RANGE)
824        );
825        assert_eq!(
826            parse!(year_div_100: 19, year_mod_100: 100, month: 1, day: 1),
827            Err(OUT_OF_RANGE)
828        );
829        assert_eq!(parse!(year_div_100: 19, year_mod_100: -1, month: 1, day: 1), Err(OUT_OF_RANGE));
830        assert_eq!(parse!(year_div_100: 0, year_mod_100: 0, month: 1, day: 1), ymd(0, 1, 1));
831        assert_eq!(parse!(year_div_100: -1, year_mod_100: 42, month: 1, day: 1), Err(OUT_OF_RANGE));
832        let max_year = NaiveDate::MAX.year();
833        assert_eq!(
834            parse!(year_div_100: max_year / 100,
835                          year_mod_100: max_year % 100, month: 1, day: 1),
836            ymd(max_year, 1, 1)
837        );
838        assert_eq!(
839            parse!(year_div_100: (max_year + 1) / 100,
840                          year_mod_100: (max_year + 1) % 100, month: 1, day: 1),
841            Err(OUT_OF_RANGE)
842        );
843
844        // ymd: conflicting inputs
845        assert_eq!(parse!(year: 1984, year_div_100: 19, month: 1, day: 1), ymd(1984, 1, 1));
846        assert_eq!(parse!(year: 1984, year_div_100: 20, month: 1, day: 1), Err(IMPOSSIBLE));
847        assert_eq!(parse!(year: 1984, year_mod_100: 84, month: 1, day: 1), ymd(1984, 1, 1));
848        assert_eq!(parse!(year: 1984, year_mod_100: 83, month: 1, day: 1), Err(IMPOSSIBLE));
849        assert_eq!(
850            parse!(year: 1984, year_div_100: 19, year_mod_100: 84, month: 1, day: 1),
851            ymd(1984, 1, 1)
852        );
853        assert_eq!(
854            parse!(year: 1984, year_div_100: 18, year_mod_100: 94, month: 1, day: 1),
855            Err(IMPOSSIBLE)
856        );
857        assert_eq!(
858            parse!(year: 1984, year_div_100: 18, year_mod_100: 184, month: 1, day: 1),
859            Err(OUT_OF_RANGE)
860        );
861        assert_eq!(
862            parse!(year: -1, year_div_100: 0, year_mod_100: -1, month: 1, day: 1),
863            Err(OUT_OF_RANGE)
864        );
865        assert_eq!(
866            parse!(year: -1, year_div_100: -1, year_mod_100: 99, month: 1, day: 1),
867            Err(OUT_OF_RANGE)
868        );
869        assert_eq!(parse!(year: -1, year_div_100: 0, month: 1, day: 1), Err(OUT_OF_RANGE));
870        assert_eq!(parse!(year: -1, year_mod_100: 99, month: 1, day: 1), Err(OUT_OF_RANGE));
871
872        // weekdates
873        assert_eq!(parse!(year: 2000, week_from_mon: 0), Err(NOT_ENOUGH));
874        assert_eq!(parse!(year: 2000, week_from_sun: 0), Err(NOT_ENOUGH));
875        assert_eq!(parse!(year: 2000, weekday: Sun), Err(NOT_ENOUGH));
876        assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Fri), Err(OUT_OF_RANGE));
877        assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Fri), Err(OUT_OF_RANGE));
878        assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sat), ymd(2000, 1, 1));
879        assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Sat), ymd(2000, 1, 1));
880        assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sun), ymd(2000, 1, 2));
881        assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sun), ymd(2000, 1, 2));
882        assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Mon), ymd(2000, 1, 3));
883        assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Mon), ymd(2000, 1, 3));
884        assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sat), ymd(2000, 1, 8));
885        assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sat), ymd(2000, 1, 8));
886        assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sun), ymd(2000, 1, 9));
887        assert_eq!(parse!(year: 2000, week_from_sun: 2, weekday: Sun), ymd(2000, 1, 9));
888        assert_eq!(parse!(year: 2000, week_from_mon: 2, weekday: Mon), ymd(2000, 1, 10));
889        assert_eq!(parse!(year: 2000, week_from_sun: 52, weekday: Sat), ymd(2000, 12, 30));
890        assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Sun), ymd(2000, 12, 31));
891        assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Mon), Err(OUT_OF_RANGE));
892        assert_eq!(parse!(year: 2000, week_from_sun: 0xffffffff, weekday: Mon), Err(OUT_OF_RANGE));
893        assert_eq!(parse!(year: 2006, week_from_sun: 0, weekday: Sat), Err(OUT_OF_RANGE));
894        assert_eq!(parse!(year: 2006, week_from_sun: 1, weekday: Sun), ymd(2006, 1, 1));
895
896        // weekdates: conflicting inputs
897        assert_eq!(
898            parse!(year: 2000, week_from_mon: 1, week_from_sun: 1, weekday: Sat),
899            ymd(2000, 1, 8)
900        );
901        assert_eq!(
902            parse!(year: 2000, week_from_mon: 1, week_from_sun: 2, weekday: Sun),
903            ymd(2000, 1, 9)
904        );
905        assert_eq!(
906            parse!(year: 2000, week_from_mon: 1, week_from_sun: 1, weekday: Sun),
907            Err(IMPOSSIBLE)
908        );
909        assert_eq!(
910            parse!(year: 2000, week_from_mon: 2, week_from_sun: 2, weekday: Sun),
911            Err(IMPOSSIBLE)
912        );
913
914        // ISO weekdates
915        assert_eq!(parse!(isoyear: 2004, isoweek: 53), Err(NOT_ENOUGH));
916        assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Fri), ymd(2004, 12, 31));
917        assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Sat), ymd(2005, 1, 1));
918        assert_eq!(parse!(isoyear: 2004, isoweek: 0xffffffff, weekday: Sat), Err(OUT_OF_RANGE));
919        assert_eq!(parse!(isoyear: 2005, isoweek: 0, weekday: Thu), Err(OUT_OF_RANGE));
920        assert_eq!(parse!(isoyear: 2005, isoweek: 5, weekday: Thu), ymd(2005, 2, 3));
921        assert_eq!(parse!(isoyear: 2005, weekday: Thu), Err(NOT_ENOUGH));
922
923        // year and ordinal
924        assert_eq!(parse!(ordinal: 123), Err(NOT_ENOUGH));
925        assert_eq!(parse!(year: 2000, ordinal: 0), Err(OUT_OF_RANGE));
926        assert_eq!(parse!(year: 2000, ordinal: 1), ymd(2000, 1, 1));
927        assert_eq!(parse!(year: 2000, ordinal: 60), ymd(2000, 2, 29));
928        assert_eq!(parse!(year: 2000, ordinal: 61), ymd(2000, 3, 1));
929        assert_eq!(parse!(year: 2000, ordinal: 366), ymd(2000, 12, 31));
930        assert_eq!(parse!(year: 2000, ordinal: 367), Err(OUT_OF_RANGE));
931        assert_eq!(parse!(year: 2000, ordinal: 0xffffffff), Err(OUT_OF_RANGE));
932        assert_eq!(parse!(year: 2100, ordinal: 0), Err(OUT_OF_RANGE));
933        assert_eq!(parse!(year: 2100, ordinal: 1), ymd(2100, 1, 1));
934        assert_eq!(parse!(year: 2100, ordinal: 59), ymd(2100, 2, 28));
935        assert_eq!(parse!(year: 2100, ordinal: 60), ymd(2100, 3, 1));
936        assert_eq!(parse!(year: 2100, ordinal: 365), ymd(2100, 12, 31));
937        assert_eq!(parse!(year: 2100, ordinal: 366), Err(OUT_OF_RANGE));
938        assert_eq!(parse!(year: 2100, ordinal: 0xffffffff), Err(OUT_OF_RANGE));
939
940        // more complex cases
941        assert_eq!(
942            parse!(year: 2014, month: 12, day: 31, ordinal: 365, isoyear: 2015, isoweek: 1,
943                          week_from_sun: 52, week_from_mon: 52, weekday: Wed),
944            ymd(2014, 12, 31)
945        );
946        assert_eq!(
947            parse!(year: 2014, month: 12, ordinal: 365, isoyear: 2015, isoweek: 1,
948                          week_from_sun: 52, week_from_mon: 52),
949            ymd(2014, 12, 31)
950        );
951        assert_eq!(
952            parse!(year: 2014, month: 12, day: 31, ordinal: 365, isoyear: 2014, isoweek: 53,
953                          week_from_sun: 52, week_from_mon: 52, weekday: Wed),
954            Err(IMPOSSIBLE)
955        ); // no ISO week date 2014-W53-3
956        assert_eq!(
957            parse!(year: 2012, isoyear: 2015, isoweek: 1,
958                          week_from_sun: 52, week_from_mon: 52),
959            Err(NOT_ENOUGH)
960        ); // ambiguous (2014-12-29, 2014-12-30, 2014-12-31)
961        assert_eq!(parse!(year_div_100: 20, isoyear_mod_100: 15, ordinal: 366), Err(NOT_ENOUGH));
962        // technically unique (2014-12-31) but Chrono gives up
963    }
964
965    #[test]
966    fn test_parsed_to_naive_time() {
967        macro_rules! parse {
968            ($($k:ident: $v:expr),*) => (
969                Parsed { $($k: Some($v),)* ..Parsed::new() }.to_naive_time()
970            )
971        }
972
973        let hms = |h, m, s| Ok(NaiveTime::from_hms_opt(h, m, s).unwrap());
974        let hmsn = |h, m, s, n| Ok(NaiveTime::from_hms_nano_opt(h, m, s, n).unwrap());
975
976        // omission of fields
977        assert_eq!(parse!(), Err(NOT_ENOUGH));
978        assert_eq!(parse!(hour_div_12: 0), Err(NOT_ENOUGH));
979        assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1), Err(NOT_ENOUGH));
980        assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23), hms(1, 23, 0));
981        assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 45), hms(1, 23, 45));
982        assert_eq!(
983            parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 45,
984                          nanosecond: 678_901_234),
985            hmsn(1, 23, 45, 678_901_234)
986        );
987        assert_eq!(parse!(hour_div_12: 1, hour_mod_12: 11, minute: 45, second: 6), hms(23, 45, 6));
988        assert_eq!(parse!(hour_mod_12: 1, minute: 23), Err(NOT_ENOUGH));
989        assert_eq!(
990            parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, nanosecond: 456_789_012),
991            Err(NOT_ENOUGH)
992        );
993
994        // out-of-range conditions
995        assert_eq!(parse!(hour_div_12: 2, hour_mod_12: 0, minute: 0), Err(OUT_OF_RANGE));
996        assert_eq!(parse!(hour_div_12: 1, hour_mod_12: 12, minute: 0), Err(OUT_OF_RANGE));
997        assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 60), Err(OUT_OF_RANGE));
998        assert_eq!(
999            parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 61),
1000            Err(OUT_OF_RANGE)
1001        );
1002        assert_eq!(
1003            parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 34,
1004                          nanosecond: 1_000_000_000),
1005            Err(OUT_OF_RANGE)
1006        );
1007
1008        // leap seconds
1009        assert_eq!(
1010            parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 60),
1011            hmsn(1, 23, 59, 1_000_000_000)
1012        );
1013        assert_eq!(
1014            parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 60,
1015                          nanosecond: 999_999_999),
1016            hmsn(1, 23, 59, 1_999_999_999)
1017        );
1018    }
1019
1020    #[test]
1021    fn test_parsed_to_naive_datetime_with_offset() {
1022        macro_rules! parse {
1023            (offset = $offset:expr; $($k:ident: $v:expr),*) => (
1024                Parsed { $($k: Some($v),)* ..Parsed::new() }.to_naive_datetime_with_offset($offset)
1025            );
1026            ($($k:ident: $v:expr),*) => (parse!(offset = 0; $($k: $v),*))
1027        }
1028
1029        let ymdhms = |y, m, d, h, n, s| {
1030            Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap())
1031        };
1032        let ymdhmsn = |y, m, d, h, n, s, nano| {
1033            Ok(NaiveDate::from_ymd_opt(y, m, d).unwrap().and_hms_nano_opt(h, n, s, nano).unwrap())
1034        };
1035
1036        // omission of fields
1037        assert_eq!(parse!(), Err(NOT_ENOUGH));
1038        assert_eq!(
1039            parse!(year: 2015, month: 1, day: 30,
1040                          hour_div_12: 1, hour_mod_12: 2, minute: 38),
1041            ymdhms(2015, 1, 30, 14, 38, 0)
1042        );
1043        assert_eq!(
1044            parse!(year: 1997, month: 1, day: 30,
1045                          hour_div_12: 1, hour_mod_12: 2, minute: 38, second: 5),
1046            ymdhms(1997, 1, 30, 14, 38, 5)
1047        );
1048        assert_eq!(
1049            parse!(year: 2012, ordinal: 34, hour_div_12: 0, hour_mod_12: 5,
1050                          minute: 6, second: 7, nanosecond: 890_123_456),
1051            ymdhmsn(2012, 2, 3, 5, 6, 7, 890_123_456)
1052        );
1053        assert_eq!(parse!(timestamp: 0), ymdhms(1970, 1, 1, 0, 0, 0));
1054        assert_eq!(parse!(timestamp: 1, nanosecond: 0), ymdhms(1970, 1, 1, 0, 0, 1));
1055        assert_eq!(parse!(timestamp: 1, nanosecond: 1), ymdhmsn(1970, 1, 1, 0, 0, 1, 1));
1056        assert_eq!(parse!(timestamp: 1_420_000_000), ymdhms(2014, 12, 31, 4, 26, 40));
1057        assert_eq!(parse!(timestamp: -0x1_0000_0000), ymdhms(1833, 11, 24, 17, 31, 44));
1058
1059        // full fields
1060        assert_eq!(
1061            parse!(year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31,
1062                          ordinal: 365, isoyear: 2015, isoyear_div_100: 20, isoyear_mod_100: 15,
1063                          isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed,
1064                          hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40,
1065                          nanosecond: 12_345_678, timestamp: 1_420_000_000),
1066            ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678)
1067        );
1068        assert_eq!(
1069            parse!(year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31,
1070                          ordinal: 365, isoyear: 2015, isoyear_div_100: 20, isoyear_mod_100: 15,
1071                          isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed,
1072                          hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40,
1073                          nanosecond: 12_345_678, timestamp: 1_419_999_999),
1074            Err(IMPOSSIBLE)
1075        );
1076        assert_eq!(
1077            parse!(offset = 32400;
1078                          year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31,
1079                          ordinal: 365, isoyear: 2015, isoyear_div_100: 20, isoyear_mod_100: 15,
1080                          isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed,
1081                          hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40,
1082                          nanosecond: 12_345_678, timestamp: 1_419_967_600),
1083            ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678)
1084        );
1085
1086        // more timestamps
1087        let max_days_from_year_1970 =
1088            NaiveDate::MAX.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
1089        let year_0_from_year_1970 = NaiveDate::from_ymd_opt(0, 1, 1)
1090            .unwrap()
1091            .signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
1092        let min_days_from_year_1970 =
1093            NaiveDate::MIN.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap());
1094        assert_eq!(
1095            parse!(timestamp: min_days_from_year_1970.num_seconds()),
1096            ymdhms(NaiveDate::MIN.year(), 1, 1, 0, 0, 0)
1097        );
1098        assert_eq!(
1099            parse!(timestamp: year_0_from_year_1970.num_seconds()),
1100            ymdhms(0, 1, 1, 0, 0, 0)
1101        );
1102        assert_eq!(
1103            parse!(timestamp: max_days_from_year_1970.num_seconds() + 86399),
1104            ymdhms(NaiveDate::MAX.year(), 12, 31, 23, 59, 59)
1105        );
1106
1107        // leap seconds #1: partial fields
1108        assert_eq!(parse!(second: 59, timestamp: 1_341_100_798), Err(IMPOSSIBLE));
1109        assert_eq!(parse!(second: 59, timestamp: 1_341_100_799), ymdhms(2012, 6, 30, 23, 59, 59));
1110        assert_eq!(parse!(second: 59, timestamp: 1_341_100_800), Err(IMPOSSIBLE));
1111        assert_eq!(
1112            parse!(second: 60, timestamp: 1_341_100_799),
1113            ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
1114        );
1115        assert_eq!(
1116            parse!(second: 60, timestamp: 1_341_100_800),
1117            ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
1118        );
1119        assert_eq!(parse!(second: 0, timestamp: 1_341_100_800), ymdhms(2012, 7, 1, 0, 0, 0));
1120        assert_eq!(parse!(second: 1, timestamp: 1_341_100_800), Err(IMPOSSIBLE));
1121        assert_eq!(parse!(second: 60, timestamp: 1_341_100_801), Err(IMPOSSIBLE));
1122
1123        // leap seconds #2: full fields
1124        // we need to have separate tests for them since it uses another control flow.
1125        assert_eq!(
1126            parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1127                          minute: 59, second: 59, timestamp: 1_341_100_798),
1128            Err(IMPOSSIBLE)
1129        );
1130        assert_eq!(
1131            parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1132                          minute: 59, second: 59, timestamp: 1_341_100_799),
1133            ymdhms(2012, 6, 30, 23, 59, 59)
1134        );
1135        assert_eq!(
1136            parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1137                          minute: 59, second: 59, timestamp: 1_341_100_800),
1138            Err(IMPOSSIBLE)
1139        );
1140        assert_eq!(
1141            parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1142                          minute: 59, second: 60, timestamp: 1_341_100_799),
1143            ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
1144        );
1145        assert_eq!(
1146            parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1147                          minute: 59, second: 60, timestamp: 1_341_100_800),
1148            ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
1149        );
1150        assert_eq!(
1151            parse!(year: 2012, ordinal: 183, hour_div_12: 0, hour_mod_12: 0,
1152                          minute: 0, second: 0, timestamp: 1_341_100_800),
1153            ymdhms(2012, 7, 1, 0, 0, 0)
1154        );
1155        assert_eq!(
1156            parse!(year: 2012, ordinal: 183, hour_div_12: 0, hour_mod_12: 0,
1157                          minute: 0, second: 1, timestamp: 1_341_100_800),
1158            Err(IMPOSSIBLE)
1159        );
1160        assert_eq!(
1161            parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11,
1162                          minute: 59, second: 60, timestamp: 1_341_100_801),
1163            Err(IMPOSSIBLE)
1164        );
1165
1166        // error codes
1167        assert_eq!(
1168            parse!(year: 2015, month: 1, day: 20, weekday: Tue,
1169                          hour_div_12: 2, hour_mod_12: 1, minute: 35, second: 20),
1170            Err(OUT_OF_RANGE)
1171        ); // `hour_div_12` is out of range
1172    }
1173
1174    #[test]
1175    fn test_parsed_to_datetime() {
1176        macro_rules! parse {
1177            ($($k:ident: $v:expr),*) => (
1178                Parsed { $($k: Some($v),)* ..Parsed::new() }.to_datetime()
1179            )
1180        }
1181
1182        let ymdhmsn = |y, m, d, h, n, s, nano, off| {
1183            Ok(FixedOffset::east_opt(off)
1184                .unwrap()
1185                .from_local_datetime(
1186                    &NaiveDate::from_ymd_opt(y, m, d)
1187                        .unwrap()
1188                        .and_hms_nano_opt(h, n, s, nano)
1189                        .unwrap(),
1190                )
1191                .unwrap())
1192        };
1193
1194        assert_eq!(parse!(offset: 0), Err(NOT_ENOUGH));
1195        assert_eq!(
1196            parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
1197                          minute: 26, second: 40, nanosecond: 12_345_678),
1198            Err(NOT_ENOUGH)
1199        );
1200        assert_eq!(
1201            parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
1202                          minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
1203            ymdhmsn(2014, 12, 31, 4, 26, 40, 12_345_678, 0)
1204        );
1205        assert_eq!(
1206            parse!(year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1,
1207                          minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
1208            ymdhmsn(2014, 12, 31, 13, 26, 40, 12_345_678, 32400)
1209        );
1210        assert_eq!(
1211            parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 1,
1212                          minute: 42, second: 4, nanosecond: 12_345_678, offset: -9876),
1213            ymdhmsn(2014, 12, 31, 1, 42, 4, 12_345_678, -9876)
1214        );
1215        assert_eq!(
1216            parse!(year: 2015, ordinal: 1, hour_div_12: 0, hour_mod_12: 4,
1217                          minute: 26, second: 40, nanosecond: 12_345_678, offset: 86_400),
1218            Err(OUT_OF_RANGE)
1219        ); // `FixedOffset` does not support such huge offset
1220    }
1221
1222    #[test]
1223    fn test_parsed_to_datetime_with_timezone() {
1224        macro_rules! parse {
1225            ($tz:expr; $($k:ident: $v:expr),*) => (
1226                Parsed { $($k: Some($v),)* ..Parsed::new() }.to_datetime_with_timezone(&$tz)
1227            )
1228        }
1229
1230        // single result from ymdhms
1231        assert_eq!(
1232            parse!(Utc;
1233                          year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
1234                          minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
1235            Ok(Utc
1236                .from_local_datetime(
1237                    &NaiveDate::from_ymd_opt(2014, 12, 31)
1238                        .unwrap()
1239                        .and_hms_nano_opt(4, 26, 40, 12_345_678)
1240                        .unwrap()
1241                )
1242                .unwrap())
1243        );
1244        assert_eq!(
1245            parse!(Utc;
1246                          year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1,
1247                          minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
1248            Err(IMPOSSIBLE)
1249        );
1250        assert_eq!(
1251            parse!(FixedOffset::east_opt(32400).unwrap();
1252                          year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
1253                          minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
1254            Err(IMPOSSIBLE)
1255        );
1256        assert_eq!(
1257            parse!(FixedOffset::east_opt(32400).unwrap();
1258                          year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1,
1259                          minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
1260            Ok(FixedOffset::east_opt(32400)
1261                .unwrap()
1262                .from_local_datetime(
1263                    &NaiveDate::from_ymd_opt(2014, 12, 31)
1264                        .unwrap()
1265                        .and_hms_nano_opt(13, 26, 40, 12_345_678)
1266                        .unwrap()
1267                )
1268                .unwrap())
1269        );
1270
1271        // single result from timestamp
1272        assert_eq!(
1273            parse!(Utc; timestamp: 1_420_000_000, offset: 0),
1274            Ok(Utc.with_ymd_and_hms(2014, 12, 31, 4, 26, 40).unwrap())
1275        );
1276        assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 32400), Err(IMPOSSIBLE));
1277        assert_eq!(
1278            parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 0),
1279            Err(IMPOSSIBLE)
1280        );
1281        assert_eq!(
1282            parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 32400),
1283            Ok(FixedOffset::east_opt(32400)
1284                .unwrap()
1285                .with_ymd_and_hms(2014, 12, 31, 13, 26, 40)
1286                .unwrap())
1287        );
1288
1289        // TODO test with a variable time zone (for None and Ambiguous cases)
1290    }
1291
1292    #[test]
1293    fn issue_551() {
1294        use crate::Weekday;
1295        let mut parsed = Parsed::new();
1296
1297        parsed.year = Some(2002);
1298        parsed.week_from_mon = Some(22);
1299        parsed.weekday = Some(Weekday::Mon);
1300        assert_eq!(NaiveDate::from_ymd_opt(2002, 6, 3).unwrap(), parsed.to_naive_date().unwrap());
1301
1302        parsed.year = Some(2001);
1303        assert_eq!(NaiveDate::from_ymd_opt(2001, 5, 28).unwrap(), parsed.to_naive_date().unwrap());
1304    }
1305}