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