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