1 // This is a part of Chrono. 2 // See README.md and LICENSE.txt for details. 3 4 //! The time zone, which calculates offsets from the local time to UTC. 5 //! 6 //! There are four operations provided by the `TimeZone` trait: 7 //! 8 //! 1. Converting the local `NaiveDateTime` to `DateTime<Tz>` 9 //! 2. Converting the UTC `NaiveDateTime` to `DateTime<Tz>` 10 //! 3. Converting `DateTime<Tz>` to the local `NaiveDateTime` 11 //! 4. Constructing `DateTime<Tz>` objects from various offsets 12 //! 13 //! 1 is used for constructors. 2 is used for the `with_timezone` method of date and time types. 14 //! 3 is used for other methods, e.g. `year()` or `format()`, and provided by an associated type 15 //! which implements `Offset` (which then passed to `TimeZone` for actual implementations). 16 //! Technically speaking `TimeZone` has a total knowledge about given timescale, 17 //! but `Offset` is used as a cache to avoid the repeated conversion 18 //! and provides implementations for 1 and 3. 19 //! An `TimeZone` instance can be reconstructed from the corresponding `Offset` instance. 20 21 use core::fmt; 22 23 use format::{parse, ParseResult, Parsed, StrftimeItems}; 24 use naive::{NaiveDate, NaiveDateTime, NaiveTime}; 25 use Weekday; 26 use {Date, DateTime}; 27 28 /// The conversion result from the local time to the timezone-aware datetime types. 29 #[derive(Clone, PartialEq, Debug, Copy, Eq, Hash)] 30 pub enum LocalResult<T> { 31 /// Given local time representation is invalid. 32 /// This can occur when, for example, the positive timezone transition. 33 None, 34 /// Given local time representation has a single unique result. 35 Single(T), 36 /// Given local time representation has multiple results and thus ambiguous. 37 /// This can occur when, for example, the negative timezone transition. 38 Ambiguous(T /*min*/, T /*max*/), 39 } 40 41 impl<T> LocalResult<T> { 42 /// Returns `Some` only when the conversion result is unique, or `None` otherwise. single(self) -> Option<T>43 pub fn single(self) -> Option<T> { 44 match self { 45 LocalResult::Single(t) => Some(t), 46 _ => None, 47 } 48 } 49 50 /// Returns `Some` for the earliest possible conversion result, or `None` if none. earliest(self) -> Option<T>51 pub fn earliest(self) -> Option<T> { 52 match self { 53 LocalResult::Single(t) | LocalResult::Ambiguous(t, _) => Some(t), 54 _ => None, 55 } 56 } 57 58 /// Returns `Some` for the latest possible conversion result, or `None` if none. latest(self) -> Option<T>59 pub fn latest(self) -> Option<T> { 60 match self { 61 LocalResult::Single(t) | LocalResult::Ambiguous(_, t) => Some(t), 62 _ => None, 63 } 64 } 65 66 /// Maps a `LocalResult<T>` into `LocalResult<U>` with given function. map<U, F: FnMut(T) -> U>(self, mut f: F) -> LocalResult<U>67 pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> LocalResult<U> { 68 match self { 69 LocalResult::None => LocalResult::None, 70 LocalResult::Single(v) => LocalResult::Single(f(v)), 71 LocalResult::Ambiguous(min, max) => LocalResult::Ambiguous(f(min), f(max)), 72 } 73 } 74 } 75 76 impl<Tz: TimeZone> LocalResult<Date<Tz>> { 77 /// Makes a new `DateTime` from the current date and given `NaiveTime`. 78 /// The offset in the current date is preserved. 79 /// 80 /// Propagates any error. Ambiguous result would be discarded. 81 #[inline] and_time(self, time: NaiveTime) -> LocalResult<DateTime<Tz>>82 pub fn and_time(self, time: NaiveTime) -> LocalResult<DateTime<Tz>> { 83 match self { 84 LocalResult::Single(d) => { 85 d.and_time(time).map_or(LocalResult::None, LocalResult::Single) 86 } 87 _ => LocalResult::None, 88 } 89 } 90 91 /// Makes a new `DateTime` from the current date, hour, minute and second. 92 /// The offset in the current date is preserved. 93 /// 94 /// Propagates any error. Ambiguous result would be discarded. 95 #[inline] and_hms_opt(self, hour: u32, min: u32, sec: u32) -> LocalResult<DateTime<Tz>>96 pub fn and_hms_opt(self, hour: u32, min: u32, sec: u32) -> LocalResult<DateTime<Tz>> { 97 match self { 98 LocalResult::Single(d) => { 99 d.and_hms_opt(hour, min, sec).map_or(LocalResult::None, LocalResult::Single) 100 } 101 _ => LocalResult::None, 102 } 103 } 104 105 /// Makes a new `DateTime` from the current date, hour, minute, second and millisecond. 106 /// The millisecond part can exceed 1,000 in order to represent the leap second. 107 /// The offset in the current date is preserved. 108 /// 109 /// Propagates any error. Ambiguous result would be discarded. 110 #[inline] and_hms_milli_opt( self, hour: u32, min: u32, sec: u32, milli: u32, ) -> LocalResult<DateTime<Tz>>111 pub fn and_hms_milli_opt( 112 self, 113 hour: u32, 114 min: u32, 115 sec: u32, 116 milli: u32, 117 ) -> LocalResult<DateTime<Tz>> { 118 match self { 119 LocalResult::Single(d) => d 120 .and_hms_milli_opt(hour, min, sec, milli) 121 .map_or(LocalResult::None, LocalResult::Single), 122 _ => LocalResult::None, 123 } 124 } 125 126 /// Makes a new `DateTime` from the current date, hour, minute, second and microsecond. 127 /// The microsecond part can exceed 1,000,000 in order to represent the leap second. 128 /// The offset in the current date is preserved. 129 /// 130 /// Propagates any error. Ambiguous result would be discarded. 131 #[inline] and_hms_micro_opt( self, hour: u32, min: u32, sec: u32, micro: u32, ) -> LocalResult<DateTime<Tz>>132 pub fn and_hms_micro_opt( 133 self, 134 hour: u32, 135 min: u32, 136 sec: u32, 137 micro: u32, 138 ) -> LocalResult<DateTime<Tz>> { 139 match self { 140 LocalResult::Single(d) => d 141 .and_hms_micro_opt(hour, min, sec, micro) 142 .map_or(LocalResult::None, LocalResult::Single), 143 _ => LocalResult::None, 144 } 145 } 146 147 /// Makes a new `DateTime` from the current date, hour, minute, second and nanosecond. 148 /// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second. 149 /// The offset in the current date is preserved. 150 /// 151 /// Propagates any error. Ambiguous result would be discarded. 152 #[inline] and_hms_nano_opt( self, hour: u32, min: u32, sec: u32, nano: u32, ) -> LocalResult<DateTime<Tz>>153 pub fn and_hms_nano_opt( 154 self, 155 hour: u32, 156 min: u32, 157 sec: u32, 158 nano: u32, 159 ) -> LocalResult<DateTime<Tz>> { 160 match self { 161 LocalResult::Single(d) => d 162 .and_hms_nano_opt(hour, min, sec, nano) 163 .map_or(LocalResult::None, LocalResult::Single), 164 _ => LocalResult::None, 165 } 166 } 167 } 168 169 impl<T: fmt::Debug> LocalResult<T> { 170 /// Returns the single unique conversion result, or panics accordingly. unwrap(self) -> T171 pub fn unwrap(self) -> T { 172 match self { 173 LocalResult::None => panic!("No such local time"), 174 LocalResult::Single(t) => t, 175 LocalResult::Ambiguous(t1, t2) => { 176 panic!("Ambiguous local time, ranging from {:?} to {:?}", t1, t2) 177 } 178 } 179 } 180 } 181 182 /// The offset from the local time to UTC. 183 pub trait Offset: Sized + Clone + fmt::Debug { 184 /// Returns the fixed offset from UTC to the local time stored. fix(&self) -> FixedOffset185 fn fix(&self) -> FixedOffset; 186 } 187 188 /// The time zone. 189 /// 190 /// The methods here are the primarily constructors for [`Date`](../struct.Date.html) and 191 /// [`DateTime`](../struct.DateTime.html) types. 192 pub trait TimeZone: Sized + Clone { 193 /// An associated offset type. 194 /// This type is used to store the actual offset in date and time types. 195 /// The original `TimeZone` value can be recovered via `TimeZone::from_offset`. 196 type Offset: Offset; 197 198 /// Makes a new `Date` from year, month, day and the current time zone. 199 /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. 200 /// 201 /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), 202 /// but it will propagate to the `DateTime` values constructed via this date. 203 /// 204 /// Panics on the out-of-range date, invalid month and/or day. 205 /// 206 /// # Example 207 /// 208 /// ~~~~ 209 /// use chrono::{Utc, TimeZone}; 210 /// 211 /// assert_eq!(Utc.ymd(2015, 5, 15).to_string(), "2015-05-15UTC"); 212 /// ~~~~ ymd(&self, year: i32, month: u32, day: u32) -> Date<Self>213 fn ymd(&self, year: i32, month: u32, day: u32) -> Date<Self> { 214 self.ymd_opt(year, month, day).unwrap() 215 } 216 217 /// Makes a new `Date` from year, month, day and the current time zone. 218 /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. 219 /// 220 /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), 221 /// but it will propagate to the `DateTime` values constructed via this date. 222 /// 223 /// Returns `None` on the out-of-range date, invalid month and/or day. 224 /// 225 /// # Example 226 /// 227 /// ~~~~ 228 /// use chrono::{Utc, LocalResult, TimeZone}; 229 /// 230 /// assert_eq!(Utc.ymd_opt(2015, 5, 15).unwrap().to_string(), "2015-05-15UTC"); 231 /// assert_eq!(Utc.ymd_opt(2000, 0, 0), LocalResult::None); 232 /// ~~~~ ymd_opt(&self, year: i32, month: u32, day: u32) -> LocalResult<Date<Self>>233 fn ymd_opt(&self, year: i32, month: u32, day: u32) -> LocalResult<Date<Self>> { 234 match NaiveDate::from_ymd_opt(year, month, day) { 235 Some(d) => self.from_local_date(&d), 236 None => LocalResult::None, 237 } 238 } 239 240 /// Makes a new `Date` from year, day of year (DOY or "ordinal") and the current time zone. 241 /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. 242 /// 243 /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), 244 /// but it will propagate to the `DateTime` values constructed via this date. 245 /// 246 /// Panics on the out-of-range date and/or invalid DOY. 247 /// 248 /// # Example 249 /// 250 /// ~~~~ 251 /// use chrono::{Utc, TimeZone}; 252 /// 253 /// assert_eq!(Utc.yo(2015, 135).to_string(), "2015-05-15UTC"); 254 /// ~~~~ yo(&self, year: i32, ordinal: u32) -> Date<Self>255 fn yo(&self, year: i32, ordinal: u32) -> Date<Self> { 256 self.yo_opt(year, ordinal).unwrap() 257 } 258 259 /// Makes a new `Date` from year, day of year (DOY or "ordinal") and the current time zone. 260 /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. 261 /// 262 /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), 263 /// but it will propagate to the `DateTime` values constructed via this date. 264 /// 265 /// Returns `None` on the out-of-range date and/or invalid DOY. yo_opt(&self, year: i32, ordinal: u32) -> LocalResult<Date<Self>>266 fn yo_opt(&self, year: i32, ordinal: u32) -> LocalResult<Date<Self>> { 267 match NaiveDate::from_yo_opt(year, ordinal) { 268 Some(d) => self.from_local_date(&d), 269 None => LocalResult::None, 270 } 271 } 272 273 /// Makes a new `Date` from ISO week date (year and week number), day of the week (DOW) and 274 /// the current time zone. 275 /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. 276 /// The resulting `Date` may have a different year from the input year. 277 /// 278 /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), 279 /// but it will propagate to the `DateTime` values constructed via this date. 280 /// 281 /// Panics on the out-of-range date and/or invalid week number. 282 /// 283 /// # Example 284 /// 285 /// ~~~~ 286 /// use chrono::{Utc, Weekday, TimeZone}; 287 /// 288 /// assert_eq!(Utc.isoywd(2015, 20, Weekday::Fri).to_string(), "2015-05-15UTC"); 289 /// ~~~~ isoywd(&self, year: i32, week: u32, weekday: Weekday) -> Date<Self>290 fn isoywd(&self, year: i32, week: u32, weekday: Weekday) -> Date<Self> { 291 self.isoywd_opt(year, week, weekday).unwrap() 292 } 293 294 /// Makes a new `Date` from ISO week date (year and week number), day of the week (DOW) and 295 /// the current time zone. 296 /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. 297 /// The resulting `Date` may have a different year from the input year. 298 /// 299 /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), 300 /// but it will propagate to the `DateTime` values constructed via this date. 301 /// 302 /// Returns `None` on the out-of-range date and/or invalid week number. isoywd_opt(&self, year: i32, week: u32, weekday: Weekday) -> LocalResult<Date<Self>>303 fn isoywd_opt(&self, year: i32, week: u32, weekday: Weekday) -> LocalResult<Date<Self>> { 304 match NaiveDate::from_isoywd_opt(year, week, weekday) { 305 Some(d) => self.from_local_date(&d), 306 None => LocalResult::None, 307 } 308 } 309 310 /// Makes a new `DateTime` from the number of non-leap seconds 311 /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp") 312 /// and the number of nanoseconds since the last whole non-leap second. 313 /// 314 /// Panics on the out-of-range number of seconds and/or invalid nanosecond, 315 /// for a non-panicking version see [`timestamp_opt`](#method.timestamp_opt). 316 /// 317 /// # Example 318 /// 319 /// ~~~~ 320 /// use chrono::{Utc, TimeZone}; 321 /// 322 /// assert_eq!(Utc.timestamp(1431648000, 0).to_string(), "2015-05-15 00:00:00 UTC"); 323 /// ~~~~ timestamp(&self, secs: i64, nsecs: u32) -> DateTime<Self>324 fn timestamp(&self, secs: i64, nsecs: u32) -> DateTime<Self> { 325 self.timestamp_opt(secs, nsecs).unwrap() 326 } 327 328 /// Makes a new `DateTime` from the number of non-leap seconds 329 /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp") 330 /// and the number of nanoseconds since the last whole non-leap second. 331 /// 332 /// Returns `LocalResult::None` on out-of-range number of seconds and/or 333 /// invalid nanosecond, otherwise always returns `LocalResult::Single`. timestamp_opt(&self, secs: i64, nsecs: u32) -> LocalResult<DateTime<Self>>334 fn timestamp_opt(&self, secs: i64, nsecs: u32) -> LocalResult<DateTime<Self>> { 335 match NaiveDateTime::from_timestamp_opt(secs, nsecs) { 336 Some(dt) => LocalResult::Single(self.from_utc_datetime(&dt)), 337 None => LocalResult::None, 338 } 339 } 340 341 /// Makes a new `DateTime` from the number of non-leap milliseconds 342 /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). 343 /// 344 /// Panics on out-of-range number of milliseconds for a non-panicking 345 /// version see [`timestamp_millis_opt`](#method.timestamp_millis_opt). 346 /// 347 /// # Example 348 /// 349 /// ~~~~ 350 /// use chrono::{Utc, TimeZone}; 351 /// 352 /// assert_eq!(Utc.timestamp_millis(1431648000).timestamp(), 1431648); 353 /// ~~~~ timestamp_millis(&self, millis: i64) -> DateTime<Self>354 fn timestamp_millis(&self, millis: i64) -> DateTime<Self> { 355 self.timestamp_millis_opt(millis).unwrap() 356 } 357 358 /// Makes a new `DateTime` from the number of non-leap milliseconds 359 /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). 360 /// 361 /// 362 /// Returns `LocalResult::None` on out-of-range number of milliseconds 363 /// and/or invalid nanosecond, otherwise always returns 364 /// `LocalResult::Single`. 365 /// 366 /// # Example 367 /// 368 /// ~~~~ 369 /// use chrono::{Utc, TimeZone, LocalResult}; 370 /// match Utc.timestamp_millis_opt(1431648000) { 371 /// LocalResult::Single(dt) => assert_eq!(dt.timestamp(), 1431648), 372 /// _ => panic!("Incorrect timestamp_millis"), 373 /// }; 374 /// ~~~~ timestamp_millis_opt(&self, millis: i64) -> LocalResult<DateTime<Self>>375 fn timestamp_millis_opt(&self, millis: i64) -> LocalResult<DateTime<Self>> { 376 let (mut secs, mut millis) = (millis / 1000, millis % 1000); 377 if millis < 0 { 378 secs -= 1; 379 millis += 1000; 380 } 381 self.timestamp_opt(secs, millis as u32 * 1_000_000) 382 } 383 384 /// Makes a new `DateTime` from the number of non-leap nanoseconds 385 /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). 386 /// 387 /// Unlike [`timestamp_millis`](#method.timestamp_millis), this never 388 /// panics. 389 /// 390 /// # Example 391 /// 392 /// ~~~~ 393 /// use chrono::{Utc, TimeZone}; 394 /// 395 /// assert_eq!(Utc.timestamp_nanos(1431648000000000).timestamp(), 1431648); 396 /// ~~~~ timestamp_nanos(&self, nanos: i64) -> DateTime<Self>397 fn timestamp_nanos(&self, nanos: i64) -> DateTime<Self> { 398 let (mut secs, mut nanos) = (nanos / 1_000_000_000, nanos % 1_000_000_000); 399 if nanos < 0 { 400 secs -= 1; 401 nanos += 1_000_000_000; 402 } 403 self.timestamp_opt(secs, nanos as u32).unwrap() 404 } 405 406 /// Parses a string with the specified format string and 407 /// returns a `DateTime` with the current offset. 408 /// See the [`format::strftime` module](../format/strftime/index.html) 409 /// on the supported escape sequences. 410 /// 411 /// If the format does not include offsets, the current offset is assumed; 412 /// otherwise the input should have a matching UTC offset. 413 /// 414 /// See also `DateTime::parse_from_str` which gives a local `DateTime` 415 /// with parsed `FixedOffset`. datetime_from_str(&self, s: &str, fmt: &str) -> ParseResult<DateTime<Self>>416 fn datetime_from_str(&self, s: &str, fmt: &str) -> ParseResult<DateTime<Self>> { 417 let mut parsed = Parsed::new(); 418 parse(&mut parsed, s, StrftimeItems::new(fmt))?; 419 parsed.to_datetime_with_timezone(self) 420 } 421 422 /// Reconstructs the time zone from the offset. from_offset(offset: &Self::Offset) -> Self423 fn from_offset(offset: &Self::Offset) -> Self; 424 425 /// Creates the offset(s) for given local `NaiveDate` if possible. offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<Self::Offset>426 fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<Self::Offset>; 427 428 /// Creates the offset(s) for given local `NaiveDateTime` if possible. offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<Self::Offset>429 fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<Self::Offset>; 430 431 /// Converts the local `NaiveDate` to the timezone-aware `Date` if possible. from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Self>>432 fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Self>> { 433 self.offset_from_local_date(local).map(|offset| { 434 // since FixedOffset is within +/- 1 day, the date is never affected 435 Date::from_utc(*local, offset) 436 }) 437 } 438 439 /// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible. from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Self>>440 fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Self>> { 441 self.offset_from_local_datetime(local) 442 .map(|offset| DateTime::from_utc(*local - offset.fix(), offset)) 443 } 444 445 /// Creates the offset for given UTC `NaiveDate`. This cannot fail. offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset446 fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset; 447 448 /// Creates the offset for given UTC `NaiveDateTime`. This cannot fail. offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset449 fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset; 450 451 /// Converts the UTC `NaiveDate` to the local time. 452 /// The UTC is continuous and thus this cannot fail (but can give the duplicate local time). from_utc_date(&self, utc: &NaiveDate) -> Date<Self>453 fn from_utc_date(&self, utc: &NaiveDate) -> Date<Self> { 454 Date::from_utc(*utc, self.offset_from_utc_date(utc)) 455 } 456 457 /// Converts the UTC `NaiveDateTime` to the local time. 458 /// The UTC is continuous and thus this cannot fail (but can give the duplicate local time). from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Self>459 fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime<Self> { 460 DateTime::from_utc(*utc, self.offset_from_utc_datetime(utc)) 461 } 462 } 463 464 mod fixed; 465 #[cfg(feature = "clock")] 466 mod local; 467 mod utc; 468 469 pub use self::fixed::FixedOffset; 470 #[cfg(feature = "clock")] 471 pub use self::local::Local; 472 pub use self::utc::Utc; 473 474 #[cfg(test)] 475 mod tests { 476 use super::*; 477 478 #[test] test_negative_millis()479 fn test_negative_millis() { 480 let dt = Utc.timestamp_millis(-1000); 481 assert_eq!(dt.to_string(), "1969-12-31 23:59:59 UTC"); 482 let dt = Utc.timestamp_millis(-7000); 483 assert_eq!(dt.to_string(), "1969-12-31 23:59:53 UTC"); 484 let dt = Utc.timestamp_millis(-7001); 485 assert_eq!(dt.to_string(), "1969-12-31 23:59:52.999 UTC"); 486 let dt = Utc.timestamp_millis(-7003); 487 assert_eq!(dt.to_string(), "1969-12-31 23:59:52.997 UTC"); 488 let dt = Utc.timestamp_millis(-999); 489 assert_eq!(dt.to_string(), "1969-12-31 23:59:59.001 UTC"); 490 let dt = Utc.timestamp_millis(-1); 491 assert_eq!(dt.to_string(), "1969-12-31 23:59:59.999 UTC"); 492 let dt = Utc.timestamp_millis(-60000); 493 assert_eq!(dt.to_string(), "1969-12-31 23:59:00 UTC"); 494 let dt = Utc.timestamp_millis(-3600000); 495 assert_eq!(dt.to_string(), "1969-12-31 23:00:00 UTC"); 496 497 for (millis, expected) in &[ 498 (-7000, "1969-12-31 23:59:53 UTC"), 499 (-7001, "1969-12-31 23:59:52.999 UTC"), 500 (-7003, "1969-12-31 23:59:52.997 UTC"), 501 ] { 502 match Utc.timestamp_millis_opt(*millis) { 503 LocalResult::Single(dt) => { 504 assert_eq!(dt.to_string(), *expected); 505 } 506 e => panic!("Got {:?} instead of an okay answer", e), 507 } 508 } 509 } 510 511 #[test] test_negative_nanos()512 fn test_negative_nanos() { 513 let dt = Utc.timestamp_nanos(-1_000_000_000); 514 assert_eq!(dt.to_string(), "1969-12-31 23:59:59 UTC"); 515 let dt = Utc.timestamp_nanos(-999_999_999); 516 assert_eq!(dt.to_string(), "1969-12-31 23:59:59.000000001 UTC"); 517 let dt = Utc.timestamp_nanos(-1); 518 assert_eq!(dt.to_string(), "1969-12-31 23:59:59.999999999 UTC"); 519 let dt = Utc.timestamp_nanos(-60_000_000_000); 520 assert_eq!(dt.to_string(), "1969-12-31 23:59:00 UTC"); 521 let dt = Utc.timestamp_nanos(-3_600_000_000_000); 522 assert_eq!(dt.to_string(), "1969-12-31 23:00:00 UTC"); 523 } 524 525 #[test] test_nanos_never_panics()526 fn test_nanos_never_panics() { 527 Utc.timestamp_nanos(i64::max_value()); 528 Utc.timestamp_nanos(i64::default()); 529 Utc.timestamp_nanos(i64::min_value()); 530 } 531 } 532