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