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