#![cfg_attr(docsrs, feature(doc_auto_cfg))]
use time::{OffsetDateTime, PrimitiveDateTime};
mod sealing {
pub trait OffsetDateTimeExt {}
pub trait PrimitiveDateTimeExt {}
impl OffsetDateTimeExt for time::OffsetDateTime {}
impl PrimitiveDateTimeExt for time::PrimitiveDateTime {}
}
pub trait OffsetDateTimeExt: sealing::OffsetDateTimeExt {
fn to_timezone<T: TimeZone>(&self, tz: &T) -> OffsetDateTime;
}
pub trait PrimitiveDateTimeExt: sealing::PrimitiveDateTimeExt {
fn assume_timezone<T: TimeZone>(&self, tz: &T) -> OffsetResult<OffsetDateTime>;
fn assume_timezone_utc<T: TimeZone>(&self, tz: &T) -> OffsetDateTime;
}
impl PrimitiveDateTimeExt for PrimitiveDateTime {
fn assume_timezone<T: TimeZone>(&self, tz: &T) -> OffsetResult<OffsetDateTime> {
match tz.get_offset_local(&self.assume_utc()) {
OffsetResult::Some(a) => OffsetResult::Some(self.assume_offset(a.to_utc())),
OffsetResult::Ambiguous(a, b) => OffsetResult::Ambiguous(
self.assume_offset(a.to_utc()),
self.assume_offset(b.to_utc()),
),
OffsetResult::None => OffsetResult::None,
}
}
fn assume_timezone_utc<T: TimeZone>(&self, tz: &T) -> OffsetDateTime {
let offset = tz.get_offset_utc(&self.assume_utc());
self.assume_offset(offset.to_utc())
}
}
impl OffsetDateTimeExt for OffsetDateTime {
fn to_timezone<T: TimeZone>(&self, tz: &T) -> OffsetDateTime {
let offset = tz.get_offset_utc(self);
self.to_offset(offset.to_utc())
}
}
mod binary_search;
mod interface;
mod timezone_impl;
#[cfg(feature = "db")]
pub mod timezones;
pub use interface::*;
#[cfg(feature = "system")]
pub mod system;
#[cfg(feature = "posix-tz")]
pub mod posix_tz;
#[cfg(feature = "db")]
pub use timezone_impl::Tz;
#[cfg(test)]
mod tests {
use crate::timezones;
use crate::Offset;
use crate::OffsetDateTimeExt;
use crate::PrimitiveDateTimeExt;
use crate::TimeZone;
use time::macros::{datetime, offset};
use time::OffsetDateTime;
#[test]
fn names() {
let shanghai = timezones::get_by_name("Asia/Shanghai");
let china = timezones::get_by_name("China Standard Time");
assert!(shanghai.is_some());
assert!(china.is_some());
assert_eq!(shanghai, china);
}
#[test]
fn find() {
let zones_iana = timezones::find_by_name("Asia");
assert!(zones_iana.len() > 1);
}
#[test]
fn offsets_and_name() {
let tz = timezones::db::europe::LONDON;
assert_eq!(tz.name(), "Europe/London");
let offset = tz.get_offset_utc(&OffsetDateTime::now_utc());
assert!(!offset.name().is_empty());
}
#[test]
fn london_to_berlin() {
let dt = datetime!(2016-10-8 17:0:0).assume_timezone_utc(timezones::db::europe::LONDON);
let converted = dt.to_timezone(timezones::db::europe::BERLIN);
let expected =
datetime!(2016-10-8 18:0:0).assume_timezone_utc(timezones::db::europe::BERLIN);
assert_eq!(converted, expected);
}
#[test]
fn dst() {
let london = timezones::db::europe::LONDON;
let odt1 = datetime!(2021-01-01 12:0:0 UTC);
assert_eq!(odt1.to_timezone(london), datetime!(2021-01-01 12:0:0 +0));
let odt2 = datetime!(2021-07-01 12:0:0 UTC);
assert_eq!(
odt2.to_timezone(london),
datetime!(2021-07-01 12:0:0 UTC).to_offset(offset!(+1))
);
}
#[test]
fn handles_forward_changeover() {
assert_eq!(
datetime!(2022-03-27 01:30)
.assume_timezone(timezones::db::CET)
.unwrap(),
datetime!(2022-03-27 01:30 +01:00)
);
}
#[test]
fn handles_after_changeover() {
assert_eq!(
datetime!(2022-03-27 03:30)
.assume_timezone(timezones::db::CET)
.unwrap(),
datetime!(2022-03-27 03:30 +02:00)
);
}
#[test]
fn handles_broken_time() {
assert!(datetime!(2022-03-27 02:30)
.assume_timezone(timezones::db::CET)
.is_none());
}
#[test]
fn handles_backward_changeover() {
assert_eq!(
datetime!(2022-10-30 02:30)
.assume_timezone(timezones::db::CET)
.unwrap_first(),
datetime!(2022-10-30 02:30 +02:00)
);
assert_eq!(
datetime!(2022-10-30 02:30)
.assume_timezone(timezones::db::CET)
.unwrap_second(),
datetime!(2022-10-30 02:30 +01:00)
);
}
}