1 // This is a part of Chrono.
2 // See README.md and LICENSE.txt for details.
4 //! A collection of parsed date and time items.
5 //! They can be constructed incrementally while being checked for consistency.
7 use num_integer
::div_rem
;
8 use num_traits
::ToPrimitive
;
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
;
16 use crate::{Datelike, Timelike}
;
18 /// Parsed parts of date and time. There are two classes of methods:
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).
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)]
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>,
33 /// Year divided by 100. Implies that the year is >= 1 BCE when set.
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>,
40 /// Year modulo 100. Implies that the year is >= 1 BCE when set.
41 pub year_mod_100
: Option
<i32>,
43 /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date).
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>,
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.
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>,
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>,
62 pub month
: Option
<u32>,
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>,
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>,
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>,
77 pub weekday
: Option
<Weekday
>,
79 /// Day of the year (1--365 or 1--366 depending on the year).
80 pub ordinal
: Option
<u32>,
82 /// Day of the month (1--28, 1--29, 1--30 or 1--31 depending on the month).
85 /// Hour number divided by 12 (0--1). 0 indicates AM and 1 indicates PM.
86 pub hour_div_12
: Option
<u32>,
88 /// Hour number modulo 12 (0--11).
89 pub hour_mod_12
: Option
<u32>,
91 /// Minute number (0--59).
92 pub minute
: Option
<u32>,
94 /// Second number (0--60, accounting for leap seconds).
95 pub second
: Option
<u32>,
97 /// The number of nanoseconds since the whole second (0--999,999,999).
98 pub nanosecond
: Option
<u32>,
100 /// The number of non-leap seconds since the midnight UTC on January 1, 1970.
102 /// This can be off by one if [`second`](#structfield.second) is 60 (a leap second).
103 pub timestamp
: Option
<i64>,
105 /// Offset from the local time to UTC, in seconds.
106 pub offset
: Option
<i32>,
108 /// A dummy field to make this type not fully destructible (required for API stability).
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.
115 fn set_if_consistent
<T
: PartialEq
>(old
: &mut Option
<T
>, new
: T
) -> ParseResult
<()> {
116 if let Some(ref old
) = *old
{
129 /// Returns the initial value of parsed parts.
130 pub fn new() -> Parsed
{
134 /// Tries to set the [`year`](#structfield.year) field from given value.
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
)?
)
140 /// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value.
142 pub fn set_year_div_100(&mut self, value
: i64) -> ParseResult
<()> {
144 return Err(OUT_OF_RANGE
);
146 set_if_consistent(&mut self.year_div_100
, value
.to_i32().ok_or(OUT_OF_RANGE
)?
)
149 /// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value.
151 pub fn set_year_mod_100(&mut self, value
: i64) -> ParseResult
<()> {
153 return Err(OUT_OF_RANGE
);
155 set_if_consistent(&mut self.year_mod_100
, value
.to_i32().ok_or(OUT_OF_RANGE
)?
)
158 /// Tries to set the [`isoyear`](#structfield.isoyear) field from given value.
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
)?
)
164 /// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value.
166 pub fn set_isoyear_div_100(&mut self, value
: i64) -> ParseResult
<()> {
168 return Err(OUT_OF_RANGE
);
170 set_if_consistent(&mut self.isoyear_div_100
, value
.to_i32().ok_or(OUT_OF_RANGE
)?
)
173 /// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value.
175 pub fn set_isoyear_mod_100(&mut self, value
: i64) -> ParseResult
<()> {
177 return Err(OUT_OF_RANGE
);
179 set_if_consistent(&mut self.isoyear_mod_100
, value
.to_i32().ok_or(OUT_OF_RANGE
)?
)
182 /// Tries to set the [`month`](#structfield.month) field from given value.
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
)?
)
188 /// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value.
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
)?
)
194 /// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value.
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
)?
)
200 /// Tries to set the [`isoweek`](#structfield.isoweek) field from given value.
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
)?
)
206 /// Tries to set the [`weekday`](#structfield.weekday) field from given value.
208 pub fn set_weekday(&mut self, value
: Weekday
) -> ParseResult
<()> {
209 set_if_consistent(&mut self.weekday
, value
)
212 /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value.
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
)?
)
218 /// Tries to set the [`day`](#structfield.day) field from given value.
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
)?
)
224 /// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value.
225 /// (`false` for AM, `true` for PM)
227 pub fn set_ampm(&mut self, value
: bool
) -> ParseResult
<()> {
228 set_if_consistent(&mut self.hour_div_12
, u32::from(value
))
231 /// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from
232 /// given hour number in 12-hour clocks.
234 pub fn set_hour12(&mut self, value
: i64) -> ParseResult
<()> {
235 if !(1..=12).contains(&value
) {
236 return Err(OUT_OF_RANGE
);
238 set_if_consistent(&mut self.hour_mod_12
, value
as u32 % 12)
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.
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)?
;
251 /// Tries to set the [`minute`](#structfield.minute) field from given value.
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
)?
)
257 /// Tries to set the [`second`](#structfield.second) field from given value.
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
)?
)
263 /// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value.
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
)?
)
269 /// Tries to set the [`timestamp`](#structfield.timestamp) field from given value.
271 pub fn set_timestamp(&mut self, value
: i64) -> ParseResult
<()> {
272 set_if_consistent(&mut self.timestamp
, value
)
275 /// Tries to set the [`offset`](#structfield.offset) field from given value.
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
)?
)
281 /// Returns a parsed naive date out of given fields.
283 /// This method is able to determine the date from given subset of fields:
285 /// - Year, month, day.
286 /// - Year, day of the year (ordinal).
287 /// - Year, week number counted from Sunday or Monday, day of the week.
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
> {
297 ) -> ParseResult
<Option
<i32>> {
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
),
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
) => {
309 return Err(OUT_OF_RANGE
);
311 let (q_
, r_
) = div_rem(y
, 100);
312 if q
.unwrap_or(q_
) == q_
&& r
.unwrap_or(r_
) == r_
{
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)) => {
323 return Err(OUT_OF_RANGE
);
325 let y
= q
.checked_mul(100).and_then(|v
| v
.checked_add(r
));
326 Ok(Some(y
.ok_or(OUT_OF_RANGE
)?
))
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 }
)),
333 // otherwise it is an out-of-bound or insufficient condition.
334 (None
, Some(_
), None
) => Err(NOT_ENOUGH
),
335 (_
, _
, Some(_
)) => Err(OUT_OF_RANGE
),
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
)?
;
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);
349 (None
, None
) // they should be empty to be consistent
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
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);
370 (None
, None
) // they should be empty to be consistent
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
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
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), .. }
) => {
395 let date
= NaiveDate
::from_ymd_opt(year
, month
, day
).ok_or(OUT_OF_RANGE
)?
;
396 (verify_isoweekdate(date
) && verify_ordinal(date
), date
)
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
)
408 &Parsed { week_from_sun: Some(week_from_sun), weekday: Some(weekday), .. }
,
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() {
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;
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
436 (verify_ymd(date
) && verify_isoweekdate(date
) && verify_ordinal(date
), date
)
442 &Parsed { week_from_mon: Some(week_from_mon), weekday: Some(weekday), .. }
,
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() {
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;
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
470 (verify_ymd(date
) && verify_isoweekdate(date
) && verify_ordinal(date
), date
)
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
)
480 (_
, _
, _
) => return Err(NOT_ENOUGH
),
490 /// Returns a parsed naive time out of given fields.
492 /// This method is able to determine the time from given subset of fields:
494 /// - Hour, minute. (second and nanosecond assumed to be 0)
495 /// - Hour, minute, second. (nanosecond assumed to be 0)
496 /// - Hour, minute, second, nanosecond.
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
),
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
),
510 let hour
= hour_div_12
* 12 + hour_mod_12
;
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
),
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
),
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
),
531 NaiveTime
::from_hms_nano_opt(hour
, minute
, second
, nano
).ok_or(OUT_OF_RANGE
)
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.
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
);
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)
555 return Err(IMPOSSIBLE
);
560 } else if let Some(timestamp
) = self.timestamp
{
561 use super::ParseError
as PE
;
562 use super::ParseErrorKind
::{Impossible, OutOfRange}
;
564 // if date and time is problematic already, there is no point proceeding.
565 // we at least try to give a correct error though.
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
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
)?
;
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.
585 // `datetime` is known to be off by one second.
587 datetime
-= OldDuration
::seconds(1);
589 // otherwise it is impossible.
590 _
=> return Err(IMPOSSIBLE
),
592 // ...and we have the correct candidates for other fields.
594 parsed
.set_second(i64::from(datetime
.second()))?
;
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()))?
;
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
))
606 // reproduce the previous error(s)
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
)
618 /// Returns a parsed timezone-aware date and time out of given fields.
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
)?
;
629 // this is used to prevent an overflow when calling FixedOffset::from_local_datetime
631 .checked_sub_signed(OldDuration
::seconds(i64::from(offset
.local_minus_utc())))
632 .ok_or(OUT_OF_RANGE
)?
;
634 match offset
.from_local_datetime(&datetime
) {
635 LocalResult
::None
=> Err(IMPOSSIBLE
),
636 LocalResult
::Single(t
) => Ok(t
),
637 LocalResult
::Ambiguous(..) => Err(NOT_ENOUGH
),
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.
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();
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
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
) {
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
),
698 use super::super::{IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE}
;
700 use crate::naive
::{NaiveDate, NaiveTime}
;
701 use crate::offset
::{FixedOffset, TimeZone, Utc}
;
703 use crate::Weekday
::*;
706 fn test_parsed_set_fields() {
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
));
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(()));
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
));
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
));
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
));
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
));
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
));
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(()));
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
));
777 fn test_parsed_to_naive_date() {
779 ($
($k
:ident
: $v
:expr
),*) => (
780 Parsed { $($k: Some($v),)* ..Parsed::new() }
.to_naive_date()
784 let ymd
= |y
, m
, d
| Ok(NaiveDate
::from_ymd_opt(y
, m
, d
).unwrap());
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));
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));
804 parse
!(year_div_100
: 19, year_mod_100
: 83, month
: 2, day
: 29),
808 parse
!(year_div_100
: 19, year_mod_100
: 83, month
: 13, day
: 1),
812 parse
!(year_div_100
: 19, year_mod_100
: 83, month
: 12, day
: 31),
816 parse
!(year_div_100
: 19, year_mod_100
: 83, month
: 12, day
: 32),
820 parse
!(year_div_100
: 19, year_mod_100
: 83, month
: 12, day
: 0),
824 parse
!(year_div_100
: 19, year_mod_100
: 100, month
: 1, day
: 1),
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();
832 parse
!(year_div_100
: max_year
/ 100,
833 year_mod_100
: max_year
% 100, month
: 1, day
: 1),
837 parse
!(year_div_100
: (max_year
+ 1) / 100,
838 year_mod_100
: (max_year
+ 1) % 100, month
: 1, day
: 1),
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
));
848 parse
!(year
: 1984, year_div_100
: 19, year_mod_100
: 84, month
: 1, day
: 1),
852 parse
!(year
: 1984, year_div_100
: 18, year_mod_100
: 94, month
: 1, day
: 1),
856 parse
!(year
: 1984, year_div_100
: 18, year_mod_100
: 184, month
: 1, day
: 1),
860 parse
!(year
: -1, year_div_100
: 0, year_mod_100
: -1, month
: 1, day
: 1),
864 parse
!(year
: -1, year_div_100
: -1, year_mod_100
: 99, month
: 1, day
: 1),
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
));
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));
894 // weekdates: conflicting inputs
896 parse
!(year
: 2000, week_from_mon
: 1, week_from_sun
: 1, weekday
: Sat
),
900 parse
!(year
: 2000, week_from_mon
: 1, week_from_sun
: 2, weekday
: Sun
),
904 parse
!(year
: 2000, week_from_mon
: 1, week_from_sun
: 1, weekday
: Sun
),
908 parse
!(year
: 2000, week_from_mon
: 2, week_from_sun
: 2, weekday
: Sun
),
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
));
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
));
938 // more complex cases
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
),
945 parse
!(year
: 2014, month
: 12, ordinal
: 365, isoyear
: 2015, isoweek
: 1,
946 week_from_sun
: 52, week_from_mon
: 52),
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
),
953 ); // no ISO week date 2014-W53-3
955 parse
!(year
: 2012, isoyear
: 2015, isoweek
: 1,
956 week_from_sun
: 52, week_from_mon
: 52),
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
964 fn test_parsed_to_naive_time() {
966 ($
($k
:ident
: $v
:expr
),*) => (
967 Parsed { $($k: Some($v),)* ..Parsed::new() }
.to_naive_time()
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());
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));
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)
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
));
988 parse
!(hour_div_12
: 0, hour_mod_12
: 1, minute
: 23, nanosecond
: 456_789_012),
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
));
997 parse
!(hour_div_12
: 0, hour_mod_12
: 1, minute
: 23, second
: 61),
1001 parse
!(hour_div_12
: 0, hour_mod_12
: 1, minute
: 23, second
: 34,
1002 nanosecond
: 1_000_000_000),
1008 parse
!(hour_div_12
: 0, hour_mod_12
: 1, minute
: 23, second
: 60),
1009 hmsn(1, 23, 59, 1_000_000_000)
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)
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
)
1024 ($
($k
:ident
: $v
:expr
),*) => (parse
!(offset
= 0; $
($k
: $v
),*))
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())
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())
1034 // omission of fields
1035 assert_eq
!(parse
!(), Err(NOT_ENOUGH
));
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)
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)
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)
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));
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)
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),
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)
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)
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());
1093 parse
!(timestamp
: min_days_from_year_1970
.num_seconds()),
1094 ymdhms(NaiveDate
::MIN
.year(), 1, 1, 0, 0, 0)
1097 parse
!(timestamp
: year_0_from_year_1970
.num_seconds()),
1098 ymdhms(0, 1, 1, 0, 0, 0)
1101 parse
!(timestamp
: max_days_from_year_1970
.num_seconds() + 86399),
1102 ymdhms(NaiveDate
::MAX
.year(), 12, 31, 23, 59, 59)
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
));
1110 parse
!(second
: 60, timestamp
: 1_341_100_799),
1111 ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
1114 parse
!(second
: 60, timestamp
: 1_341_100_800),
1115 ymdhmsn(2012, 6, 30, 23, 59, 59, 1_000_000_000)
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
));
1121 // leap seconds #2: full fields
1122 // we need to have separate tests for them since it uses another control flow.
1124 parse
!(year
: 2012, ordinal
: 182, hour_div_12
: 1, hour_mod_12
: 11,
1125 minute
: 59, second
: 59, timestamp
: 1_341_100_798),
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)
1134 parse
!(year
: 2012, ordinal
: 182, hour_div_12
: 1, hour_mod_12
: 11,
1135 minute
: 59, second
: 59, timestamp
: 1_341_100_800),
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)
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)
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)
1154 parse
!(year
: 2012, ordinal
: 183, hour_div_12
: 0, hour_mod_12
: 0,
1155 minute
: 0, second
: 1, timestamp
: 1_341_100_800),
1159 parse
!(year
: 2012, ordinal
: 182, hour_div_12
: 1, hour_mod_12
: 11,
1160 minute
: 59, second
: 60, timestamp
: 1_341_100_801),
1166 parse
!(year
: 2015, month
: 1, day
: 20, weekday
: Tue
,
1167 hour_div_12
: 2, hour_mod_12
: 1, minute
: 35, second
: 20),
1169 ); // `hour_div_12` is out of range
1173 fn test_parsed_to_datetime() {
1174 macro_rules
! parse
{
1175 ($
($k
:ident
: $v
:expr
),*) => (
1176 Parsed { $($k: Some($v),)* ..Parsed::new() }
.to_datetime()
1180 let ymdhmsn
= |y
, m
, d
, h
, n
, s
, nano
, off
| {
1181 Ok(FixedOffset
::east_opt(off
)
1183 .from_local_datetime(
1184 &NaiveDate
::from_ymd_opt(y
, m
, d
)
1186 .and_hms_nano_opt(h
, n
, s
, nano
)
1192 assert_eq
!(parse
!(offset
: 0), Err(NOT_ENOUGH
));
1194 parse
!(year
: 2014, ordinal
: 365, hour_div_12
: 0, hour_mod_12
: 4,
1195 minute
: 26, second
: 40, nanosecond
: 12_345_678),
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)
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)
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)
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),
1217 ); // `FixedOffset` does not support such huge offset
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
)
1228 // single result from ymdhms
1231 year
: 2014, ordinal
: 365, hour_div_12
: 0, hour_mod_12
: 4,
1232 minute
: 26, second
: 40, nanosecond
: 12_345_678, offset
: 0),
1234 .from_local_datetime(
1235 &NaiveDate
::from_ymd_opt(2014, 12, 31)
1237 .and_hms_nano_opt(4, 26, 40, 12_345_678)
1244 year
: 2014, ordinal
: 365, hour_div_12
: 1, hour_mod_12
: 1,
1245 minute
: 26, second
: 40, nanosecond
: 12_345_678, offset
: 32400),
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),
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)
1260 .from_local_datetime(
1261 &NaiveDate
::from_ymd_opt(2014, 12, 31)
1263 .and_hms_nano_opt(13, 26, 40, 12_345_678)
1269 // single result from timestamp
1271 parse
!(Utc
; timestamp
: 1_420_000_000, offset
: 0),
1272 Ok(Utc
.with_ymd_and_hms(2014, 12, 31, 4, 26, 40).unwrap())
1274 assert_eq
!(parse
!(Utc
; timestamp
: 1_420_000_000, offset
: 32400), Err(IMPOSSIBLE
));
1276 parse
!(FixedOffset
::east_opt(32400).unwrap(); timestamp
: 1_420_000_000, offset
: 0),
1280 parse
!(FixedOffset
::east_opt(32400).unwrap(); timestamp
: 1_420_000_000, offset
: 32400),
1281 Ok(FixedOffset
::east_opt(32400)
1283 .with_ymd_and_hms(2014, 12, 31, 13, 26, 40)
1287 // TODO test with a variable time zone (for None and Ambiguous cases)