|
|
@ -1142,21 +1142,26 @@ impl fmt::Display for GDay { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)] |
|
|
|
/// A timezone offset with respect to UTC.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// It is encoded as a number of minutes between -PT14H and PT14H.
|
|
|
|
|
|
|
|
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash)] |
|
|
|
pub struct TimezoneOffset { |
|
|
|
pub struct TimezoneOffset { |
|
|
|
offset: i16, // in minute with respect to UTC
|
|
|
|
offset: i16, // in minute with respect to UTC
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl TimezoneOffset { |
|
|
|
impl TimezoneOffset { |
|
|
|
#[inline] |
|
|
|
|
|
|
|
pub const fn utc() -> Self { |
|
|
|
|
|
|
|
Self { offset: 0 } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// From offset in minute with respect to UTC
|
|
|
|
/// From offset in minute with respect to UTC
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
pub(super) const fn new(offset: i16) -> Self { |
|
|
|
pub fn new(offset_in_minutes: i16) -> Result<Self, DateTimeError> { |
|
|
|
Self { offset } |
|
|
|
let value = Self { |
|
|
|
|
|
|
|
offset: offset_in_minutes, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
if Self::MIN <= value && value <= Self::MAX { |
|
|
|
|
|
|
|
Ok(value) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
Err(DATE_TIME_OVERFLOW) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
@ -1170,12 +1175,35 @@ impl TimezoneOffset { |
|
|
|
pub fn to_be_bytes(self) -> [u8; 2] { |
|
|
|
pub fn to_be_bytes(self) -> [u8; 2] { |
|
|
|
self.offset.to_be_bytes() |
|
|
|
self.offset.to_be_bytes() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub const MIN: Self = Self { offset: -14 * 60 }; |
|
|
|
|
|
|
|
pub const UTC: Self = Self { offset: 0 }; |
|
|
|
|
|
|
|
pub const MAX: Self = Self { offset: 14 * 60 }; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl From<i16> for TimezoneOffset { |
|
|
|
impl TryFrom<DayTimeDuration> for TimezoneOffset { |
|
|
|
|
|
|
|
type Error = DateTimeError; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline] |
|
|
|
|
|
|
|
fn try_from(value: DayTimeDuration) -> Result<Self, DateTimeError> { |
|
|
|
|
|
|
|
let result = Self::new((value.minutes() + value.hours() * 60) as i16)?; |
|
|
|
|
|
|
|
if DayTimeDuration::from(result) == value { |
|
|
|
|
|
|
|
Ok(result) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// The value is not an integral number of minutes or overflow problems
|
|
|
|
|
|
|
|
Err(DATE_TIME_OVERFLOW) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl TryFrom<Duration> for TimezoneOffset { |
|
|
|
|
|
|
|
type Error = DateTimeError; |
|
|
|
|
|
|
|
|
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
fn from(offset: i16) -> Self { |
|
|
|
fn try_from(value: Duration) -> Result<Self, DateTimeError> { |
|
|
|
Self { offset } |
|
|
|
DayTimeDuration::try_from(value) |
|
|
|
|
|
|
|
.map_err(|_| DATE_TIME_OVERFLOW)? |
|
|
|
|
|
|
|
.try_into() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1287,9 +1315,7 @@ impl Timestamp { |
|
|
|
|
|
|
|
|
|
|
|
Ok(Self { |
|
|
|
Ok(Self { |
|
|
|
timezone_offset: props.timezone_offset, |
|
|
|
timezone_offset: props.timezone_offset, |
|
|
|
value: time_on_timeline(props).ok_or(DateTimeError { |
|
|
|
value: time_on_timeline(props).ok_or(DATE_TIME_OVERFLOW)?, |
|
|
|
kind: DateTimeErrorKind::Overflow, |
|
|
|
|
|
|
|
})?, |
|
|
|
|
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1305,12 +1331,10 @@ impl Timestamp { |
|
|
|
hour: Some(0), |
|
|
|
hour: Some(0), |
|
|
|
minute: Some(0), |
|
|
|
minute: Some(0), |
|
|
|
second: Some(Decimal::default()), |
|
|
|
second: Some(Decimal::default()), |
|
|
|
timezone_offset: Some(TimezoneOffset::utc()), |
|
|
|
timezone_offset: Some(TimezoneOffset::UTC), |
|
|
|
}, |
|
|
|
}, |
|
|
|
) |
|
|
|
) |
|
|
|
.ok_or(DateTimeError { |
|
|
|
.ok_or(DATE_TIME_OVERFLOW)?, |
|
|
|
kind: DateTimeErrorKind::Overflow, |
|
|
|
|
|
|
|
})?, |
|
|
|
|
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1332,11 +1356,7 @@ impl Timestamp { |
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
fn year_month_day(&self) -> (i64, u8, u8) { |
|
|
|
fn year_month_day(&self) -> (i64, u8, u8) { |
|
|
|
let mut days = (self.value.as_i128() |
|
|
|
let mut days = (self.value.as_i128() |
|
|
|
+ i128::from( |
|
|
|
+ i128::from(self.timezone_offset.unwrap_or(TimezoneOffset::UTC).offset) * 60) |
|
|
|
self.timezone_offset |
|
|
|
|
|
|
|
.unwrap_or_else(TimezoneOffset::utc) |
|
|
|
|
|
|
|
.offset, |
|
|
|
|
|
|
|
) * 60) |
|
|
|
|
|
|
|
.div_euclid(86400) |
|
|
|
.div_euclid(86400) |
|
|
|
+ 366; |
|
|
|
+ 366; |
|
|
|
|
|
|
|
|
|
|
@ -1406,11 +1426,7 @@ impl Timestamp { |
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
fn hour(&self) -> u8 { |
|
|
|
fn hour(&self) -> u8 { |
|
|
|
(((self.value.as_i128() |
|
|
|
(((self.value.as_i128() |
|
|
|
+ i128::from( |
|
|
|
+ i128::from(self.timezone_offset.unwrap_or(TimezoneOffset::UTC).offset) * 60) |
|
|
|
self.timezone_offset |
|
|
|
|
|
|
|
.unwrap_or_else(TimezoneOffset::utc) |
|
|
|
|
|
|
|
.offset, |
|
|
|
|
|
|
|
) * 60) |
|
|
|
|
|
|
|
.rem_euclid(86400)) |
|
|
|
.rem_euclid(86400)) |
|
|
|
/ 3600) as u8 |
|
|
|
/ 3600) as u8 |
|
|
|
} |
|
|
|
} |
|
|
@ -1419,11 +1435,7 @@ impl Timestamp { |
|
|
|
#[inline] |
|
|
|
#[inline] |
|
|
|
fn minute(&self) -> u8 { |
|
|
|
fn minute(&self) -> u8 { |
|
|
|
(((self.value.as_i128() |
|
|
|
(((self.value.as_i128() |
|
|
|
+ i128::from( |
|
|
|
+ i128::from(self.timezone_offset.unwrap_or(TimezoneOffset::UTC).offset) * 60) |
|
|
|
self.timezone_offset |
|
|
|
|
|
|
|
.unwrap_or_else(TimezoneOffset::utc) |
|
|
|
|
|
|
|
.offset, |
|
|
|
|
|
|
|
) * 60) |
|
|
|
|
|
|
|
.rem_euclid(3600)) |
|
|
|
.rem_euclid(3600)) |
|
|
|
/ 60) as u8 |
|
|
|
/ 60) as u8 |
|
|
|
} |
|
|
|
} |
|
|
@ -1486,11 +1498,8 @@ impl Timestamp { |
|
|
|
fn since_unix_epoch() -> Result<Duration, DateTimeError> { |
|
|
|
fn since_unix_epoch() -> Result<Duration, DateTimeError> { |
|
|
|
Ok(Duration::new( |
|
|
|
Ok(Duration::new( |
|
|
|
0, |
|
|
|
0, |
|
|
|
Decimal::try_from(crate::Double::from(js_sys::Date::now() / 1000.)).map_err(|_| { |
|
|
|
Decimal::try_from(crate::Double::from(js_sys::Date::now() / 1000.)) |
|
|
|
DateTimeError { |
|
|
|
.map_err(|_| DATE_TIME_OVERFLOW)?, |
|
|
|
kind: DateTimeErrorKind::Overflow, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
})?, |
|
|
|
|
|
|
|
)) |
|
|
|
)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1501,9 +1510,7 @@ fn since_unix_epoch() -> Result<Duration, DateTimeError> { |
|
|
|
SystemTime::now() |
|
|
|
SystemTime::now() |
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)? |
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)? |
|
|
|
.try_into() |
|
|
|
.try_into() |
|
|
|
.map_err(|_| DateTimeError { |
|
|
|
.map_err(|_| DATE_TIME_OVERFLOW) |
|
|
|
kind: DateTimeErrorKind::Overflow, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// The [normalizeMonth](https://www.w3.org/TR/xmlschema11-2/#f-dt-normMo) function
|
|
|
|
/// The [normalizeMonth](https://www.w3.org/TR/xmlschema11-2/#f-dt-normMo) function
|
|
|
@ -1627,12 +1634,7 @@ fn time_on_timeline(props: &DateTimeSevenPropertyModel) -> Option<Decimal> { |
|
|
|
.map_or_else(|| days_in_month(Some(yr + 1), mo) - 1, |d| d - 1); |
|
|
|
.map_or_else(|| days_in_month(Some(yr + 1), mo) - 1, |d| d - 1); |
|
|
|
let hr = props.hour.unwrap_or(0); |
|
|
|
let hr = props.hour.unwrap_or(0); |
|
|
|
let mi = i128::from(props.minute.unwrap_or(0)) |
|
|
|
let mi = i128::from(props.minute.unwrap_or(0)) |
|
|
|
- i128::from( |
|
|
|
- i128::from(props.timezone_offset.unwrap_or(TimezoneOffset::UTC).offset); |
|
|
|
props |
|
|
|
|
|
|
|
.timezone_offset |
|
|
|
|
|
|
|
.unwrap_or_else(TimezoneOffset::utc) |
|
|
|
|
|
|
|
.offset, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
let se = props.second.unwrap_or_default(); |
|
|
|
let se = props.second.unwrap_or_default(); |
|
|
|
|
|
|
|
|
|
|
|
Decimal::try_from( |
|
|
|
Decimal::try_from( |
|
|
@ -1695,6 +1697,10 @@ impl From<SystemTimeError> for DateTimeError { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const DATE_TIME_OVERFLOW: DateTimeError = DateTimeError { |
|
|
|
|
|
|
|
kind: DateTimeErrorKind::Overflow, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
#[cfg(test)] |
|
|
|
mod tests { |
|
|
|
mod tests { |
|
|
|
use super::*; |
|
|
|
use super::*; |
|
|
|