Skip to main content

chrono/format/
parsed.rs

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