1#![cfg_attr(not(feature = "std"), no_std)]
132
133#[cfg(feature = "std")]
134extern crate std as core;
135
136extern crate chrono;
137extern crate phf;
138#[cfg(feature = "case-insensitive")]
139extern crate uncased;
140
141#[cfg(feature = "serde")]
142mod serde;
143
144mod binary_search;
145mod directory;
146mod timezone_impl;
147mod timezones;
148
149pub use directory::*;
150pub use timezone_impl::{OffsetComponents, OffsetName};
151pub use timezones::ParseError;
152pub use timezones::Tz;
153pub use timezones::TZ_VARIANTS;
154
155#[cfg(test)]
156mod tests {
157 use super::America::Danmarkshavn;
158 use super::Asia::Dhaka;
159 use super::Australia::Adelaide;
160 use super::Europe::Berlin;
161 use super::Europe::London;
162 use super::Europe::Moscow;
163 use super::Europe::Vilnius;
164 use super::Europe::Warsaw;
165 use super::Pacific::Apia;
166 use super::Pacific::Noumea;
167 use super::Pacific::Tahiti;
168 use super::Tz;
169 use super::US::Eastern;
170 use super::UTC;
171 use chrono::{Duration, TimeZone};
172
173 #[test]
174 fn london_to_berlin() {
175 let dt = London.ymd(2016, 10, 8).and_hms(17, 0, 0);
176 let converted = dt.with_timezone(&Berlin);
177 let expected = Berlin.ymd(2016, 10, 8).and_hms(18, 0, 0);
178 assert_eq!(converted, expected);
179 }
180
181 #[test]
182 fn us_eastern_dst_commutativity() {
183 let dt = UTC.ymd(2002, 4, 7).and_hms(7, 0, 0);
184 for days in -420..720 {
185 let dt1 = (dt + Duration::days(days)).with_timezone(&Eastern);
186 let dt2 = dt.with_timezone(&Eastern) + Duration::days(days);
187 assert_eq!(dt1, dt2);
188 }
189 }
190
191 #[test]
192 fn test_addition_across_dst_boundary() {
193 use chrono::TimeZone;
194 let two_hours = Duration::hours(2);
195 let edt = Eastern.ymd(2019, 11, 3).and_hms(0, 0, 0);
196 let est = edt + two_hours;
197
198 assert_eq!(edt.to_string(), "2019-11-03 00:00:00 EDT".to_string());
199 assert_eq!(est.to_string(), "2019-11-03 01:00:00 EST".to_string());
200 assert_eq!(est.timestamp(), edt.timestamp() + two_hours.num_seconds());
201 }
202
203 #[test]
204 fn warsaw_tz_name() {
205 let dt = UTC.ymd(1915, 8, 4).and_hms(22, 35, 59);
206 assert_eq!(dt.with_timezone(&Warsaw).format("%Z").to_string(), "WMT");
207 let dt = dt + Duration::seconds(1);
208 assert_eq!(dt.with_timezone(&Warsaw).format("%Z").to_string(), "CET");
209 }
210
211 #[test]
212 fn vilnius_utc_offset() {
213 let dt = UTC.ymd(1916, 12, 31).and_hms(22, 35, 59).with_timezone(&Vilnius);
214 assert_eq!(dt, Vilnius.ymd(1916, 12, 31).and_hms(23, 59, 59));
215 let dt = dt + Duration::seconds(1);
216 assert_eq!(dt, Vilnius.ymd(1917, 1, 1).and_hms(0, 11, 36));
217 }
218
219 #[test]
220 fn victorian_times() {
221 let dt = UTC.ymd(1847, 12, 1).and_hms(0, 1, 14).with_timezone(&London);
222 assert_eq!(dt, London.ymd(1847, 11, 30).and_hms(23, 59, 59));
223 let dt = dt + Duration::seconds(1);
224 assert_eq!(dt, London.ymd(1847, 12, 1).and_hms(0, 1, 15));
225 }
226
227 #[test]
228 fn london_dst() {
229 let dt = London.ymd(2016, 3, 10).and_hms(5, 0, 0);
230 let later = dt + Duration::days(180);
231 let expected = London.ymd(2016, 9, 6).and_hms(6, 0, 0);
232 assert_eq!(later, expected);
233 }
234
235 #[test]
236 fn international_date_line_change() {
237 let dt = UTC.ymd(2011, 12, 30).and_hms(9, 59, 59).with_timezone(&Apia);
238 assert_eq!(dt, Apia.ymd(2011, 12, 29).and_hms(23, 59, 59));
239 let dt = dt + Duration::seconds(1);
240 assert_eq!(dt, Apia.ymd(2011, 12, 31).and_hms(0, 0, 0));
241 }
242
243 #[test]
244 fn negative_offset_with_minutes_and_seconds() {
245 let dt = UTC.ymd(1900, 1, 1).and_hms(12, 0, 0).with_timezone(&Danmarkshavn);
246 assert_eq!(dt, Danmarkshavn.ymd(1900, 1, 1).and_hms(10, 45, 20));
247 }
248
249 #[test]
250 fn monotonicity() {
251 let mut dt = Noumea.ymd(1800, 1, 1).and_hms(12, 0, 0);
252 for _ in 0..24 * 356 * 400 {
253 let new = dt + Duration::hours(1);
254 assert!(new > dt);
255 assert!(new.with_timezone(&UTC) > dt.with_timezone(&UTC));
256 dt = new;
257 }
258 }
259
260 fn test_inverse<T: TimeZone>(tz: T, begin: i32, end: i32) {
261 for y in begin..end {
262 for d in 1..366 {
263 for h in 0..24 {
264 for m in 0..60 {
265 let dt = UTC.yo(y, d).and_hms(h, m, 0);
266 let with_tz = dt.with_timezone(&tz);
267 let utc = with_tz.with_timezone(&UTC);
268 assert_eq!(dt, utc);
269 }
270 }
271 }
272 }
273 }
274
275 #[test]
276 fn inverse_london() {
277 test_inverse(London, 1989, 1994);
278 }
279
280 #[test]
281 fn inverse_dhaka() {
282 test_inverse(Dhaka, 1995, 2000);
283 }
284
285 #[test]
286 fn inverse_apia() {
287 test_inverse(Apia, 2011, 2012);
288 }
289
290 #[test]
291 fn inverse_tahiti() {
292 test_inverse(Tahiti, 1911, 1914);
293 }
294
295 #[test]
296 fn string_representation() {
297 let dt = UTC.ymd(2000, 9, 1).and_hms(12, 30, 15).with_timezone(&Adelaide);
298 assert_eq!(dt.to_string(), "2000-09-01 22:00:15 ACST");
299 assert_eq!(format!("{:?}", dt), "2000-09-01T22:00:15ACST");
300 assert_eq!(dt.to_rfc3339(), "2000-09-01T22:00:15+09:30");
301 assert_eq!(format!("{}", dt), "2000-09-01 22:00:15 ACST");
302 }
303
304 #[test]
305 fn tahiti() {
306 let dt = UTC.ymd(1912, 10, 1).and_hms(9, 58, 16).with_timezone(&Tahiti);
307 let before = dt - Duration::hours(1);
308 assert_eq!(before, Tahiti.ymd(1912, 9, 30).and_hms(23, 0, 0));
309 let after = dt + Duration::hours(1);
310 assert_eq!(after, Tahiti.ymd(1912, 10, 1).and_hms(0, 58, 16));
311 }
312
313 #[test]
314 #[should_panic]
315 fn nonexistent_time() {
316 let _ = London.ymd(2016, 3, 27).and_hms(1, 30, 0);
317 }
318
319 #[test]
320 #[should_panic]
321 fn nonexistent_time_2() {
322 let _ = London.ymd(2016, 3, 27).and_hms(1, 0, 0);
323 }
324
325 #[test]
326 fn time_exists() {
327 let _ = London.ymd(2016, 3, 27).and_hms(2, 0, 0);
328 }
329
330 #[test]
331 #[should_panic]
332 fn ambiguous_time() {
333 let _ = London.ymd(2016, 10, 30).and_hms(1, 0, 0);
334 }
335
336 #[test]
337 #[should_panic]
338 fn ambiguous_time_2() {
339 let _ = London.ymd(2016, 10, 30).and_hms(1, 30, 0);
340 }
341
342 #[test]
343 #[should_panic]
344 fn ambiguous_time_3() {
345 let _ = Moscow.ymd(2014, 10, 26).and_hms(1, 30, 0);
346 }
347
348 #[test]
349 #[should_panic]
350 fn ambiguous_time_4() {
351 let _ = Moscow.ymd(2014, 10, 26).and_hms(1, 0, 0);
352 }
353
354 #[test]
355 fn unambiguous_time() {
356 let _ = London.ymd(2016, 10, 30).and_hms(2, 0, 0);
357 }
358
359 #[test]
360 fn unambiguous_time_2() {
361 let _ = Moscow.ymd(2014, 10, 26).and_hms(2, 0, 0);
362 }
363
364 #[test]
365 fn test_get_name() {
366 assert_eq!(London.name(), "Europe/London");
367 assert_eq!(Tz::Africa__Abidjan.name(), "Africa/Abidjan");
368 assert_eq!(Tz::UTC.name(), "UTC");
369 assert_eq!(Tz::Zulu.name(), "Zulu");
370 }
371
372 #[test]
373 fn test_display() {
374 assert_eq!(format!("{}", London), "Europe/London");
375 assert_eq!(format!("{}", Tz::Africa__Abidjan), "Africa/Abidjan");
376 assert_eq!(format!("{}", Tz::UTC), "UTC");
377 assert_eq!(format!("{}", Tz::Zulu), "Zulu");
378 }
379
380 #[test]
381 fn test_impl_hash() {
382 #[allow(dead_code)]
383 #[derive(Hash)]
384 struct Foo(Tz);
385 }
386}