diff options
Diffstat (limited to 'vendor/chrono/src/offset/local/mod.rs')
-rw-r--r-- | vendor/chrono/src/offset/local/mod.rs | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/vendor/chrono/src/offset/local/mod.rs b/vendor/chrono/src/offset/local/mod.rs new file mode 100644 index 000000000..e280c7800 --- /dev/null +++ b/vendor/chrono/src/offset/local/mod.rs @@ -0,0 +1,260 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! The local (system) time zone. + +#[cfg(feature = "rkyv")] +use rkyv::{Archive, Deserialize, Serialize}; + +use super::fixed::FixedOffset; +use super::{LocalResult, TimeZone}; +use crate::naive::{NaiveDate, NaiveDateTime}; +#[allow(deprecated)] +use crate::{Date, DateTime}; + +// 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), + not(all( + target_arch = "wasm32", + feature = "wasmbind", + not(any(target_os = "emscripten", target_os = "wasi")) + )) +))] +#[path = "stub.rs"] +mod inner; + +#[cfg(unix)] +#[path = "unix.rs"] +mod inner; + +#[cfg(windows)] +#[path = "windows.rs"] +mod inner; + +#[cfg(unix)] +mod tz_info; + +/// The local timescale. This is implemented via the standard `time` crate. +/// +/// Using the [`TimeZone`](./trait.TimeZone.html) methods +/// on the Local struct is the preferred way to construct `DateTime<Local>` +/// instances. +/// +/// # Example +/// +/// ``` +/// use chrono::{Local, DateTime, TimeZone}; +/// +/// let dt: DateTime<Local> = Local::now(); +/// let dt: DateTime<Local> = Local.timestamp(0, 0); +/// ``` +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +pub struct Local; + +impl Local { + /// Returns a `Date` which corresponds to the current date. + #[deprecated(since = "0.4.23", note = "use `Local::now()` instead")] + #[allow(deprecated)] + pub fn today() -> Date<Local> { + Local::now().date() + } + + /// Returns a `DateTime` which corresponds to the current date and time. + #[cfg(not(all( + target_arch = "wasm32", + feature = "wasmbind", + not(any(target_os = "emscripten", target_os = "wasi")) + )))] + pub fn now() -> DateTime<Local> { + inner::now() + } + + /// Returns a `DateTime` which corresponds to the current date and time. + #[cfg(all( + target_arch = "wasm32", + feature = "wasmbind", + not(any(target_os = "emscripten", target_os = "wasi")) + ))] + pub fn now() -> DateTime<Local> { + use super::Utc; + let now: DateTime<Utc> = super::Utc::now(); + + // Workaround missing timezone logic in `time` crate + let offset = + FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) + .unwrap(); + DateTime::from_utc(now.naive_utc(), offset) + } +} + +impl TimeZone for Local { + type Offset = FixedOffset; + + fn from_offset(_offset: &FixedOffset) -> 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()) + } + + fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<FixedOffset> { + self.from_local_datetime(local).map(|datetime| *datetime.offset()) + } + + #[allow(deprecated)] + fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset { + *self.from_utc_date(utc).offset() + } + + 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() + } +} + +#[cfg(test)] +mod tests { + use super::Local; + use crate::offset::TimeZone; + use crate::{Datelike, Duration, Utc}; + + #[test] + fn verify_correct_offsets() { + let now = Local::now(); + let from_local = Local.from_local_datetime(&now.naive_local()).unwrap(); + let from_utc = Local.from_utc_datetime(&now.naive_utc()); + + assert_eq!(now.offset().local_minus_utc(), from_local.offset().local_minus_utc()); + assert_eq!(now.offset().local_minus_utc(), from_utc.offset().local_minus_utc()); + + assert_eq!(now, from_local); + assert_eq!(now, from_utc); + } + + #[test] + fn verify_correct_offsets_distant_past() { + // let distant_past = Local::now() - Duration::days(365 * 100); + let distant_past = Local::now() - Duration::days(250 * 31); + let from_local = Local.from_local_datetime(&distant_past.naive_local()).unwrap(); + let from_utc = Local.from_utc_datetime(&distant_past.naive_utc()); + + assert_eq!(distant_past.offset().local_minus_utc(), from_local.offset().local_minus_utc()); + assert_eq!(distant_past.offset().local_minus_utc(), from_utc.offset().local_minus_utc()); + + assert_eq!(distant_past, from_local); + assert_eq!(distant_past, from_utc); + } + + #[test] + fn verify_correct_offsets_distant_future() { + let distant_future = Local::now() + Duration::days(250 * 31); + let from_local = Local.from_local_datetime(&distant_future.naive_local()).unwrap(); + let from_utc = Local.from_utc_datetime(&distant_future.naive_utc()); + + assert_eq!( + distant_future.offset().local_minus_utc(), + from_local.offset().local_minus_utc() + ); + assert_eq!(distant_future.offset().local_minus_utc(), from_utc.offset().local_minus_utc()); + + assert_eq!(distant_future, from_local); + assert_eq!(distant_future, from_utc); + } + + #[test] + fn test_local_date_sanity_check() { + // issue #27 + assert_eq!(Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0).unwrap().day(), 28); + } + + #[test] + fn test_leap_second() { + // 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 + ); + } +} |