diff options
Diffstat (limited to 'vendor/chrono/src/offset/local')
-rw-r--r-- | vendor/chrono/src/offset/local/mod.rs | 177 | ||||
-rw-r--r-- | vendor/chrono/src/offset/local/stub.rs | 236 | ||||
-rw-r--r-- | vendor/chrono/src/offset/local/tz_info/mod.rs | 15 | ||||
-rw-r--r-- | vendor/chrono/src/offset/local/tz_info/parser.rs | 7 | ||||
-rw-r--r-- | vendor/chrono/src/offset/local/tz_info/rule.rs | 15 | ||||
-rw-r--r-- | vendor/chrono/src/offset/local/tz_info/timezone.rs | 19 | ||||
-rw-r--r-- | vendor/chrono/src/offset/local/unix.rs | 52 | ||||
-rw-r--r-- | vendor/chrono/src/offset/local/windows.rs | 346 |
8 files changed, 226 insertions, 641 deletions
diff --git a/vendor/chrono/src/offset/local/mod.rs b/vendor/chrono/src/offset/local/mod.rs index e280c7800..372fd4976 100644 --- a/vendor/chrono/src/offset/local/mod.rs +++ b/vendor/chrono/src/offset/local/mod.rs @@ -8,12 +8,19 @@ use rkyv::{Archive, Deserialize, Serialize}; use super::fixed::FixedOffset; use super::{LocalResult, TimeZone}; -use crate::naive::{NaiveDate, NaiveDateTime}; +use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime}; #[allow(deprecated)] -use crate::{Date, DateTime}; +use crate::Date; +use crate::{DateTime, Utc}; + +#[cfg(unix)] +#[path = "unix.rs"] +mod inner; + +#[cfg(windows)] +#[path = "windows.rs"] +mod inner; -// we don't want `stub.rs` when the target_os is not wasi or emscripten -// as we use js-sys to get the date instead #[cfg(all( not(unix), not(windows), @@ -23,16 +30,37 @@ use crate::{Date, DateTime}; not(any(target_os = "emscripten", target_os = "wasi")) )) ))] -#[path = "stub.rs"] -mod inner; +mod inner { + use crate::{FixedOffset, LocalResult, NaiveDateTime}; -#[cfg(unix)] -#[path = "unix.rs"] -mod inner; + pub(super) fn offset_from_utc_datetime(_utc_time: &NaiveDateTime) -> LocalResult<FixedOffset> { + LocalResult::Single(FixedOffset::east_opt(0).unwrap()) + } -#[cfg(windows)] -#[path = "windows.rs"] -mod inner; + pub(super) fn offset_from_local_datetime( + _local_time: &NaiveDateTime, + ) -> LocalResult<FixedOffset> { + LocalResult::Single(FixedOffset::east_opt(0).unwrap()) + } +} + +#[cfg(all( + target_arch = "wasm32", + feature = "wasmbind", + not(any(target_os = "emscripten", target_os = "wasi")) +))] +mod inner { + use crate::{FixedOffset, LocalResult, NaiveDateTime}; + + pub(super) fn offset_from_utc_datetime(_utc: &NaiveDateTime) -> LocalResult<FixedOffset> { + let offset = js_sys::Date::new_0().get_timezone_offset(); + LocalResult::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap()) + } + + pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset_from_utc_datetime(local) + } +} #[cfg(unix)] mod tz_info; @@ -48,8 +76,9 @@ mod tz_info; /// ``` /// use chrono::{Local, DateTime, TimeZone}; /// -/// let dt: DateTime<Local> = Local::now(); -/// let dt: DateTime<Local> = Local.timestamp(0, 0); +/// let dt1: DateTime<Local> = Local::now(); +/// let dt2: DateTime<Local> = Local.timestamp_opt(0, 0).unwrap(); +/// assert!(dt1 >= dt2); /// ``` #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] @@ -60,6 +89,7 @@ impl Local { /// Returns a `Date` which corresponds to the current date. #[deprecated(since = "0.4.23", note = "use `Local::now()` instead")] #[allow(deprecated)] + #[must_use] pub fn today() -> Date<Local> { Local::now().date() } @@ -70,8 +100,9 @@ impl Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) )))] + #[must_use] pub fn now() -> DateTime<Local> { - inner::now() + Utc::now().with_timezone(&Local) } /// Returns a `DateTime` which corresponds to the current date and time. @@ -80,6 +111,7 @@ impl Local { feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] + #[must_use] pub fn now() -> DateTime<Local> { use super::Utc; let now: DateTime<Utc> = super::Utc::now(); @@ -99,87 +131,24 @@ impl TimeZone for Local { Local } - // they are easier to define in terms of the finished date and time unlike other offsets #[allow(deprecated)] fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> { - self.from_local_date(local).map(|date| *date.offset()) + // Get the offset at local midnight. + self.offset_from_local_datetime(&local.and_time(NaiveTime::MIN)) } fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> { - self.from_local_datetime(local).map(|datetime| *datetime.offset()) + inner::offset_from_local_datetime(local) } #[allow(deprecated)] fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset { - *self.from_utc_date(utc).offset() + // Get the offset at midnight. + self.offset_from_utc_datetime(&utc.and_time(NaiveTime::MIN)) } fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset { - *self.from_utc_datetime(utc).offset() - } - - // override them for avoiding redundant works - #[allow(deprecated)] - fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Local>> { - // this sounds very strange, but required for keeping `TimeZone::ymd` sane. - // in the other words, we use the offset at the local midnight - // but keep the actual date unaltered (much like `FixedOffset`). - let midnight = self.from_local_datetime(&local.and_hms_opt(0, 0, 0).unwrap()); - midnight.map(|datetime| Date::from_utc(*local, *datetime.offset())) - } - - #[cfg(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - ))] - fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> { - let mut local = local.clone(); - // Get the offset from the js runtime - let offset = - FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) - .unwrap(); - local -= crate::Duration::seconds(offset.local_minus_utc() as i64); - LocalResult::Single(DateTime::from_utc(local, offset)) - } - - #[cfg(not(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - )))] - fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Local>> { - inner::naive_to_local(local, true) - } - - #[allow(deprecated)] - fn from_utc_date(&self, utc: &NaiveDate) -> Date<Local> { - let midnight = self.from_utc_datetime(&utc.and_hms_opt(0, 0, 0).unwrap()); - Date::from_utc(*utc, *midnight.offset()) - } - - #[cfg(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - ))] - fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> { - // Get the offset from the js runtime - let offset = - FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) - .unwrap(); - DateTime::from_utc(*utc, offset) - } - - #[cfg(not(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - )))] - fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Local> { - // this is OK to unwrap as getting local time from a UTC - // timestamp is never ambiguous - inner::naive_to_local(utc, false).unwrap() + inner::offset_from_utc_datetime(utc).unwrap() } } @@ -243,18 +212,32 @@ mod tests { // issue #123 let today = Utc::now().date_naive(); - let dt = today.and_hms_milli_opt(1, 2, 59, 1000).unwrap(); - let timestr = dt.time().to_string(); - // the OS API may or may not support the leap second, - // but there are only two sensible options. - assert!(timestr == "01:02:60" || timestr == "01:03:00", "unexpected timestr {:?}", timestr); - - let dt = today.and_hms_milli_opt(1, 2, 3, 1234).unwrap(); - let timestr = dt.time().to_string(); - assert!( - timestr == "01:02:03.234" || timestr == "01:02:04.234", - "unexpected timestr {:?}", - timestr - ); + if let Some(dt) = today.and_hms_milli_opt(15, 2, 59, 1000) { + let timestr = dt.time().to_string(); + // the OS API may or may not support the leap second, + // but there are only two sensible options. + assert!( + timestr == "15:02:60" || timestr == "15:03:00", + "unexpected timestr {:?}", + timestr + ); + } + + if let Some(dt) = today.and_hms_milli_opt(15, 2, 3, 1234) { + let timestr = dt.time().to_string(); + assert!( + timestr == "15:02:03.234" || timestr == "15:02:04.234", + "unexpected timestr {:?}", + timestr + ); + } + } + + /// Test Issue #866 + #[test] + fn test_issue_866() { + #[allow(deprecated)] + let local_20221106 = Local.ymd(2022, 11, 6); + let _dt_20221106 = local_20221106.and_hms_milli_opt(1, 2, 59, 1000).unwrap(); } } diff --git a/vendor/chrono/src/offset/local/stub.rs b/vendor/chrono/src/offset/local/stub.rs deleted file mode 100644 index 9ececd3c2..000000000 --- a/vendor/chrono/src/offset/local/stub.rs +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::time::{SystemTime, UNIX_EPOCH}; - -use super::{FixedOffset, Local}; -use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; - -pub(super) fn now() -> DateTime<Local> { - tm_to_datetime(Timespec::now().local()) -} - -/// Converts a local `NaiveDateTime` to the `time::Timespec`. -#[cfg(not(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) -)))] -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> { - let tm = Tm { - tm_sec: d.second() as i32, - tm_min: d.minute() as i32, - tm_hour: d.hour() as i32, - tm_mday: d.day() as i32, - tm_mon: d.month0() as i32, // yes, C is that strange... - tm_year: d.year() - 1900, // this doesn't underflow, we know that d is `NaiveDateTime`. - tm_wday: 0, // to_local ignores this - tm_yday: 0, // and this - tm_isdst: -1, - // This seems pretty fake? - tm_utcoff: if local { 1 } else { 0 }, - // do not set this, OS APIs are heavily inconsistent in terms of leap second handling - tm_nsec: 0, - }; - - let spec = Timespec { - sec: match local { - false => utc_tm_to_time(&tm), - true => local_tm_to_time(&tm), - }, - nsec: tm.tm_nsec, - }; - - // Adjust for leap seconds - let mut tm = spec.local(); - assert_eq!(tm.tm_nsec, 0); - tm.tm_nsec = d.nanosecond() as i32; - - LocalResult::Single(tm_to_datetime(tm)) -} - -/// Converts a `time::Tm` struct into the timezone-aware `DateTime`. -/// This assumes that `time` is working correctly, i.e. any error is fatal. -#[cfg(not(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) -)))] -fn tm_to_datetime(mut tm: Tm) -> DateTime<Local> { - if tm.tm_sec >= 60 { - tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000; - tm.tm_sec = 59; - } - - let date = NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1); - let time = NaiveTime::from_hms_nano( - tm.tm_hour as u32, - tm.tm_min as u32, - tm.tm_sec as u32, - tm.tm_nsec as u32, - ); - - let offset = FixedOffset::east_opt(tm.tm_utcoff).unwrap(); - DateTime::from_utc(date.and_time(time) - offset, offset) -} - -/// A record specifying a time value in seconds and nanoseconds, where -/// nanoseconds represent the offset from the given second. -/// -/// For example a timespec of 1.2 seconds after the beginning of the epoch would -/// be represented as {sec: 1, nsec: 200000000}. -struct Timespec { - sec: i64, - nsec: i32, -} - -impl Timespec { - /// Constructs a timespec representing the current time in UTC. - fn now() -> Timespec { - let st = - SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); - Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 } - } - - /// Converts this timespec into the system's local time. - fn local(self) -> Tm { - let mut tm = Tm { - tm_sec: 0, - tm_min: 0, - tm_hour: 0, - tm_mday: 0, - tm_mon: 0, - tm_year: 0, - tm_wday: 0, - tm_yday: 0, - tm_isdst: 0, - tm_utcoff: 0, - tm_nsec: 0, - }; - time_to_local_tm(self.sec, &mut tm); - tm.tm_nsec = self.nsec; - tm - } -} - -/// Holds a calendar date and time broken down into its components (year, month, -/// day, and so on), also called a broken-down time value. -// FIXME: use c_int instead of i32? -#[repr(C)] -pub(super) struct Tm { - /// Seconds after the minute - [0, 60] - tm_sec: i32, - - /// Minutes after the hour - [0, 59] - tm_min: i32, - - /// Hours after midnight - [0, 23] - tm_hour: i32, - - /// Day of the month - [1, 31] - tm_mday: i32, - - /// Months since January - [0, 11] - tm_mon: i32, - - /// Years since 1900 - tm_year: i32, - - /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday. - tm_wday: i32, - - /// Days since January 1 - [0, 365] - tm_yday: i32, - - /// Daylight Saving Time flag. - /// - /// This value is positive if Daylight Saving Time is in effect, zero if - /// Daylight Saving Time is not in effect, and negative if this information - /// is not available. - tm_isdst: i32, - - /// Identifies the time zone that was used to compute this broken-down time - /// value, including any adjustment for Daylight Saving Time. This is the - /// number of seconds east of UTC. For example, for U.S. Pacific Daylight - /// Time, the value is `-7*60*60 = -25200`. - tm_utcoff: i32, - - /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1] - tm_nsec: i32, -} - -fn time_to_tm(ts: i64, tm: &mut Tm) { - let leapyear = |year| -> bool { year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) }; - - static YTAB: [[i64; 12]; 2] = [ - [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], - [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], - ]; - - let mut year = 1970; - - let dayclock = ts % 86400; - let mut dayno = ts / 86400; - - tm.tm_sec = (dayclock % 60) as i32; - tm.tm_min = ((dayclock % 3600) / 60) as i32; - tm.tm_hour = (dayclock / 3600) as i32; - tm.tm_wday = ((dayno + 4) % 7) as i32; - loop { - let yearsize = if leapyear(year) { 366 } else { 365 }; - if dayno >= yearsize { - dayno -= yearsize; - year += 1; - } else { - break; - } - } - tm.tm_year = (year - 1900) as i32; - tm.tm_yday = dayno as i32; - let mut mon = 0; - while dayno >= YTAB[if leapyear(year) { 1 } else { 0 }][mon] { - dayno -= YTAB[if leapyear(year) { 1 } else { 0 }][mon]; - mon += 1; - } - tm.tm_mon = mon as i32; - tm.tm_mday = dayno as i32 + 1; - tm.tm_isdst = 0; -} - -fn tm_to_time(tm: &Tm) -> i64 { - let mut y = tm.tm_year as i64 + 1900; - let mut m = tm.tm_mon as i64 + 1; - if m <= 2 { - y -= 1; - m += 12; - } - let d = tm.tm_mday as i64; - let h = tm.tm_hour as i64; - let mi = tm.tm_min as i64; - let s = tm.tm_sec as i64; - (365 * y + y / 4 - y / 100 + y / 400 + 3 * (m + 1) / 5 + 30 * m + d - 719561) * 86400 - + 3600 * h - + 60 * mi - + s -} - -pub(super) fn time_to_local_tm(sec: i64, tm: &mut Tm) { - // FIXME: Add timezone logic - time_to_tm(sec, tm); -} - -pub(super) fn utc_tm_to_time(tm: &Tm) -> i64 { - tm_to_time(tm) -} - -pub(super) fn local_tm_to_time(tm: &Tm) -> i64 { - // FIXME: Add timezone logic - tm_to_time(tm) -} diff --git a/vendor/chrono/src/offset/local/tz_info/mod.rs b/vendor/chrono/src/offset/local/tz_info/mod.rs index bd2693b6b..780e15ace 100644 --- a/vendor/chrono/src/offset/local/tz_info/mod.rs +++ b/vendor/chrono/src/offset/local/tz_info/mod.rs @@ -100,21 +100,6 @@ impl From<Utf8Error> for Error { } } -// MSRV: 1.38 -#[inline] -fn rem_euclid(v: i64, rhs: i64) -> i64 { - let r = v % rhs; - if r < 0 { - if rhs < 0 { - r - rhs - } else { - r + rhs - } - } else { - r - } -} - /// Number of hours in one day const HOURS_PER_DAY: i64 = 24; /// Number of seconds in one hour diff --git a/vendor/chrono/src/offset/local/tz_info/parser.rs b/vendor/chrono/src/offset/local/tz_info/parser.rs index 5652a0ea9..47cc0377e 100644 --- a/vendor/chrono/src/offset/local/tz_info/parser.rs +++ b/vendor/chrono/src/offset/local/tz_info/parser.rs @@ -7,7 +7,6 @@ use super::rule::TransitionRule; use super::timezone::{LeapSecond, LocalTimeType, TimeZone, Transition}; use super::Error; -#[allow(clippy::map_clone)] // MSRV: 1.36 pub(super) fn parse(bytes: &[u8]) -> Result<TimeZone, Error> { let mut cursor = Cursor::new(bytes); let state = State::new(&mut cursor, true)?; @@ -66,8 +65,8 @@ pub(super) fn parse(bytes: &[u8]) -> Result<TimeZone, Error> { leap_seconds.push(LeapSecond::new(unix_leap_time, correction)); } - let std_walls_iter = state.std_walls.iter().map(|&i| i).chain(iter::repeat(0)); - let ut_locals_iter = state.ut_locals.iter().map(|&i| i).chain(iter::repeat(0)); + let std_walls_iter = state.std_walls.iter().copied().chain(iter::repeat(0)); + let ut_locals_iter = state.ut_locals.iter().copied().chain(iter::repeat(0)); if std_walls_iter.zip(ut_locals_iter).take(state.header.type_count).any(|pair| pair == (0, 1)) { return Err(Error::InvalidTzFile( "invalid couple of standard/wall and UT/local indicators", @@ -238,7 +237,7 @@ impl<'a> Cursor<'a> { } /// Returns `true` if data is remaining - pub(crate) fn is_empty(&self) -> bool { + pub(crate) const fn is_empty(&self) -> bool { self.remaining.is_empty() } diff --git a/vendor/chrono/src/offset/local/tz_info/rule.rs b/vendor/chrono/src/offset/local/tz_info/rule.rs index 7befddb5c..369e317a4 100644 --- a/vendor/chrono/src/offset/local/tz_info/rule.rs +++ b/vendor/chrono/src/offset/local/tz_info/rule.rs @@ -3,7 +3,7 @@ use std::cmp::Ordering; use super::parser::Cursor; use super::timezone::{LocalTimeType, SECONDS_PER_WEEK}; use super::{ - rem_euclid, Error, CUMUL_DAY_IN_MONTHS_NORMAL_YEAR, DAYS_PER_WEEK, DAY_IN_MONTHS_NORMAL_YEAR, + Error, CUMUL_DAY_IN_MONTHS_NORMAL_YEAR, DAYS_PER_WEEK, DAY_IN_MONTHS_NORMAL_YEAR, SECONDS_PER_DAY, }; @@ -127,7 +127,7 @@ pub(super) struct AlternateTime { impl AlternateTime { /// Construct a transition rule representing alternate local time types - fn new( + const fn new( std: LocalTimeType, dst: LocalTimeType, dst_start: RuleDay, @@ -504,7 +504,7 @@ impl RuleDay { } /// Construct a transition rule day represented by a zero-based Julian day in `[0, 365]`, taking occasional Feb 29 into account - fn julian_0(julian_day_0: u16) -> Result<Self, Error> { + const fn julian_0(julian_day_0: u16) -> Result<Self, Error> { if julian_day_0 > 365 { return Err(Error::TransitionRule("invalid rule day julian day")); } @@ -589,9 +589,9 @@ impl RuleDay { } let week_day_of_first_month_day = - rem_euclid(4 + days_since_unix_epoch(year, month, 1), DAYS_PER_WEEK); + (4 + days_since_unix_epoch(year, month, 1)).rem_euclid(DAYS_PER_WEEK); let first_week_day_occurence_in_month = - 1 + rem_euclid(week_day as i64 - week_day_of_first_month_day, DAYS_PER_WEEK); + 1 + (week_day as i64 - week_day_of_first_month_day).rem_euclid(DAYS_PER_WEEK); let mut month_day = first_week_day_occurence_in_month + (week as i64 - 1) * DAYS_PER_WEEK; @@ -737,7 +737,7 @@ const DAY_IN_MONTHS_LEAP_YEAR_FROM_MARCH: [i64; 12] = /// * `year`: Year /// * `month`: Month in `[1, 12]` /// * `month_day`: Day of the month in `[1, 31]` -pub(crate) fn days_since_unix_epoch(year: i32, month: usize, month_day: i64) -> i64 { +pub(crate) const fn days_since_unix_epoch(year: i32, month: usize, month_day: i64) -> i64 { let is_leap_year = is_leap_year(year); let year = year as i64; @@ -768,7 +768,7 @@ pub(crate) fn days_since_unix_epoch(year: i32, month: usize, month_day: i64) -> } /// Check if a year is a leap year -pub(crate) fn is_leap_year(year: i32) -> bool { +pub(crate) const fn is_leap_year(year: i32) -> bool { year % 400 == 0 || (year % 4 == 0 && year % 100 != 0) } @@ -777,7 +777,6 @@ mod tests { use super::super::timezone::Transition; use super::super::{Error, TimeZone}; use super::{AlternateTime, LocalTimeType, RuleDay, TransitionRule}; - use crate::matches; #[test] fn test_quoted() -> Result<(), Error> { diff --git a/vendor/chrono/src/offset/local/tz_info/timezone.rs b/vendor/chrono/src/offset/local/tz_info/timezone.rs index 8572825a8..33c89060c 100644 --- a/vendor/chrono/src/offset/local/tz_info/timezone.rs +++ b/vendor/chrono/src/offset/local/tz_info/timezone.rs @@ -43,6 +43,14 @@ impl TimeZone { return Self::from_tz_data(&fs::read("/etc/localtime")?); } + // attributes are not allowed on if blocks in Rust 1.38 + #[cfg(target_os = "android")] + { + if let Ok(bytes) = android_tzdata::find_tz_data(tz_string) { + return Self::from_tz_data(&bytes); + } + } + let mut chars = tz_string.chars(); if chars.next() == Some(':') { return Self::from_file(&mut find_tz_file(chars.as_str())?); @@ -374,7 +382,7 @@ impl<'a> TimeZoneRef<'a> { } /// Convert Unix time to Unix leap time, from the list of leap seconds in a time zone - fn unix_time_to_unix_leap_time(&self, unix_time: i64) -> Result<i64, Error> { + const fn unix_time_to_unix_leap_time(&self, unix_time: i64) -> Result<i64, Error> { let mut unix_leap_time = unix_time; let mut i = 0; @@ -563,7 +571,7 @@ impl LocalTimeType { } /// Construct a local time type with the specified UTC offset in seconds - pub(super) fn with_offset(ut_offset: i32) -> Result<Self, Error> { + pub(super) const fn with_offset(ut_offset: i32) -> Result<Self, Error> { if ut_offset == i32::min_value() { return Err(Error::LocalTimeType("invalid UTC offset")); } @@ -608,7 +616,7 @@ fn find_tz_file(path: impl AsRef<Path>) -> Result<File, Error> { } #[inline] -fn saturating_abs(v: i32) -> i32 { +const fn saturating_abs(v: i32) -> i32 { if v.is_positive() { v } else if v == i32::min_value() { @@ -620,8 +628,8 @@ fn saturating_abs(v: i32) -> i32 { // Possible system timezone directories #[cfg(unix)] -const ZONE_INFO_DIRECTORIES: [&str; 3] = - ["/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo"]; +const ZONE_INFO_DIRECTORIES: [&str; 4] = + ["/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo", "/usr/share/lib/zoneinfo"]; /// Number of seconds in one week pub(crate) const SECONDS_PER_WEEK: i64 = SECONDS_PER_DAY * DAYS_PER_WEEK; @@ -632,7 +640,6 @@ const SECONDS_PER_28_DAYS: i64 = SECONDS_PER_DAY * 28; mod tests { use super::super::Error; use super::{LeapSecond, LocalTimeType, TimeZone, TimeZoneName, Transition, TransitionRule}; - use crate::matches; #[test] fn test_no_dst() -> Result<(), Error> { diff --git a/vendor/chrono/src/offset/local/unix.rs b/vendor/chrono/src/offset/local/unix.rs index 32aa31618..ce96a6e3b 100644 --- a/vendor/chrono/src/offset/local/unix.rs +++ b/vendor/chrono/src/offset/local/unix.rs @@ -11,15 +11,18 @@ use std::{cell::RefCell, collections::hash_map, env, fs, hash::Hasher, time::SystemTime}; use super::tz_info::TimeZone; -use super::{DateTime, FixedOffset, Local, NaiveDateTime}; -use crate::{Datelike, LocalResult, Utc}; +use super::{FixedOffset, NaiveDateTime}; +use crate::{Datelike, LocalResult}; -pub(super) fn now() -> DateTime<Local> { - let now = Utc::now().naive_utc(); - naive_to_local(&now, false).unwrap() +pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset(utc, false) } -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> { +pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset(local, true) +} + +fn offset(d: &NaiveDateTime, local: bool) -> LocalResult<FixedOffset> { TZ_INFO.with(|maybe_cache| { maybe_cache.borrow_mut().get_or_insert_with(Cache::default).offset(*d, local) }) @@ -68,19 +71,18 @@ struct Cache { last_checked: SystemTime, } -#[cfg(target_os = "android")] -const TZDB_LOCATION: &str = " /system/usr/share/zoneinfo"; - #[cfg(target_os = "aix")] const TZDB_LOCATION: &str = "/usr/share/lib/zoneinfo"; -#[allow(dead_code)] // keeps the cfg simpler #[cfg(not(any(target_os = "android", target_os = "aix")))] const TZDB_LOCATION: &str = "/usr/share/zoneinfo"; fn fallback_timezone() -> Option<TimeZone> { let tz_name = iana_time_zone::get_timezone().ok()?; + #[cfg(not(target_os = "android"))] let bytes = fs::read(format!("{}/{}", TZDB_LOCATION, tz_name)).ok()?; + #[cfg(target_os = "android")] + let bytes = android_tzdata::find_tz_data(&tz_name).ok()?; TimeZone::from_tz_data(&bytes).ok() } @@ -88,7 +90,7 @@ impl Default for Cache { fn default() -> Cache { // default to UTC if no local timezone can be found let env_tz = env::var("TZ").ok(); - let env_ref = env_tz.as_ref().map(|s| s.as_str()); + let env_ref = env_tz.as_deref(); Cache { last_checked: SystemTime::now(), source: Source::new(env_ref), @@ -102,7 +104,7 @@ fn current_zone(var: Option<&str>) -> TimeZone { } impl Cache { - fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> { + fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<FixedOffset> { let now = SystemTime::now(); match now.duration_since(self.last_checked) { @@ -114,7 +116,7 @@ impl Cache { Ok(d) if d.as_secs() < 1 => (), Ok(_) | Err(_) => { let env_tz = env::var("TZ").ok(); - let env_ref = env_tz.as_ref().map(|s| s.as_str()); + let env_ref = env_tz.as_deref(); let new_source = Source::new(env_ref); let out_of_date = match (&self.source, &new_source) { @@ -154,32 +156,16 @@ impl Cache { .offset(); return match FixedOffset::east_opt(offset) { - Some(offset) => LocalResult::Single(DateTime::from_utc(d, offset)), + Some(offset) => LocalResult::Single(offset), None => LocalResult::None, }; } // we pass through the year as the year of a local point in time must either be valid in that locale, or - // the entire time was skipped in which case we will return LocalResult::None anywa. - match self - .zone + // the entire time was skipped in which case we will return LocalResult::None anyway. + self.zone .find_local_time_type_from_local(d.timestamp(), d.year()) .expect("unable to select local time type") - { - LocalResult::None => LocalResult::None, - LocalResult::Ambiguous(early, late) => { - let early_offset = FixedOffset::east_opt(early.offset()).unwrap(); - let late_offset = FixedOffset::east_opt(late.offset()).unwrap(); - - LocalResult::Ambiguous( - DateTime::from_utc(d - early_offset, early_offset), - DateTime::from_utc(d - late_offset, late_offset), - ) - } - LocalResult::Single(tt) => { - let offset = FixedOffset::east_opt(tt.offset()).unwrap(); - LocalResult::Single(DateTime::from_utc(d - offset, offset)) - } - } + .map(|o| FixedOffset::east_opt(o.offset()).unwrap()) } } diff --git a/vendor/chrono/src/offset/local/windows.rs b/vendor/chrono/src/offset/local/windows.rs index e6415015c..84585170c 100644 --- a/vendor/chrono/src/offset/local/windows.rs +++ b/vendor/chrono/src/offset/local/windows.rs @@ -8,271 +8,133 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; -use std::mem; -use std::time::{SystemTime, UNIX_EPOCH}; +use core::mem::MaybeUninit; +use std::io::Error; +use std::ptr; +use std::result::Result; -use winapi::shared::minwindef::*; +use winapi::shared::minwindef::FILETIME; use winapi::um::minwinbase::SYSTEMTIME; -use winapi::um::timezoneapi::*; +use winapi::um::timezoneapi::{ + SystemTimeToFileTime, SystemTimeToTzSpecificLocalTime, TzSpecificLocalTimeToSystemTime, +}; -use super::{FixedOffset, Local}; -use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; +use super::FixedOffset; +use crate::{Datelike, LocalResult, NaiveDateTime, Timelike}; -pub(super) fn now() -> DateTime<Local> { - tm_to_datetime(Timespec::now().local()) -} - -/// Converts a local `NaiveDateTime` to the `time::Timespec`. -pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> { - let tm = Tm { - tm_sec: d.second() as i32, - tm_min: d.minute() as i32, - tm_hour: d.hour() as i32, - tm_mday: d.day() as i32, - tm_mon: d.month0() as i32, // yes, C is that strange... - tm_year: d.year() - 1900, // this doesn't underflow, we know that d is `NaiveDateTime`. - tm_wday: 0, // to_local ignores this - tm_yday: 0, // and this - tm_isdst: -1, - // This seems pretty fake? - tm_utcoff: if local { 1 } else { 0 }, - // do not set this, OS APIs are heavily inconsistent in terms of leap second handling - tm_nsec: 0, - }; - - let spec = Timespec { - sec: match local { - false => utc_tm_to_time(&tm), - true => local_tm_to_time(&tm), - }, - nsec: tm.tm_nsec, - }; - - // Adjust for leap seconds - let mut tm = spec.local(); - assert_eq!(tm.tm_nsec, 0); - tm.tm_nsec = d.nanosecond() as i32; - - // #TODO - there should be ambiguous cases, investigate? - LocalResult::Single(tm_to_datetime(tm)) -} - -/// Converts a `time::Tm` struct into the timezone-aware `DateTime`. -fn tm_to_datetime(mut tm: Tm) -> DateTime<Local> { - if tm.tm_sec >= 60 { - tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000; - tm.tm_sec = 59; - } - - let date = NaiveDate::from_ymd_opt(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32) - .unwrap(); - let time = NaiveTime::from_hms_nano( - tm.tm_hour as u32, - tm.tm_min as u32, - tm.tm_sec as u32, - tm.tm_nsec as u32, - ); - - let offset = FixedOffset::east_opt(tm.tm_utcoff).unwrap(); - DateTime::from_utc(date.and_time(time) - offset, offset) -} - -/// A record specifying a time value in seconds and nanoseconds, where -/// nanoseconds represent the offset from the given second. +/// This macro calls a Windows API FFI and checks whether the function errored with the provided error_id. If an error returns, +/// the macro will return an `Error::last_os_error()`. /// -/// For example a timespec of 1.2 seconds after the beginning of the epoch would -/// be represented as {sec: 1, nsec: 200000000}. -struct Timespec { - sec: i64, - nsec: i32, -} - -impl Timespec { - /// Constructs a timespec representing the current time in UTC. - fn now() -> Timespec { - let st = - SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); - Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 } - } - - /// Converts this timespec into the system's local time. - fn local(self) -> Tm { - let mut tm = Tm { - tm_sec: 0, - tm_min: 0, - tm_hour: 0, - tm_mday: 0, - tm_mon: 0, - tm_year: 0, - tm_wday: 0, - tm_yday: 0, - tm_isdst: 0, - tm_utcoff: 0, - tm_nsec: 0, - }; - time_to_local_tm(self.sec, &mut tm); - tm.tm_nsec = self.nsec; - tm +/// # Safety +/// +/// The provided error ID must align with the provided Windows API, providing the wrong ID could lead to UB. +macro_rules! windows_sys_call { + ($name:ident($($arg:expr),*), $error_id:expr) => { + if $name($($arg),*) == $error_id { + return Err(Error::last_os_error()); + } } } -/// Holds a calendar date and time broken down into its components (year, month, -/// day, and so on), also called a broken-down time value. -// FIXME: use c_int instead of i32? -#[repr(C)] -struct Tm { - /// Seconds after the minute - [0, 60] - tm_sec: i32, - - /// Minutes after the hour - [0, 59] - tm_min: i32, - - /// Hours after midnight - [0, 23] - tm_hour: i32, - - /// Day of the month - [1, 31] - tm_mday: i32, - - /// Months since January - [0, 11] - tm_mon: i32, - - /// Years since 1900 - tm_year: i32, - - /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday. - tm_wday: i32, - - /// Days since January 1 - [0, 365] - tm_yday: i32, - - /// Daylight Saving Time flag. - /// - /// This value is positive if Daylight Saving Time is in effect, zero if - /// Daylight Saving Time is not in effect, and negative if this information - /// is not available. - tm_isdst: i32, - - /// Identifies the time zone that was used to compute this broken-down time - /// value, including any adjustment for Daylight Saving Time. This is the - /// number of seconds east of UTC. For example, for U.S. Pacific Daylight - /// Time, the value is `-7*60*60 = -25200`. - tm_utcoff: i32, - - /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1] - tm_nsec: i32, -} - const HECTONANOSECS_IN_SEC: i64 = 10_000_000; const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC; -fn time_to_file_time(sec: i64) -> FILETIME { - let t = ((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH) as u64; - FILETIME { dwLowDateTime: t as DWORD, dwHighDateTime: (t >> 32) as DWORD } -} - -fn file_time_as_u64(ft: &FILETIME) -> u64 { - ((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64) +pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset(utc, false) } -fn file_time_to_unix_seconds(ft: &FILETIME) -> i64 { - let t = file_time_as_u64(ft) as i64; - ((t - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC) as i64 +pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult<FixedOffset> { + offset(local, true) } -fn system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME { - unsafe { - let mut ft = mem::zeroed(); - SystemTimeToFileTime(sys, &mut ft); - ft - } -} - -fn tm_to_system_time(tm: &Tm) -> SYSTEMTIME { - let mut sys: SYSTEMTIME = unsafe { mem::zeroed() }; - sys.wSecond = tm.tm_sec as WORD; - sys.wMinute = tm.tm_min as WORD; - sys.wHour = tm.tm_hour as WORD; - sys.wDay = tm.tm_mday as WORD; - sys.wDayOfWeek = tm.tm_wday as WORD; - sys.wMonth = (tm.tm_mon + 1) as WORD; - sys.wYear = (tm.tm_year + 1900) as WORD; - sys -} - -fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { - tm.tm_sec = sys.wSecond as i32; - tm.tm_min = sys.wMinute as i32; - tm.tm_hour = sys.wHour as i32; - tm.tm_mday = sys.wDay as i32; - tm.tm_wday = sys.wDayOfWeek as i32; - tm.tm_mon = (sys.wMonth - 1) as i32; - tm.tm_year = (sys.wYear - 1900) as i32; - tm.tm_yday = yday(tm.tm_year, tm.tm_mon + 1, tm.tm_mday); - - fn yday(year: i32, month: i32, day: i32) -> i32 { - let leap = if month > 2 { - if year % 4 == 0 { - 1 - } else { - 2 - } - } else { - 0 - }; - let july = if month > 7 { 1 } else { 0 }; +/// Converts a local `NaiveDateTime` to the `time::Timespec`. +pub(super) fn offset(d: &NaiveDateTime, local: bool) -> LocalResult<FixedOffset> { + let naive_sys_time = system_time_from_naive_date_time(d); - (month - 1) * 30 + month / 2 + (day - 1) - leap + july - } -} + let local_sys_time = match local { + false => from_utc_time(naive_sys_time), + true => from_local_time(naive_sys_time), + }; -macro_rules! call { - ($name:ident($($arg:expr),*)) => { - if $name($($arg),*) == 0 { - panic!(concat!(stringify!($name), " failed with: {}"), - io::Error::last_os_error()); - } + if let Ok(offset) = local_sys_time { + return LocalResult::Single(offset); } -} - -fn time_to_local_tm(sec: i64, tm: &mut Tm) { - let ft = time_to_file_time(sec); - unsafe { - let mut utc = mem::zeroed(); - let mut local = mem::zeroed(); - call!(FileTimeToSystemTime(&ft, &mut utc)); - call!(SystemTimeToTzSpecificLocalTime(0 as *const _, &mut utc, &mut local)); - system_time_to_tm(&local, tm); - - let local = system_time_to_file_time(&local); - let local_sec = file_time_to_unix_seconds(&local); - - let mut tz = mem::zeroed(); - GetTimeZoneInformation(&mut tz); - - // SystemTimeToTzSpecificLocalTime already applied the biases so - // check if it non standard - tm.tm_utcoff = (local_sec - sec) as i32; - tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { 0 } else { 1 }; + LocalResult::None +} + +fn from_utc_time(utc_time: SYSTEMTIME) -> Result<FixedOffset, Error> { + let local_time = utc_to_local_time(&utc_time)?; + let utc_secs = system_time_as_unix_seconds(&utc_time)?; + let local_secs = system_time_as_unix_seconds(&local_time)?; + let offset = (local_secs - utc_secs) as i32; + Ok(FixedOffset::east_opt(offset).unwrap()) +} + +fn from_local_time(local_time: SYSTEMTIME) -> Result<FixedOffset, Error> { + let utc_time = local_to_utc_time(&local_time)?; + let utc_secs = system_time_as_unix_seconds(&utc_time)?; + let local_secs = system_time_as_unix_seconds(&local_time)?; + let offset = (local_secs - utc_secs) as i32; + Ok(FixedOffset::east_opt(offset).unwrap()) +} + +fn system_time_from_naive_date_time(dt: &NaiveDateTime) -> SYSTEMTIME { + SYSTEMTIME { + // Valid values: 1601-30827 + wYear: dt.year() as u16, + // Valid values:1-12 + wMonth: dt.month() as u16, + // Valid values: 0-6, starting Sunday. + // NOTE: enum returns 1-7, starting Monday, so we are + // off here, but this is not currently used in local. + wDayOfWeek: dt.weekday() as u16, + // Valid values: 1-31 + wDay: dt.day() as u16, + // Valid values: 0-23 + wHour: dt.hour() as u16, + // Valid values: 0-59 + wMinute: dt.minute() as u16, + // Valid values: 0-59 + wSecond: dt.second() as u16, + // Valid values: 0-999 + wMilliseconds: 0, } } -fn utc_tm_to_time(tm: &Tm) -> i64 { +pub(crate) fn local_to_utc_time(local: &SYSTEMTIME) -> Result<SYSTEMTIME, Error> { + let mut sys_time = MaybeUninit::<SYSTEMTIME>::uninit(); unsafe { - let mut ft = mem::zeroed(); - let sys_time = tm_to_system_time(tm); - call!(SystemTimeToFileTime(&sys_time, &mut ft)); - file_time_to_unix_seconds(&ft) - } + windows_sys_call!( + TzSpecificLocalTimeToSystemTime(ptr::null(), local, sys_time.as_mut_ptr()), + 0 + ) + }; + // SAFETY: TzSpecificLocalTimeToSystemTime must have succeeded at this point, so we can + // assume the value is initialized. + Ok(unsafe { sys_time.assume_init() }) } -fn local_tm_to_time(tm: &Tm) -> i64 { +pub(crate) fn utc_to_local_time(utc_time: &SYSTEMTIME) -> Result<SYSTEMTIME, Error> { + let mut local = MaybeUninit::<SYSTEMTIME>::uninit(); unsafe { - let mut ft = mem::zeroed(); - let mut utc = mem::zeroed(); - let mut sys_time = tm_to_system_time(tm); - call!(TzSpecificLocalTimeToSystemTime(0 as *mut _, &mut sys_time, &mut utc)); - call!(SystemTimeToFileTime(&utc, &mut ft)); - file_time_to_unix_seconds(&ft) - } + windows_sys_call!( + SystemTimeToTzSpecificLocalTime(ptr::null(), utc_time, local.as_mut_ptr()), + 0 + ) + }; + // SAFETY: SystemTimeToTzSpecificLocalTime must have succeeded at this point, so we can + // assume the value is initialized. + Ok(unsafe { local.assume_init() }) +} + +/// Returns a i64 value representing the unix seconds conversion of the current `WinSystemTime`. +pub(crate) fn system_time_as_unix_seconds(st: &SYSTEMTIME) -> Result<i64, Error> { + let mut init = MaybeUninit::<FILETIME>::uninit(); + unsafe { windows_sys_call!(SystemTimeToFileTime(st, init.as_mut_ptr()), 0) } + // SystemTimeToFileTime must have succeeded at this point, so we can assum the value is + // initalized. + let filetime = unsafe { init.assume_init() }; + let bit_shift = ((filetime.dwHighDateTime as u64) << 32) | (filetime.dwLowDateTime as u64); + let unix_secs = (bit_shift as i64 - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC; + Ok(unix_secs) } |