// This is a part of Chrono. // See README.md and LICENSE.txt for details.
//! A collection of parsed date and time items. //! They can be constructed incrementally while being checked for consistency.
use num_traits::ToPrimitive; use oldtime::Duration as OldDuration;
usesuper::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE}; use div::div_rem; use naive::{NaiveDate, NaiveDateTime, NaiveTime}; use offset::{FixedOffset, LocalResult, Offset, TimeZone}; use DateTime; use Weekday; use {Datelike, Timelike};
/// Parsed parts of date and time. There are two classes of methods: /// /// - `set_*` methods try to set given field(s) while checking for the consistency. /// It may or may not check for the range constraint immediately (for efficiency reasons). /// /// - `to_*` methods try to make a concrete date and time value out of set fields. /// It fully checks any remaining out-of-range conditions and inconsistent/impossible fields. #[allow(missing_copy_implementations)] #[derive(Clone, PartialEq, Debug)] pubstruct Parsed { /// Year. /// /// This can be negative unlike [`year_div_100`](#structfield.year_div_100) /// and [`year_mod_100`](#structfield.year_mod_100) fields. pub year: Option<i32>,
/// Year divided by 100. Implies that the year is >= 1 BCE when set. /// /// Due to the common usage, if this field is missing but /// [`year_mod_100`](#structfield.year_mod_100) is present, /// it is inferred to 19 when `year_mod_100 >= 70` and 20 otherwise. pub year_div_100: Option<i32>,
/// Year modulo 100. Implies that the year is >= 1 BCE when set. pub year_mod_100: Option<i32>,
/// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date). /// /// This can be negative unlike [`isoyear_div_100`](#structfield.isoyear_div_100) and /// [`isoyear_mod_100`](#structfield.isoyear_mod_100) fields. pub isoyear: Option<i32>,
/// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), divided by 100. /// Implies that the year is >= 1 BCE when set. /// /// Due to the common usage, if this field is missing but /// [`isoyear_mod_100`](#structfield.isoyear_mod_100) is present, /// it is inferred to 19 when `isoyear_mod_100 >= 70` and 20 otherwise. pub isoyear_div_100: Option<i32>,
/// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), modulo 100. /// Implies that the year is >= 1 BCE when set. pub isoyear_mod_100: Option<i32>,
/// Month (1--12). pub month: Option<u32>,
/// Week number, where the week 1 starts at the first Sunday of January /// (0--53, 1--53 or 1--52 depending on the year). pub week_from_sun: Option<u32>,
/// Week number, where the week 1 starts at the first Monday of January /// (0--53, 1--53 or 1--52 depending on the year). pub week_from_mon: Option<u32>,
/// [ISO week number](../naive/struct.NaiveDate.html#week-date) /// (1--52 or 1--53 depending on the year). pub isoweek: Option<u32>,
/// Day of the week. pub weekday: Option<Weekday>,
/// Day of the year (1--365 or 1--366 depending on the year). pub ordinal: Option<u32>,
/// Day of the month (1--28, 1--29, 1--30 or 1--31 depending on the month). pub day: Option<u32>,
/// Hour number divided by 12 (0--1). 0 indicates AM and 1 indicates PM. pub hour_div_12: Option<u32>,
/// Hour number modulo 12 (0--11). pub hour_mod_12: Option<u32>,
/// Minute number (0--59). pub minute: Option<u32>,
/// Second number (0--60, accounting for leap seconds). pub second: Option<u32>,
/// The number of nanoseconds since the whole second (0--999,999,999). pub nanosecond: Option<u32>,
/// The number of non-leap seconds since the midnight UTC on January 1, 1970. /// /// This can be off by one if [`second`](#structfield.second) is 60 (a leap second). pub timestamp: Option<i64>,
/// Offset from the local time to UTC, in seconds. pub offset: Option<i32>,
/// A dummy field to make this type not fully destructible (required for API stability).
_dummy: (),
}
/// Checks if `old` is either empty or has the same value as `new` (i.e. "consistent"), /// and if it is empty, set `old` to `new` as well. #[inline] fn set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<()> { iflet Some(ref old) = *old { if *old == new {
Ok(())
} else {
Err(IMPOSSIBLE)
}
} else {
*old = Some(new);
Ok(())
}
}
impl Parsed { /// Returns the initial value of parsed parts. pubfn new() -> Parsed {
Parsed::default()
}
/// Tries to set the [`year`](#structfield.year) field from given value. #[inline] pubfn set_year(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.year, value.to_i32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value. #[inline] pubfn set_year_div_100(&mutself, value: i64) -> ParseResult<()> { if value < 0 { return Err(OUT_OF_RANGE);
}
set_if_consistent(&mutself.year_div_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value. #[inline] pubfn set_year_mod_100(&mutself, value: i64) -> ParseResult<()> { if value < 0 { return Err(OUT_OF_RANGE);
}
set_if_consistent(&mutself.year_mod_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`isoyear`](#structfield.isoyear) field from given value. #[inline] pubfn set_isoyear(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.isoyear, value.to_i32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value. #[inline] pubfn set_isoyear_div_100(&mutself, value: i64) -> ParseResult<()> { if value < 0 { return Err(OUT_OF_RANGE);
}
set_if_consistent(&mutself.isoyear_div_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value. #[inline] pubfn set_isoyear_mod_100(&mutself, value: i64) -> ParseResult<()> { if value < 0 { return Err(OUT_OF_RANGE);
}
set_if_consistent(&mutself.isoyear_mod_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`month`](#structfield.month) field from given value. #[inline] pubfn set_month(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.month, value.to_u32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value. #[inline] pubfn set_week_from_sun(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.week_from_sun, value.to_u32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value. #[inline] pubfn set_week_from_mon(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.week_from_mon, value.to_u32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`isoweek`](#structfield.isoweek) field from given value. #[inline] pubfn set_isoweek(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.isoweek, value.to_u32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`weekday`](#structfield.weekday) field from given value. #[inline] pubfn set_weekday(&mutself, value: Weekday) -> ParseResult<()> {
set_if_consistent(&mutself.weekday, value)
}
/// Tries to set the [`ordinal`](#structfield.ordinal) field from given value. #[inline] pubfn set_ordinal(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.ordinal, value.to_u32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`day`](#structfield.day) field from given value. #[inline] pubfn set_day(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.day, value.to_u32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value. /// (`false` for AM, `true` for PM) #[inline] pubfn set_ampm(&mutself, value: bool) -> ParseResult<()> {
set_if_consistent(&mutself.hour_div_12, if value { 1 } else { 0 })
}
/// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from /// given hour number in 12-hour clocks. #[inline] pubfn set_hour12(&mutself, value: i64) -> ParseResult<()> { if value < 1 || value > 12 { return Err(OUT_OF_RANGE);
}
set_if_consistent(&mutself.hour_mod_12, value as u32 % 12)
}
/// Tries to set both [`hour_div_12`](#structfield.hour_div_12) and /// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value. #[inline] pubfn set_hour(&mutself, value: i64) -> ParseResult<()> { let v = value.to_u32().ok_or(OUT_OF_RANGE)?;
set_if_consistent(&mutself.hour_div_12, v / 12)?;
set_if_consistent(&mutself.hour_mod_12, v % 12)?;
Ok(())
}
/// Tries to set the [`minute`](#structfield.minute) field from given value. #[inline] pubfn set_minute(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.minute, value.to_u32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`second`](#structfield.second) field from given value. #[inline] pubfn set_second(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.second, value.to_u32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value. #[inline] pubfn set_nanosecond(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.nanosecond, value.to_u32().ok_or(OUT_OF_RANGE)?)
}
/// Tries to set the [`timestamp`](#structfield.timestamp) field from given value. #[inline] pubfn set_timestamp(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.timestamp, value)
}
/// Tries to set the [`offset`](#structfield.offset) field from given value. #[inline] pubfn set_offset(&mutself, value: i64) -> ParseResult<()> {
set_if_consistent(&mutself.offset, value.to_i32().ok_or(OUT_OF_RANGE)?)
}
/// Returns a parsed naive date out of given fields. /// /// This method is able to determine the date from given subset of fields: /// /// - Year, month, day. /// - Year, day of the year (ordinal). /// - Year, week number counted from Sunday or Monday, day of the week. /// - ISO week date. /// /// Gregorian year and ISO week date year can have their century number (`*_div_100`) omitted, /// the two-digit year is used to guess the century number then. pubfn to_naive_date(&self) -> ParseResult<NaiveDate> { fn resolve_year(
y: Option<i32>,
q: Option<i32>,
r: Option<i32>,
) -> ParseResult<Option<i32>> { match (y, q, r) { // if there is no further information, simply return the given full year. // this is a common case, so let's avoid division here.
(y, None, None) => Ok(y),
// if there is a full year *and* also quotient and/or modulo, // check if present quotient and/or modulo is consistent to the full year. // since the presence of those fields means a positive full year, // we should filter a negative full year first.
(Some(y), q, r @ Some(0...99)) | (Some(y), q, r @ None) => { if y < 0 { return Err(OUT_OF_RANGE);
} let (q_, r_) = div_rem(y, 100); if q.unwrap_or(q_) == q_ && r.unwrap_or(r_) == r_ {
Ok(Some(y))
} else {
Err(IMPOSSIBLE)
}
}
// the full year is missing but we have quotient and modulo. // reconstruct the full year. make sure that the result is always positive.
(None, Some(q), Some(r @ 0...99)) => { if q < 0 { return Err(OUT_OF_RANGE);
} let y = q.checked_mul(100).and_then(|v| v.checked_add(r));
Ok(Some(y.ok_or(OUT_OF_RANGE)?))
}
// we only have modulo. try to interpret a modulo as a conventional two-digit year. // note: we are affected by Rust issue #18060. avoid multiple range patterns.
(None, None, Some(r @ 0...99)) => Ok(Some(r + if r < 70 { 2000 } else { 1900 })),
// otherwise it is an out-of-bound or insufficient condition.
(None, Some(_), None) => Err(NOT_ENOUGH),
(_, _, Some(_)) => Err(OUT_OF_RANGE),
}
}
let given_year = resolve_year(self.year, self.year_div_100, self.year_mod_100)?; let given_isoyear = resolve_year(self.isoyear, self.isoyear_div_100, self.isoyear_mod_100)?;
// verify the normal year-month-day date. let verify_ymd = |date: NaiveDate| { let year = date.year(); let (year_div_100, year_mod_100) = if year >= 0 { let (q, r) = div_rem(year, 100);
(Some(q), Some(r))
} else {
(None, None) // they should be empty to be consistent
}; let month = date.month(); let day = date.day(); self.year.unwrap_or(year) == year
&& self.year_div_100.or(year_div_100) == year_div_100
&& self.year_mod_100.or(year_mod_100) == year_mod_100
&& self.month.unwrap_or(month) == month
&& self.day.unwrap_or(day) == day
};
// verify the ISO week date. let verify_isoweekdate = |date: NaiveDate| { let week = date.iso_week(); let isoyear = week.year(); let isoweek = week.week(); let weekday = date.weekday(); let (isoyear_div_100, isoyear_mod_100) = if isoyear >= 0 { let (q, r) = div_rem(isoyear, 100);
(Some(q), Some(r))
} else {
(None, None) // they should be empty to be consistent
}; self.isoyear.unwrap_or(isoyear) == isoyear
&& self.isoyear_div_100.or(isoyear_div_100) == isoyear_div_100
&& self.isoyear_mod_100.or(isoyear_mod_100) == isoyear_mod_100
&& self.isoweek.unwrap_or(isoweek) == isoweek
&& self.weekday.unwrap_or(weekday) == weekday
};
// verify the ordinal and other (non-ISO) week dates. let verify_ordinal = |date: NaiveDate| { let ordinal = date.ordinal(); let weekday = date.weekday(); let week_from_sun = (ordinal as i32 - weekday.num_days_from_sunday() as i32 + 7) / 7; let week_from_mon = (ordinal as i32 - weekday.num_days_from_monday() as i32 + 7) / 7; self.ordinal.unwrap_or(ordinal) == ordinal
&& self.week_from_sun.map_or(week_from_sun, |v| v as i32) == week_from_sun
&& self.week_from_mon.map_or(week_from_mon, |v| v as i32) == week_from_mon
};
// test several possibilities. // tries to construct a full `NaiveDate` as much as possible, then verifies that // it is consistent with other given fields. let (verified, parsed_date) = match (given_year, given_isoyear, self) {
(Some(year), _, &Parsed { month: Some(month), day: Some(day), .. }) => { // year, month, day let date = NaiveDate::from_ymd_opt(year, month, day).ok_or(OUT_OF_RANGE)?;
(verify_isoweekdate(date) && verify_ordinal(date), date)
}
(Some(year), _, &Parsed { ordinal: Some(ordinal), .. }) => { // year, day of the year let date = NaiveDate::from_yo_opt(year, ordinal).ok_or(OUT_OF_RANGE)?;
(verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date)
}
(
Some(year),
_,
&Parsed { week_from_sun: Some(week_from_sun), weekday: Some(weekday), .. },
) => { // year, week (starting at 1st Sunday), day of the week let newyear = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?; let firstweek = match newyear.weekday() {
Weekday::Sun => 0,
Weekday::Mon => 6,
Weekday::Tue => 5,
Weekday::Wed => 4,
Weekday::Thu => 3,
Weekday::Fri => 2,
Weekday::Sat => 1,
};
// `firstweek+1`-th day of January is the beginning of the week 1. if week_from_sun > 53 { return Err(OUT_OF_RANGE);
} // can it overflow? let ndays = firstweek
+ (week_from_sun as i32 - 1) * 7
+ weekday.num_days_from_sunday() as i32; let date = newyear
.checked_add_signed(OldDuration::days(i64::from(ndays)))
.ok_or(OUT_OF_RANGE)?; if date.year() != year { return Err(OUT_OF_RANGE);
} // early exit for correct error
(
Some(year),
_,
&Parsed { week_from_mon: Some(week_from_mon), weekday: Some(weekday), .. },
) => { // year, week (starting at 1st Monday), day of the week let newyear = NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)?; let firstweek = match newyear.weekday() {
Weekday::Sun => 1,
Weekday::Mon => 0,
Weekday::Tue => 6,
Weekday::Wed => 5,
Weekday::Thu => 4,
Weekday::Fri => 3,
Weekday::Sat => 2,
};
// `firstweek+1`-th day of January is the beginning of the week 1. if week_from_mon > 53 { return Err(OUT_OF_RANGE);
} // can it overflow? let ndays = firstweek
+ (week_from_mon as i32 - 1) * 7
+ weekday.num_days_from_monday() as i32; let date = newyear
.checked_add_signed(OldDuration::days(i64::from(ndays)))
.ok_or(OUT_OF_RANGE)?; if date.year() != year { return Err(OUT_OF_RANGE);
} // early exit for correct error
(_, Some(isoyear), &Parsed { isoweek: Some(isoweek), weekday: Some(weekday), .. }) => { // ISO year, week, day of the week let date = NaiveDate::from_isoywd_opt(isoyear, isoweek, weekday); let date = date.ok_or(OUT_OF_RANGE)?;
(verify_ymd(date) && verify_ordinal(date), date)
}
(_, _, _) => return Err(NOT_ENOUGH),
};
if verified {
Ok(parsed_date)
} else {
Err(IMPOSSIBLE)
}
}
/// Returns a parsed naive time out of given fields. /// /// This method is able to determine the time from given subset of fields: /// /// - Hour, minute. (second and nanosecond assumed to be 0) /// - Hour, minute, second. (nanosecond assumed to be 0) /// - Hour, minute, second, nanosecond. /// /// It is able to handle leap seconds when given second is 60. pubfn to_naive_time(&self) -> ParseResult<NaiveTime> { let hour_div_12 = matchself.hour_div_12 {
Some(v @ 0...1) => v,
Some(_) => return Err(OUT_OF_RANGE),
None => return Err(NOT_ENOUGH),
}; let hour_mod_12 = matchself.hour_mod_12 {
Some(v @ 0...11) => v,
Some(_) => return Err(OUT_OF_RANGE),
None => return Err(NOT_ENOUGH),
}; let hour = hour_div_12 * 12 + hour_mod_12;
/// Returns a parsed naive date and time out of given fields, /// except for the [`offset`](#structfield.offset) field (assumed to have a given value). /// This is required for parsing a local time or other known-timezone inputs. /// /// This method is able to determine the combined date and time /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field. /// Either way those fields have to be consistent to each other. pubfn to_naive_datetime_with_offset(&self, offset: i32) -> ParseResult<NaiveDateTime> { let date = self.to_naive_date(); let time = self.to_naive_time(); iflet (Ok(date), Ok(time)) = (date, time) { let datetime = date.and_time(time);
// verify the timestamp field if any // the following is safe, `timestamp` is very limited in range let timestamp = datetime.timestamp() - i64::from(offset); iflet Some(given_timestamp) = self.timestamp { // if `datetime` represents a leap second, it might be off by one second. if given_timestamp != timestamp
&& !(datetime.nanosecond() >= 1_000_000_000 && given_timestamp == timestamp + 1)
{ return Err(IMPOSSIBLE);
}
}
// if date and time is problematic already, there is no point proceeding. // we at least try to give a correct error though. match (date, time) {
(Err(PE(OutOfRange)), _) | (_, Err(PE(OutOfRange))) => return Err(OUT_OF_RANGE),
(Err(PE(Impossible)), _) | (_, Err(PE(Impossible))) => return Err(IMPOSSIBLE),
(_, _) => {} // one of them is insufficient
}
// reconstruct date and time fields from timestamp let ts = timestamp.checked_add(i64::from(offset)).ok_or(OUT_OF_RANGE)?; let datetime = NaiveDateTime::from_timestamp_opt(ts, 0); letmut datetime = datetime.ok_or(OUT_OF_RANGE)?;
// fill year, ordinal, hour, minute and second fields from timestamp. // if existing fields are consistent, this will allow the full date/time reconstruction. letmut parsed = self.clone(); if parsed.second == Some(60) { // `datetime.second()` cannot be 60, so this is the only case for a leap second. match datetime.second() { // it's okay, just do not try to overwrite the existing field. 59 => {} // `datetime` is known to be off by one second. 0 => {
datetime -= OldDuration::seconds(1);
} // otherwise it is impossible.
_ => return Err(IMPOSSIBLE),
} // ...and we have the correct candidates for other fields.
} else {
parsed.set_second(i64::from(datetime.second()))?;
}
parsed.set_year(i64::from(datetime.year()))?;
parsed.set_ordinal(i64::from(datetime.ordinal()))?; // more efficient than ymd
parsed.set_hour(i64::from(datetime.hour()))?;
parsed.set_minute(i64::from(datetime.minute()))?;
// validate other fields (e.g. week) and return let date = parsed.to_naive_date()?; let time = parsed.to_naive_time()?;
Ok(date.and_time(time))
} else { // reproduce the previous error(s)
date?;
time?;
unreachable!()
}
}
/// Returns a parsed fixed time zone offset out of given fields. pubfn to_fixed_offset(&self) -> ParseResult<FixedOffset> { self.offset.and_then(FixedOffset::east_opt).ok_or(OUT_OF_RANGE)
}
/// Returns a parsed timezone-aware date and time out of given fields. /// /// This method is able to determine the combined date and time /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field, /// plus a time zone offset. /// Either way those fields have to be consistent to each other. pubfn to_datetime(&self) -> ParseResult<DateTime<FixedOffset>> { let offset = self.offset.ok_or(NOT_ENOUGH)?; let datetime = self.to_naive_datetime_with_offset(offset)?; let offset = FixedOffset::east_opt(offset).ok_or(OUT_OF_RANGE)?; match offset.from_local_datetime(&datetime) {
LocalResult::None => Err(IMPOSSIBLE),
LocalResult::Single(t) => Ok(t),
LocalResult::Ambiguous(..) => Err(NOT_ENOUGH),
}
}
/// Returns a parsed timezone-aware date and time out of given fields, /// with an additional `TimeZone` used to interpret and validate the local date. /// /// This method is able to determine the combined date and time /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field, /// plus a time zone offset. /// Either way those fields have to be consistent to each other. /// If parsed fields include an UTC offset, it also has to be consistent to /// [`offset`](#structfield.offset). pubfn to_datetime_with_timezone<Tz: TimeZone>(&self, tz: &Tz) -> ParseResult<DateTime<Tz>> { // if we have `timestamp` specified, guess an offset from that. letmut guessed_offset = 0; iflet Some(timestamp) = self.timestamp { // make a naive `DateTime` from given timestamp and (if any) nanosecond. // an empty `nanosecond` is always equal to zero, so missing nanosecond is fine. let nanosecond = self.nanosecond.unwrap_or(0); let dt = NaiveDateTime::from_timestamp_opt(timestamp, nanosecond); let dt = dt.ok_or(OUT_OF_RANGE)?;
guessed_offset = tz.offset_from_utc_datetime(&dt).fix().local_minus_utc();
}
// checks if the given `DateTime` has a consistent `Offset` with given `self.offset`. let check_offset = |dt: &DateTime<Tz>| { iflet Some(offset) = self.offset {
dt.offset().fix().local_minus_utc() == offset
} else { true
}
};
// `guessed_offset` should be correct when `self.timestamp` is given. // it will be 0 otherwise, but this is fine as the algorithm ignores offset for that case. let datetime = self.to_naive_datetime_with_offset(guessed_offset)?; match tz.from_local_datetime(&datetime) {
LocalResult::None => Err(IMPOSSIBLE),
LocalResult::Single(t) => { if check_offset(&t) {
Ok(t)
} else {
Err(IMPOSSIBLE)
}
}
LocalResult::Ambiguous(min, max) => { // try to disambiguate two possible local dates by offset. match (check_offset(&min), check_offset(&max)) {
(false, false) => Err(IMPOSSIBLE),
(false, true) => Ok(max),
(true, false) => Ok(min),
(true, true) => Err(NOT_ENOUGH),
}
}
}
}
}
#[cfg(test)] mod tests { usesuper::super::{IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE}; usesuper::Parsed; use naive::{NaiveDate, NaiveTime, MAX_DATE, MIN_DATE}; use offset::{FixedOffset, TimeZone, Utc}; use Datelike; use Weekday::*;
let ymdhms = |y, m, d, h, n, s| Ok(NaiveDate::from_ymd(y, m, d).and_hms(h, n, s)); let ymdhmsn =
|y, m, d, h, n, s, nano| Ok(NaiveDate::from_ymd(y, m, d).and_hms_nano(h, n, s, nano));
// TODO test with a variable time zone (for None and Ambiguous cases)
}
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.26Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-21)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.