1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
35
36use time::{OffsetDateTime, PrimitiveDateTime};
37
38mod sealing {
39 pub trait OffsetDateTimeExt {}
40 pub trait PrimitiveDateTimeExt {}
41
42 impl OffsetDateTimeExt for time::OffsetDateTime {}
43 impl PrimitiveDateTimeExt for time::PrimitiveDateTime {}
44}
45
46pub trait OffsetDateTimeExt: sealing::OffsetDateTimeExt {
48 fn to_timezone<T: TimeZone>(&self, tz: &T) -> OffsetDateTime;
50}
51
52pub trait PrimitiveDateTimeExt: sealing::PrimitiveDateTimeExt {
54 fn assume_timezone<T: TimeZone>(&self, tz: &T) -> OffsetResult<OffsetDateTime>;
65
66 fn assume_timezone_utc<T: TimeZone>(&self, tz: &T) -> OffsetDateTime;
76}
77
78impl PrimitiveDateTimeExt for PrimitiveDateTime {
79 fn assume_timezone<T: TimeZone>(&self, tz: &T) -> OffsetResult<OffsetDateTime> {
80 match tz.get_offset_local(&self.assume_utc()) {
81 OffsetResult::Some(a) => OffsetResult::Some(self.assume_offset(a.to_utc())),
82 OffsetResult::Ambiguous(a, b) => OffsetResult::Ambiguous(
83 self.assume_offset(a.to_utc()),
84 self.assume_offset(b.to_utc()),
85 ),
86 OffsetResult::None => OffsetResult::None,
87 }
88 }
89
90 fn assume_timezone_utc<T: TimeZone>(&self, tz: &T) -> OffsetDateTime {
91 let offset = tz.get_offset_utc(&self.assume_utc());
92 self.assume_offset(offset.to_utc())
93 }
94}
95
96impl OffsetDateTimeExt for OffsetDateTime {
97 fn to_timezone<T: TimeZone>(&self, tz: &T) -> OffsetDateTime {
98 let offset = tz.get_offset_utc(self);
99 self.to_offset(offset.to_utc())
100 }
101}
102
103mod binary_search;
104mod interface;
105mod timezone_impl;
106
107#[cfg(feature = "db")]
108pub mod timezones;
109
110pub use interface::*;
111
112#[cfg(feature = "system")]
113pub mod system;
114
115#[cfg(feature = "posix-tz")]
116pub mod posix_tz;
117
118#[cfg(feature = "db")]
119pub use timezone_impl::Tz;
120
121#[cfg(test)]
122mod tests {
123 use crate::timezones;
124 use crate::Offset;
125 use crate::OffsetDateTimeExt;
126 use crate::PrimitiveDateTimeExt;
127 use crate::TimeZone;
128 use time::macros::{datetime, offset};
129 use time::OffsetDateTime;
130
131 #[test]
132 fn names() {
133 let shanghai = timezones::get_by_name("Asia/Shanghai");
135 let china = timezones::get_by_name("China Standard Time");
136 assert!(shanghai.is_some());
137 assert!(china.is_some());
138 assert_eq!(shanghai, china);
139 }
140
141 #[test]
142 fn find() {
143 let zones_iana = timezones::find_by_name("Asia");
144 assert!(zones_iana.len() > 1);
146 }
148
149 #[test]
150 fn offsets_and_name() {
151 let tz = timezones::db::europe::LONDON;
152 assert_eq!(tz.name(), "Europe/London");
153 let offset = tz.get_offset_utc(&OffsetDateTime::now_utc());
154 assert!(!offset.name().is_empty());
155 }
156
157 #[test]
158 fn london_to_berlin() {
159 let dt = datetime!(2016-10-8 17:0:0).assume_timezone_utc(timezones::db::europe::LONDON);
160 let converted = dt.to_timezone(timezones::db::europe::BERLIN);
161 let expected =
162 datetime!(2016-10-8 18:0:0).assume_timezone_utc(timezones::db::europe::BERLIN);
163 assert_eq!(converted, expected);
164 }
165
166 #[test]
167 fn dst() {
168 let london = timezones::db::europe::LONDON;
169 let odt1 = datetime!(2021-01-01 12:0:0 UTC);
170 assert_eq!(odt1.to_timezone(london), datetime!(2021-01-01 12:0:0 +0));
171 let odt2 = datetime!(2021-07-01 12:0:0 UTC);
172 assert_eq!(
175 odt2.to_timezone(london),
176 datetime!(2021-07-01 12:0:0 UTC).to_offset(offset!(+1))
177 );
178 }
179
180 #[test]
181 fn handles_forward_changeover() {
182 assert_eq!(
183 datetime!(2022-03-27 01:30)
184 .assume_timezone(timezones::db::CET)
185 .unwrap(),
186 datetime!(2022-03-27 01:30 +01:00)
187 );
188 }
189
190 #[test]
191 fn handles_after_changeover() {
192 assert_eq!(
193 datetime!(2022-03-27 03:30)
194 .assume_timezone(timezones::db::CET)
195 .unwrap(),
196 datetime!(2022-03-27 03:30 +02:00)
197 );
198 }
199
200 #[test]
201 fn handles_broken_time() {
202 assert!(datetime!(2022-03-27 02:30)
203 .assume_timezone(timezones::db::CET)
204 .is_none());
205 }
206
207 #[test]
208 fn handles_backward_changeover() {
209 assert_eq!(
211 datetime!(2022-10-30 02:30)
212 .assume_timezone(timezones::db::CET)
213 .unwrap_first(),
214 datetime!(2022-10-30 02:30 +02:00)
215 );
216 assert_eq!(
217 datetime!(2022-10-30 02:30)
218 .assume_timezone(timezones::db::CET)
219 .unwrap_second(),
220 datetime!(2022-10-30 02:30 +01:00)
221 );
222 }
223}