| 1 | //! # Chrono-TZ |
| 2 | //! |
| 3 | //! `Chrono-TZ` is a library that provides implementors of the |
| 4 | //! [`TimeZone`][timezone] trait for [`chrono`][chrono]. The |
| 5 | //! impls are generated by a build script using the [`IANA database`][iana] |
| 6 | //! and [`zoneinfo_parse`][zoneinfo_parse]. |
| 7 | //! |
| 8 | //! [chrono]: https://github.com/lifthrasiir/rust-chrono |
| 9 | //! [timezone]: https://lifthrasiir.github.io/rust-chrono/chrono/offset/trait.TimeZone.html |
| 10 | //! [iana]: http://www.iana.org/time-zones |
| 11 | //! [zoneinfo_parse]: https://github.com/rust-datetime/zoneinfo-parse |
| 12 | //! |
| 13 | //! ## Examples |
| 14 | //! |
| 15 | //! Create a time in one timezone and convert it to UTC |
| 16 | //! |
| 17 | //! ``` |
| 18 | //! # extern crate chrono; |
| 19 | //! # extern crate chrono_tz; |
| 20 | //! use chrono::{TimeZone, Utc}; |
| 21 | //! use chrono_tz::US::Pacific; |
| 22 | //! |
| 23 | //! # fn main() { |
| 24 | //! let pacific_time = Pacific.ymd(1990, 5, 6).and_hms(12, 30, 45); |
| 25 | //! let utc_time = pacific_time.with_timezone(&Utc); |
| 26 | //! assert_eq!(utc_time, Utc.ymd(1990, 5, 6).and_hms(19, 30, 45)); |
| 27 | //! # } |
| 28 | //! ``` |
| 29 | //! |
| 30 | //! Create a naive datetime and convert it to a timezone-aware datetime |
| 31 | //! |
| 32 | //! ``` |
| 33 | //! # extern crate chrono; |
| 34 | //! # extern crate chrono_tz; |
| 35 | //! use chrono::{TimeZone, NaiveDate}; |
| 36 | //! use chrono_tz::Africa::Johannesburg; |
| 37 | //! |
| 38 | //! # fn main() { |
| 39 | //! let naive_dt = NaiveDate::from_ymd(2038, 1, 19).and_hms(3, 14, 08); |
| 40 | //! let tz_aware = Johannesburg.from_local_datetime(&naive_dt).unwrap(); |
| 41 | //! assert_eq!(tz_aware.to_string(), "2038-01-19 03:14:08 SAST" ); |
| 42 | //! # } |
| 43 | //! ``` |
| 44 | //! |
| 45 | //! London and New York change their clocks on different days in March |
| 46 | //! so only have a 4-hour difference on certain days. |
| 47 | //! |
| 48 | //! ``` |
| 49 | //! # extern crate chrono; |
| 50 | //! # extern crate chrono_tz; |
| 51 | //! use chrono::TimeZone; |
| 52 | //! use chrono_tz::Europe::London; |
| 53 | //! use chrono_tz::America::New_York; |
| 54 | //! |
| 55 | //! # fn main() { |
| 56 | //! let london_time = London.ymd(2016, 3, 18).and_hms(3, 0, 0); |
| 57 | //! let ny_time = london_time.with_timezone(&New_York); |
| 58 | //! assert_eq!(ny_time, New_York.ymd(2016, 3, 17).and_hms(23, 0, 0)); |
| 59 | //! # } |
| 60 | //! ``` |
| 61 | //! |
| 62 | //! Adding 24 hours across a daylight savings change causes a change |
| 63 | //! in local time |
| 64 | //! |
| 65 | //! ``` |
| 66 | //! # extern crate chrono; |
| 67 | //! # extern crate chrono_tz; |
| 68 | //! use chrono::{TimeZone, Duration}; |
| 69 | //! use chrono_tz::Europe::London; |
| 70 | //! |
| 71 | //! # fn main() { |
| 72 | //! let dt = London.ymd(2016, 10, 29).and_hms(12, 0, 0); |
| 73 | //! let later = dt + Duration::hours(24); |
| 74 | //! assert_eq!(later, London.ymd(2016, 10, 30).and_hms(11, 0, 0)); |
| 75 | //! # } |
| 76 | //! ``` |
| 77 | //! |
| 78 | //! And of course you can always convert a local time to a unix timestamp |
| 79 | //! |
| 80 | //! ``` |
| 81 | //! # extern crate chrono; |
| 82 | //! # extern crate chrono_tz; |
| 83 | //! use chrono::TimeZone; |
| 84 | //! use chrono_tz::Asia::Kolkata; |
| 85 | //! |
| 86 | //! # fn main() { |
| 87 | //! let dt = Kolkata.ymd(2000, 1, 1).and_hms(0, 0, 0); |
| 88 | //! let timestamp = dt.timestamp(); |
| 89 | //! assert_eq!(timestamp, 946665000); |
| 90 | //! # } |
| 91 | //! ``` |
| 92 | //! |
| 93 | //! Pretty-printing a string will use the correct abbreviation for the timezone |
| 94 | //! |
| 95 | //! ``` |
| 96 | //! # extern crate chrono; |
| 97 | //! # extern crate chrono_tz; |
| 98 | //! use chrono::TimeZone; |
| 99 | //! use chrono_tz::Europe::London; |
| 100 | //! |
| 101 | //! # fn main() { |
| 102 | //! let dt = London.ymd(2016, 5, 10).and_hms(12, 0, 0); |
| 103 | //! assert_eq!(dt.to_string(), "2016-05-10 12:00:00 BST" ); |
| 104 | //! assert_eq!(dt.to_rfc3339(), "2016-05-10T12:00:00+01:00" ); |
| 105 | //! # } |
| 106 | //! ``` |
| 107 | //! |
| 108 | //! You can convert a timezone string to a timezone using the `FromStr` trait |
| 109 | //! |
| 110 | //! ``` |
| 111 | //! # extern crate chrono; |
| 112 | //! # extern crate chrono_tz; |
| 113 | //! use chrono::TimeZone; |
| 114 | //! use chrono_tz::Tz; |
| 115 | //! use chrono_tz::UTC; |
| 116 | //! |
| 117 | //! # fn main() { |
| 118 | //! let tz: Tz = "Antarctica/South_Pole" .parse().unwrap(); |
| 119 | //! let dt = tz.ymd(2016, 10, 22).and_hms(12, 0, 0); |
| 120 | //! let utc = dt.with_timezone(&UTC); |
| 121 | //! assert_eq!(utc.to_string(), "2016-10-21 23:00:00 UTC" ); |
| 122 | //! # } |
| 123 | //! ``` |
| 124 | //! |
| 125 | //! If you need to iterate over all variants you can use the `TZ_VARIANTS` array |
| 126 | //! ``` |
| 127 | //! use chrono_tz::{TZ_VARIANTS, Tz}; |
| 128 | //! assert!(TZ_VARIANTS.iter().any(|v| *v == Tz::UTC)); |
| 129 | //! ``` |
| 130 | |
| 131 | #![cfg_attr (not(any(feature = "std" , test)), no_std)] |
| 132 | #![cfg_attr (docsrs, feature(doc_cfg, doc_auto_cfg))] |
| 133 | |
| 134 | #[cfg (feature = "serde" )] |
| 135 | mod serde; |
| 136 | |
| 137 | mod binary_search; |
| 138 | mod directory; |
| 139 | mod timezone_impl; |
| 140 | mod timezones; |
| 141 | |
| 142 | pub use crate::directory::*; |
| 143 | pub use crate::timezone_impl::{OffsetComponents, OffsetName, TzOffset}; |
| 144 | pub use crate::timezones::ParseError; |
| 145 | pub use crate::timezones::Tz; |
| 146 | pub use crate::timezones::TZ_VARIANTS; |
| 147 | pub use crate::IANA_TZDB_VERSION; |
| 148 | |
| 149 | #[cfg (test)] |
| 150 | mod tests { |
| 151 | use super::Africa::Addis_Ababa; |
| 152 | use super::America::Danmarkshavn; |
| 153 | use super::America::Scoresbysund; |
| 154 | use super::Antarctica::Casey; |
| 155 | use super::Asia::Dhaka; |
| 156 | use super::Australia::Adelaide; |
| 157 | use super::Europe::Berlin; |
| 158 | use super::Europe::London; |
| 159 | use super::Europe::Moscow; |
| 160 | use super::Europe::Vilnius; |
| 161 | use super::Europe::Warsaw; |
| 162 | use super::Pacific::Apia; |
| 163 | use super::Pacific::Noumea; |
| 164 | use super::Pacific::Tahiti; |
| 165 | use super::Tz; |
| 166 | use super::IANA_TZDB_VERSION; |
| 167 | use super::US::Eastern; |
| 168 | use super::UTC; |
| 169 | use chrono::{Duration, NaiveDate, TimeZone}; |
| 170 | |
| 171 | #[test ] |
| 172 | fn london_to_berlin() { |
| 173 | let dt = London.with_ymd_and_hms(2016, 10, 8, 17, 0, 0).unwrap(); |
| 174 | let converted = dt.with_timezone(&Berlin); |
| 175 | let expected = Berlin.with_ymd_and_hms(2016, 10, 8, 18, 0, 0).unwrap(); |
| 176 | assert_eq!(converted, expected); |
| 177 | } |
| 178 | |
| 179 | #[test ] |
| 180 | fn us_eastern_dst_commutativity() { |
| 181 | let dt = UTC.with_ymd_and_hms(2002, 4, 7, 7, 0, 0).unwrap(); |
| 182 | for days in -420..720 { |
| 183 | let dt1 = (dt + Duration::days(days)).with_timezone(&Eastern); |
| 184 | let dt2 = dt.with_timezone(&Eastern) + Duration::days(days); |
| 185 | assert_eq!(dt1, dt2); |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | #[test ] |
| 190 | fn test_addition_across_dst_boundary() { |
| 191 | use chrono::TimeZone; |
| 192 | let two_hours = Duration::hours(2); |
| 193 | let edt = Eastern.with_ymd_and_hms(2019, 11, 3, 0, 0, 0).unwrap(); |
| 194 | let est = edt + two_hours; |
| 195 | |
| 196 | assert_eq!(edt.to_string(), "2019-11-03 00:00:00 EDT" .to_string()); |
| 197 | assert_eq!(est.to_string(), "2019-11-03 01:00:00 EST" .to_string()); |
| 198 | assert_eq!(est.timestamp(), edt.timestamp() + two_hours.num_seconds()); |
| 199 | } |
| 200 | |
| 201 | #[test ] |
| 202 | fn warsaw_tz_name() { |
| 203 | let dt = UTC.with_ymd_and_hms(1915, 8, 4, 22, 35, 59).unwrap(); |
| 204 | assert_eq!(dt.with_timezone(&Warsaw).format("%Z" ).to_string(), "WMT" ); |
| 205 | let dt = dt + Duration::seconds(1); |
| 206 | assert_eq!(dt.with_timezone(&Warsaw).format("%Z" ).to_string(), "CET" ); |
| 207 | } |
| 208 | |
| 209 | #[test ] |
| 210 | fn vilnius_utc_offset() { |
| 211 | let dt = UTC |
| 212 | .with_ymd_and_hms(1916, 12, 31, 22, 35, 59) |
| 213 | .unwrap() |
| 214 | .with_timezone(&Vilnius); |
| 215 | assert_eq!( |
| 216 | dt, |
| 217 | Vilnius.with_ymd_and_hms(1916, 12, 31, 23, 59, 59).unwrap() |
| 218 | ); |
| 219 | let dt = dt + Duration::seconds(1); |
| 220 | assert_eq!(dt, Vilnius.with_ymd_and_hms(1917, 1, 1, 0, 11, 36).unwrap()); |
| 221 | } |
| 222 | |
| 223 | #[test ] |
| 224 | fn victorian_times() { |
| 225 | let dt = UTC |
| 226 | .with_ymd_and_hms(1847, 12, 1, 0, 1, 14) |
| 227 | .unwrap() |
| 228 | .with_timezone(&London); |
| 229 | assert_eq!( |
| 230 | dt, |
| 231 | London.with_ymd_and_hms(1847, 11, 30, 23, 59, 59).unwrap() |
| 232 | ); |
| 233 | let dt = dt + Duration::seconds(1); |
| 234 | assert_eq!(dt, London.with_ymd_and_hms(1847, 12, 1, 0, 1, 15).unwrap()); |
| 235 | } |
| 236 | |
| 237 | #[test ] |
| 238 | fn london_dst() { |
| 239 | let dt = London.with_ymd_and_hms(2016, 3, 10, 5, 0, 0).unwrap(); |
| 240 | let later = dt + Duration::days(180); |
| 241 | let expected = London.with_ymd_and_hms(2016, 9, 6, 6, 0, 0).unwrap(); |
| 242 | assert_eq!(later, expected); |
| 243 | } |
| 244 | |
| 245 | #[test ] |
| 246 | fn international_date_line_change() { |
| 247 | let dt = UTC |
| 248 | .with_ymd_and_hms(2011, 12, 30, 9, 59, 59) |
| 249 | .unwrap() |
| 250 | .with_timezone(&Apia); |
| 251 | assert_eq!(dt, Apia.with_ymd_and_hms(2011, 12, 29, 23, 59, 59).unwrap()); |
| 252 | let dt = dt + Duration::seconds(1); |
| 253 | assert_eq!(dt, Apia.with_ymd_and_hms(2011, 12, 31, 0, 0, 0).unwrap()); |
| 254 | } |
| 255 | |
| 256 | #[test ] |
| 257 | fn negative_offset_with_minutes_and_seconds() { |
| 258 | let dt = UTC |
| 259 | .with_ymd_and_hms(1900, 1, 1, 12, 0, 0) |
| 260 | .unwrap() |
| 261 | .with_timezone(&Danmarkshavn); |
| 262 | assert_eq!( |
| 263 | dt, |
| 264 | Danmarkshavn |
| 265 | .with_ymd_and_hms(1900, 1, 1, 10, 45, 20) |
| 266 | .unwrap() |
| 267 | ); |
| 268 | } |
| 269 | |
| 270 | #[test ] |
| 271 | fn monotonicity() { |
| 272 | let mut dt = Noumea.with_ymd_and_hms(1800, 1, 1, 12, 0, 0).unwrap(); |
| 273 | for _ in 0..24 * 356 * 400 { |
| 274 | let new = dt + Duration::hours(1); |
| 275 | assert!(new > dt); |
| 276 | assert!(new.with_timezone(&UTC) > dt.with_timezone(&UTC)); |
| 277 | dt = new; |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | fn test_inverse<T: TimeZone>(tz: T, begin: i32, end: i32) { |
| 282 | for y in begin..end { |
| 283 | for d in 1..366 { |
| 284 | let date = NaiveDate::from_yo_opt(y, d).unwrap(); |
| 285 | for h in 0..24 { |
| 286 | for m in 0..60 { |
| 287 | let dt = date.and_hms_opt(h, m, 0).unwrap().and_utc(); |
| 288 | let with_tz = dt.with_timezone(&tz); |
| 289 | let utc = with_tz.with_timezone(&UTC); |
| 290 | assert_eq!(dt, utc); |
| 291 | } |
| 292 | } |
| 293 | } |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | #[test ] |
| 298 | fn inverse_london() { |
| 299 | test_inverse(London, 1989, 1994); |
| 300 | } |
| 301 | |
| 302 | #[test ] |
| 303 | fn inverse_dhaka() { |
| 304 | test_inverse(Dhaka, 1995, 2000); |
| 305 | } |
| 306 | |
| 307 | #[test ] |
| 308 | fn inverse_apia() { |
| 309 | test_inverse(Apia, 2011, 2012); |
| 310 | } |
| 311 | |
| 312 | #[test ] |
| 313 | fn inverse_tahiti() { |
| 314 | test_inverse(Tahiti, 1911, 1914); |
| 315 | } |
| 316 | |
| 317 | #[test ] |
| 318 | fn string_representation() { |
| 319 | let dt = UTC |
| 320 | .with_ymd_and_hms(2000, 9, 1, 12, 30, 15) |
| 321 | .unwrap() |
| 322 | .with_timezone(&Adelaide); |
| 323 | assert_eq!(dt.to_string(), "2000-09-01 22:00:15 ACST" ); |
| 324 | assert_eq!(format!("{:?}" , dt), "2000-09-01T22:00:15ACST" ); |
| 325 | assert_eq!(dt.to_rfc3339(), "2000-09-01T22:00:15+09:30" ); |
| 326 | assert_eq!(format!("{}" , dt), "2000-09-01 22:00:15 ACST" ); |
| 327 | } |
| 328 | |
| 329 | #[test ] |
| 330 | fn tahiti() { |
| 331 | let dt = UTC |
| 332 | .with_ymd_and_hms(1912, 10, 1, 9, 58, 16) |
| 333 | .unwrap() |
| 334 | .with_timezone(&Tahiti); |
| 335 | let before = dt - Duration::hours(1); |
| 336 | assert_eq!( |
| 337 | before, |
| 338 | Tahiti.with_ymd_and_hms(1912, 9, 30, 23, 0, 0).unwrap() |
| 339 | ); |
| 340 | let after = dt + Duration::hours(1); |
| 341 | assert_eq!( |
| 342 | after, |
| 343 | Tahiti.with_ymd_and_hms(1912, 10, 1, 0, 58, 16).unwrap() |
| 344 | ); |
| 345 | } |
| 346 | |
| 347 | #[test ] |
| 348 | fn nonexistent_time() { |
| 349 | assert!(London |
| 350 | .with_ymd_and_hms(2016, 3, 27, 1, 30, 0) |
| 351 | .single() |
| 352 | .is_none()); |
| 353 | } |
| 354 | |
| 355 | #[test ] |
| 356 | fn nonexistent_time_2() { |
| 357 | assert!(London |
| 358 | .with_ymd_and_hms(2016, 3, 27, 1, 0, 0) |
| 359 | .single() |
| 360 | .is_none()); |
| 361 | } |
| 362 | |
| 363 | #[test ] |
| 364 | fn time_exists() { |
| 365 | assert!(London |
| 366 | .with_ymd_and_hms(2016, 3, 27, 2, 0, 0) |
| 367 | .single() |
| 368 | .is_some()); |
| 369 | } |
| 370 | |
| 371 | #[test ] |
| 372 | fn ambiguous_time() { |
| 373 | let ambiguous = London.with_ymd_and_hms(2016, 10, 30, 1, 0, 0); |
| 374 | let earliest_utc = NaiveDate::from_ymd_opt(2016, 10, 30) |
| 375 | .unwrap() |
| 376 | .and_hms_opt(0, 0, 0) |
| 377 | .unwrap(); |
| 378 | assert_eq!( |
| 379 | ambiguous.earliest().unwrap(), |
| 380 | London.from_utc_datetime(&earliest_utc) |
| 381 | ); |
| 382 | let latest_utc = NaiveDate::from_ymd_opt(2016, 10, 30) |
| 383 | .unwrap() |
| 384 | .and_hms_opt(1, 0, 0) |
| 385 | .unwrap(); |
| 386 | assert_eq!( |
| 387 | ambiguous.latest().unwrap(), |
| 388 | London.from_utc_datetime(&latest_utc) |
| 389 | ); |
| 390 | } |
| 391 | |
| 392 | #[test ] |
| 393 | fn ambiguous_time_2() { |
| 394 | let ambiguous = London.with_ymd_and_hms(2016, 10, 30, 1, 30, 0); |
| 395 | let earliest_utc = NaiveDate::from_ymd_opt(2016, 10, 30) |
| 396 | .unwrap() |
| 397 | .and_hms_opt(0, 30, 0) |
| 398 | .unwrap(); |
| 399 | assert_eq!( |
| 400 | ambiguous.earliest().unwrap(), |
| 401 | London.from_utc_datetime(&earliest_utc) |
| 402 | ); |
| 403 | let latest_utc = NaiveDate::from_ymd_opt(2016, 10, 30) |
| 404 | .unwrap() |
| 405 | .and_hms_opt(1, 30, 0) |
| 406 | .unwrap(); |
| 407 | assert_eq!( |
| 408 | ambiguous.latest().unwrap(), |
| 409 | London.from_utc_datetime(&latest_utc) |
| 410 | ); |
| 411 | } |
| 412 | |
| 413 | #[test ] |
| 414 | fn ambiguous_time_3() { |
| 415 | let ambiguous = Moscow.with_ymd_and_hms(2014, 10, 26, 1, 30, 0); |
| 416 | let earliest_utc = NaiveDate::from_ymd_opt(2014, 10, 25) |
| 417 | .unwrap() |
| 418 | .and_hms_opt(21, 30, 0) |
| 419 | .unwrap(); |
| 420 | assert_eq!( |
| 421 | ambiguous.earliest().unwrap().fixed_offset(), |
| 422 | Moscow.from_utc_datetime(&earliest_utc).fixed_offset() |
| 423 | ); |
| 424 | let latest_utc = NaiveDate::from_ymd_opt(2014, 10, 25) |
| 425 | .unwrap() |
| 426 | .and_hms_opt(22, 30, 0) |
| 427 | .unwrap(); |
| 428 | assert_eq!( |
| 429 | ambiguous.latest().unwrap(), |
| 430 | Moscow.from_utc_datetime(&latest_utc) |
| 431 | ); |
| 432 | } |
| 433 | |
| 434 | #[test ] |
| 435 | fn ambiguous_time_4() { |
| 436 | let ambiguous = Moscow.with_ymd_and_hms(2014, 10, 26, 1, 0, 0); |
| 437 | let earliest_utc = NaiveDate::from_ymd_opt(2014, 10, 25) |
| 438 | .unwrap() |
| 439 | .and_hms_opt(21, 0, 0) |
| 440 | .unwrap(); |
| 441 | assert_eq!( |
| 442 | ambiguous.earliest().unwrap().fixed_offset(), |
| 443 | Moscow.from_utc_datetime(&earliest_utc).fixed_offset() |
| 444 | ); |
| 445 | let latest_utc = NaiveDate::from_ymd_opt(2014, 10, 25) |
| 446 | .unwrap() |
| 447 | .and_hms_opt(22, 0, 0) |
| 448 | .unwrap(); |
| 449 | assert_eq!( |
| 450 | ambiguous.latest().unwrap(), |
| 451 | Moscow.from_utc_datetime(&latest_utc) |
| 452 | ); |
| 453 | } |
| 454 | |
| 455 | #[test ] |
| 456 | fn unambiguous_time() { |
| 457 | assert!(London |
| 458 | .with_ymd_and_hms(2016, 10, 30, 2, 0, 0) |
| 459 | .single() |
| 460 | .is_some()); |
| 461 | } |
| 462 | |
| 463 | #[test ] |
| 464 | fn unambiguous_time_2() { |
| 465 | assert!(Moscow |
| 466 | .with_ymd_and_hms(2014, 10, 26, 2, 0, 0) |
| 467 | .single() |
| 468 | .is_some()); |
| 469 | } |
| 470 | |
| 471 | #[test ] |
| 472 | fn test_get_name() { |
| 473 | assert_eq!(London.name(), "Europe/London" ); |
| 474 | assert_eq!(Tz::Africa__Abidjan.name(), "Africa/Abidjan" ); |
| 475 | assert_eq!(Tz::UTC.name(), "UTC" ); |
| 476 | assert_eq!(Tz::Zulu.name(), "Zulu" ); |
| 477 | } |
| 478 | |
| 479 | #[test ] |
| 480 | fn test_display() { |
| 481 | assert_eq!(format!("{}" , London), "Europe/London" ); |
| 482 | assert_eq!(format!("{}" , Tz::Africa__Abidjan), "Africa/Abidjan" ); |
| 483 | assert_eq!(format!("{}" , Tz::UTC), "UTC" ); |
| 484 | assert_eq!(format!("{}" , Tz::Zulu), "Zulu" ); |
| 485 | } |
| 486 | |
| 487 | #[test ] |
| 488 | fn test_impl_hash() { |
| 489 | #[allow (dead_code)] |
| 490 | #[derive (Hash)] |
| 491 | struct Foo(Tz); |
| 492 | } |
| 493 | |
| 494 | #[test ] |
| 495 | fn test_iana_tzdb_version() { |
| 496 | // Format should be something like 2023c. |
| 497 | assert_eq!(5, IANA_TZDB_VERSION.len()); |
| 498 | let numbers: Vec<&str> = IANA_TZDB_VERSION.matches(char::is_numeric).collect(); |
| 499 | assert_eq!(4, numbers.len()); |
| 500 | assert!(IANA_TZDB_VERSION.ends_with(|c: char| c.is_ascii_lowercase())); |
| 501 | } |
| 502 | |
| 503 | #[test ] |
| 504 | fn test_numeric_names() { |
| 505 | let dt = Scoresbysund |
| 506 | .with_ymd_and_hms(2024, 05, 01, 0, 0, 0) |
| 507 | .unwrap(); |
| 508 | assert_eq!(format!("{}" , dt.offset()), "-01" ); |
| 509 | assert_eq!(format!("{:?}" , dt.offset()), "-01" ); |
| 510 | let dt = Casey.with_ymd_and_hms(2022, 11, 01, 0, 0, 0).unwrap(); |
| 511 | assert_eq!(format!("{}" , dt.offset()), "+11" ); |
| 512 | assert_eq!(format!("{:?}" , dt.offset()), "+11" ); |
| 513 | let dt = Addis_Ababa.with_ymd_and_hms(1937, 02, 01, 0, 0, 0).unwrap(); |
| 514 | assert_eq!(format!("{}" , dt.offset()), "+0245" ); |
| 515 | assert_eq!(format!("{:?}" , dt.offset()), "+0245" ); |
| 516 | } |
| 517 | } |
| 518 | |