1 // This is a part of Chrono.
2 // See README.md and LICENSE.txt for details.
3 
4 //! A collection of parsed date and time items.
5 //! They can be constructed incrementally while being checked for consistency.
6 
7 use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
8 use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
9 use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone};
10 use 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)]
21 pub 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]
set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<()>111 fn 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 
124 impl Parsed {
125     /// Returns the initial value of parsed parts.
126     #[must_use]
new() -> Parsed127     pub fn new() -> Parsed {
128         Parsed::default()
129     }
130 
131     /// Tries to set the [`year`](#structfield.year) field from given value.
132     #[inline]
set_year(&mut self, value: i64) -> ParseResult<()>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]
set_year_div_100(&mut self, value: i64) -> ParseResult<()>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]
set_year_mod_100(&mut self, value: i64) -> ParseResult<()>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]
set_isoyear(&mut self, value: i64) -> ParseResult<()>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]
set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()>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]
set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()>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]
set_month(&mut self, value: i64) -> ParseResult<()>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]
set_week_from_sun(&mut self, value: i64) -> ParseResult<()>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]
set_week_from_mon(&mut self, value: i64) -> ParseResult<()>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]
set_isoweek(&mut self, value: i64) -> ParseResult<()>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]
set_weekday(&mut self, value: Weekday) -> ParseResult<()>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]
set_ordinal(&mut self, value: i64) -> ParseResult<()>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]
set_day(&mut self, value: i64) -> ParseResult<()>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]
set_ampm(&mut self, value: bool) -> ParseResult<()>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]
set_hour12(&mut self, value: i64) -> ParseResult<()>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]
set_hour(&mut self, value: i64) -> ParseResult<()>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]
set_minute(&mut self, value: i64) -> ParseResult<()>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]
set_second(&mut self, value: i64) -> ParseResult<()>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]
set_nanosecond(&mut self, value: i64) -> ParseResult<()>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]
set_timestamp(&mut self, value: i64) -> ParseResult<()>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]
set_offset(&mut self, value: i64) -> ParseResult<()>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.
to_naive_date(&self) -> ParseResult<NaiveDate>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.
to_naive_time(&self) -> ParseResult<NaiveTime>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.
to_naive_datetime_with_offset(&self, offset: i32) -> ParseResult<NaiveDateTime>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.
to_fixed_offset(&self) -> ParseResult<FixedOffset>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.
to_datetime(&self) -> ParseResult<DateTime<FixedOffset>>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).
to_datetime_with_timezone<Tz: TimeZone>(&self, tz: &Tz) -> ParseResult<DateTime<Tz>>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)]
699 mod 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]
test_parsed_set_fields()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]
test_parsed_to_naive_date()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]
test_parsed_to_naive_time()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]
test_parsed_to_naive_datetime_with_offset()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]
test_parsed_to_datetime()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]
test_parsed_to_datetime_with_timezone()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]
issue_551()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 }
1306