1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Simple time handling.
15 //! This crate is [on crates.io](https://crates.io/crates/time) and can be
16 //! used by adding `time` to the dependencies in your project's `Cargo.toml`.
23 //! And this in your crate root:
26 //! extern crate time;
29 //! This crate uses the same syntax for format strings as the
30 //! [`strftime()`](http://man7.org/linux/man-pages/man3/strftime.3.html)
31 //! function from the C standard library.
33 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
34 html_favicon_url
= "https://www.rust-lang.org/favicon.ico",
35 html_root_url
= "https://doc.rust-lang.org/time/")]
36 #![allow(unknown_lints)]
37 #![allow(ellipsis_inclusive_range_patterns)] // `..=` requires Rust 1.26
38 #![allow(trivial_numeric_casts)]
39 #![cfg_attr(test, deny(warnings))]
41 #[cfg(unix)] extern crate libc;
42 #[cfg(windows)] extern crate winapi;
43 #[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
45 #[cfg(target_os = "wasi")] extern crate wasi;
47 #[cfg(test)] #[macro_use] extern crate log;
49 use std
::cmp
::Ordering
;
50 use std
::error
::Error
;
52 use std
::ops
::{Add, Sub}
;
54 pub use duration
::{Duration, OutOfRangeError}
;
56 use self::ParseError
::{InvalidDay
, InvalidDayOfMonth
, InvalidDayOfWeek
,
57 InvalidDayOfYear
, InvalidFormatSpecifier
, InvalidHour
,
58 InvalidMinute
, InvalidMonth
, InvalidSecond
, InvalidTime
,
59 InvalidYear
, InvalidZoneOffset
, InvalidSecondsSinceEpoch
,
60 MissingFormatConverter
, UnexpectedCharacter
};
62 pub use parse
::strptime
;
69 static NSEC_PER_SEC
: i32 = 1_000_000_000;
71 /// A record specifying a time value in seconds and nanoseconds, where
72 /// nanoseconds represent the offset from the given second.
74 /// For example a timespec of 1.2 seconds after the beginning of the epoch would
75 /// be represented as {sec: 1, nsec: 200000000}.
76 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
77 #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
78 pub struct Timespec { pub sec: i64, pub nsec: i32 }
80 * Timespec assumes that pre-epoch Timespecs have negative sec and positive
81 * nsec fields. Darwin's and Linux's struct timespec functions handle pre-
82 * epoch timestamps using a "two steps back, one step forward" representation,
83 * though the man pages do not actually document this. For example, the time
84 * -1.2 seconds before the epoch is represented by `Timespec { sec: -2_i64,
85 * nsec: 800_000_000 }`.
88 pub fn new(sec
: i64, nsec
: i32) -> Timespec
{
89 assert
!(nsec
>= 0 && nsec
< NSEC_PER_SEC
);
90 Timespec { sec: sec, nsec: nsec }
94 impl Add
<Duration
> for Timespec
{
95 type Output
= Timespec
;
97 fn add(self, other
: Duration
) -> Timespec
{
98 let d_sec
= other
.num_seconds();
99 // It is safe to unwrap the nanoseconds, because there cannot be
100 // more than one second left, which fits in i64 and in i32.
101 let d_nsec
= (other
- Duration
::seconds(d_sec
))
102 .num_nanoseconds().unwrap() as i32;
103 let mut sec
= self.sec
+ d_sec
;
104 let mut nsec
= self.nsec
+ d_nsec
;
105 if nsec
>= NSEC_PER_SEC
{
106 nsec
-= NSEC_PER_SEC
;
109 nsec
+= NSEC_PER_SEC
;
112 Timespec
::new(sec
, nsec
)
116 impl Sub
<Duration
> for Timespec
{
117 type Output
= Timespec
;
119 fn sub(self, other
: Duration
) -> Timespec
{
120 let d_sec
= other
.num_seconds();
121 // It is safe to unwrap the nanoseconds, because there cannot be
122 // more than one second left, which fits in i64 and in i32.
123 let d_nsec
= (other
- Duration
::seconds(d_sec
))
124 .num_nanoseconds().unwrap() as i32;
125 let mut sec
= self.sec
- d_sec
;
126 let mut nsec
= self.nsec
- d_nsec
;
127 if nsec
>= NSEC_PER_SEC
{
128 nsec
-= NSEC_PER_SEC
;
131 nsec
+= NSEC_PER_SEC
;
134 Timespec
::new(sec
, nsec
)
138 impl Sub
<Timespec
> for Timespec
{
139 type Output
= Duration
;
141 fn sub(self, other
: Timespec
) -> Duration
{
142 let sec
= self.sec
- other
.sec
;
143 let nsec
= self.nsec
- other
.nsec
;
144 Duration
::seconds(sec
) + Duration
::nanoseconds(nsec
as i64)
149 * Returns the current time as a `timespec` containing the seconds and
150 * nanoseconds since 1970-01-01T00:00:00Z.
152 pub fn get_time() -> Timespec
{
153 let (sec
, nsec
) = sys
::get_time();
154 Timespec
::new(sec
, nsec
)
159 * Returns the current value of a high-resolution performance counter
160 * in nanoseconds since an unspecified epoch.
163 pub fn precise_time_ns() -> u64 {
164 sys
::get_precise_ns()
169 * Returns the current value of a high-resolution performance counter
170 * in seconds since an unspecified epoch.
172 pub fn precise_time_s() -> f64 {
173 return (precise_time_ns() as f64) / 1000000000.;
176 /// An opaque structure representing a moment in time.
178 /// The only operation that can be performed on a `PreciseTime` is the
179 /// calculation of the `Duration` of time that lies between them.
183 /// Repeatedly call a function for 1 second:
186 /// use time::{Duration, PreciseTime};
187 /// # fn do_some_work() {}
189 /// let start = PreciseTime::now();
191 /// while start.to(PreciseTime::now()) < Duration::seconds(1) {
195 #[derive(Copy, Clone)]
196 pub struct PreciseTime(u64);
199 /// Returns a `PreciseTime` representing the current moment in time.
200 pub fn now() -> PreciseTime
{
201 PreciseTime(precise_time_ns())
204 /// Returns a `Duration` representing the span of time from the value of
205 /// `self` to the value of `later`.
209 /// If `later` represents a time before `self`, the result of this method
212 /// If `later` represents a time more than 293 years after `self`, the
213 /// result of this method is unspecified.
215 pub fn to(&self, later
: PreciseTime
) -> Duration
{
216 // NB: even if later is less than self due to overflow, this will work
217 // since the subtraction will underflow properly as well.
219 // We could deal with the overflow when casting to an i64, but all that
220 // gets us is the ability to handle intervals of up to 584 years, which
221 // seems not very useful :)
222 Duration
::nanoseconds((later
.0 - self.0) as i64)
226 /// A structure representing a moment in time.
228 /// `SteadyTime`s are generated by a "steady" clock, that is, a clock which
229 /// never experiences discontinuous jumps and for which time always flows at
234 /// Repeatedly call a function for 1 second:
237 /// # use time::{Duration, SteadyTime};
238 /// # fn do_some_work() {}
239 /// let start = SteadyTime::now();
241 /// while SteadyTime::now() - start < Duration::seconds(1) {
245 #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)]
246 pub struct SteadyTime(sys
::SteadyTime
);
249 /// Returns a `SteadyTime` representing the current moment in time.
250 pub fn now() -> SteadyTime
{
251 SteadyTime(sys
::SteadyTime
::now())
255 impl fmt
::Display
for SteadyTime
{
256 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
257 // TODO: needs a display customization
258 fmt
::Debug
::fmt(self, fmt
)
262 impl Sub
for SteadyTime
{
263 type Output
= Duration
;
265 fn sub(self, other
: SteadyTime
) -> Duration
{
270 impl Sub
<Duration
> for SteadyTime
{
271 type Output
= SteadyTime
;
273 fn sub(self, other
: Duration
) -> SteadyTime
{
274 SteadyTime(self.0 - other
)
278 impl Add
<Duration
> for SteadyTime
{
279 type Output
= SteadyTime
;
281 fn add(self, other
: Duration
) -> SteadyTime
{
282 SteadyTime(self.0 + other
)
286 #[cfg(not(any(windows, target_env = "sgx")))]
288 extern { fn tzset(); }
293 #[cfg(any(windows, target_env = "sgx"))]
296 /// Holds a calendar date and time broken down into its components (year, month,
297 /// day, and so on), also called a broken-down time value.
298 // FIXME: use c_int instead of i32?
300 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
301 #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
303 /// Seconds after the minute - [0, 60]
306 /// Minutes after the hour - [0, 59]
309 /// Hours after midnight - [0, 23]
312 /// Day of the month - [1, 31]
315 /// Months since January - [0, 11]
321 /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday.
324 /// Days since January 1 - [0, 365]
327 /// Daylight Saving Time flag.
329 /// This value is positive if Daylight Saving Time is in effect, zero if
330 /// Daylight Saving Time is not in effect, and negative if this information
331 /// is not available.
334 /// Identifies the time zone that was used to compute this broken-down time
335 /// value, including any adjustment for Daylight Saving Time. This is the
336 /// number of seconds east of UTC. For example, for U.S. Pacific Daylight
337 /// Time, the value is `-7*60*60 = -25200`.
340 /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1]
344 impl Add
<Duration
> for Tm
{
347 /// The resulting Tm is in UTC.
348 // FIXME: The resulting Tm should have the same timezone as `self`;
349 // however, we need a function such as `at_tm(clock: Timespec, offset: i32)`
351 fn add(self, other
: Duration
) -> Tm
{
352 at_utc(self.to_timespec() + other
)
356 impl Sub
<Duration
> for Tm
{
359 /// The resulting Tm is in UTC.
360 // FIXME: The resulting Tm should have the same timezone as `self`;
361 // however, we need a function such as `at_tm(clock: Timespec, offset: i32)`
363 fn sub(self, other
: Duration
) -> Tm
{
364 at_utc(self.to_timespec() - other
)
368 impl Sub
<Tm
> for Tm
{
369 type Output
= Duration
;
371 fn sub(self, other
: Tm
) -> Duration
{
372 self.to_timespec() - other
.to_timespec()
376 impl PartialOrd
for Tm
{
377 fn partial_cmp(&self, other
: &Tm
) -> Option
<Ordering
> {
378 self.to_timespec().partial_cmp(&other
.to_timespec())
383 fn cmp(&self, other
: &Tm
) -> Ordering
{
384 self.to_timespec().cmp(&other
.to_timespec())
388 pub fn empty_tm() -> Tm
{
404 /// Returns the specified time in UTC
405 pub fn at_utc(clock
: Timespec
) -> Tm
{
406 let Timespec { sec, nsec }
= clock
;
407 let mut tm
= empty_tm();
408 sys
::time_to_utc_tm(sec
, &mut tm
);
413 /// Returns the current time in UTC
414 pub fn now_utc() -> Tm
{
418 /// Returns the specified time in the local timezone
419 pub fn at(clock
: Timespec
) -> Tm
{
420 let Timespec { sec, nsec }
= clock
;
421 let mut tm
= empty_tm();
422 sys
::time_to_local_tm(sec
, &mut tm
);
427 /// Returns the current time in the local timezone
433 /// Convert time to the seconds from January 1, 1970
434 pub fn to_timespec(&self) -> Timespec
{
435 let sec
= match self.tm_utcoff
{
436 0 => sys
::utc_tm_to_time(self),
437 _
=> sys
::local_tm_to_time(self)
440 Timespec
::new(sec
, self.tm_nsec
)
443 /// Convert time to the local timezone
444 pub fn to_local(&self) -> Tm
{
445 at(self.to_timespec())
448 /// Convert time to the UTC
449 pub fn to_utc(&self) -> Tm
{
450 match self.tm_utcoff
{
452 _
=> at_utc(self.to_timespec())
457 * Returns a TmFmt that outputs according to the `asctime` format in ISO
458 * C, in the local timezone.
460 * Example: "Thu Jan 1 00:00:00 1970"
462 pub fn ctime(&self) -> TmFmt
{
470 * Returns a TmFmt that outputs according to the `asctime` format in ISO
473 * Example: "Thu Jan 1 00:00:00 1970"
475 pub fn asctime(&self) -> TmFmt
{
478 format
: Fmt
::Str("%c"),
482 /// Formats the time according to the format string.
483 pub fn strftime
<'a
>(&'a
self, format
: &'a
str) -> Result
<TmFmt
<'a
>, ParseError
> {
484 validate_format(TmFmt
{
486 format
: Fmt
::Str(format
),
491 * Returns a TmFmt that outputs according to RFC 822.
493 * local: "Thu, 22 Mar 2012 07:53:18 PST"
494 * utc: "Thu, 22 Mar 2012 14:53:18 GMT"
496 pub fn rfc822(&self) -> TmFmt
{
497 let fmt
= if self.tm_utcoff
== 0 {
498 "%a, %d %b %Y %T GMT"
504 format
: Fmt
::Str(fmt
),
509 * Returns a TmFmt that outputs according to RFC 822 with Zulu time.
511 * local: "Thu, 22 Mar 2012 07:53:18 -0700"
512 * utc: "Thu, 22 Mar 2012 14:53:18 -0000"
514 pub fn rfc822z(&self) -> TmFmt
{
517 format
: Fmt
::Str("%a, %d %b %Y %T %z"),
522 * Returns a TmFmt that outputs according to RFC 3339. RFC 3339 is
523 * compatible with ISO 8601.
525 * local: "2012-02-22T07:53:18-07:00"
526 * utc: "2012-02-22T14:53:18Z"
528 pub fn rfc3339
<'a
>(&'a
self) -> TmFmt
{
531 format
: Fmt
::Rfc3339
,
536 #[derive(Copy, PartialEq, Debug, Clone)]
537 pub enum ParseError
{
549 InvalidSecondsSinceEpoch
,
550 MissingFormatConverter
,
551 InvalidFormatSpecifier(char),
552 UnexpectedCharacter(char, char),
555 impl fmt
::Display
for ParseError
{
556 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
559 InvalidFormatSpecifier(ch
) => {
560 write
!(f
, "{}: %{}", self.description(), ch
)
562 UnexpectedCharacter(a
, b
) => {
563 write
!(f
, "expected: `{}`, found: `{}`", a
, b
)
565 _
=> write
!(f
, "{}", self.description())
570 impl Error
for ParseError
{
571 fn description(&self) -> &str {
573 InvalidSecond
=> "Invalid second.",
574 InvalidMinute
=> "Invalid minute.",
575 InvalidHour
=> "Invalid hour.",
576 InvalidDay
=> "Invalid day.",
577 InvalidMonth
=> "Invalid month.",
578 InvalidYear
=> "Invalid year.",
579 InvalidDayOfWeek
=> "Invalid day of the week.",
580 InvalidDayOfMonth
=> "Invalid day of the month.",
581 InvalidDayOfYear
=> "Invalid day of the year.",
582 InvalidZoneOffset
=> "Invalid zone offset.",
583 InvalidTime
=> "Invalid time.",
584 InvalidSecondsSinceEpoch
=> "Invalid seconds since epoch.",
585 MissingFormatConverter
=> "missing format converter after `%`",
586 InvalidFormatSpecifier(..) => "invalid format specifier",
587 UnexpectedCharacter(..) => "Unexpected character.",
592 /// A wrapper around a `Tm` and format string that implements Display.
594 pub struct TmFmt
<'a
> {
606 fn validate_format
<'a
>(fmt
: TmFmt
<'a
>) -> Result
<TmFmt
<'a
>, ParseError
> {
608 match (fmt
.tm
.tm_wday
, fmt
.tm
.tm_mon
) {
609 (0...6, 0...11) => (),
610 (_wday
, 0...11) => return Err(InvalidDayOfWeek
),
611 (0...6, _mon
) => return Err(InvalidMonth
),
612 _
=> return Err(InvalidDay
)
616 let mut chars
= s
.chars();
621 Some('A'
) | Some('a'
) | Some('B'
) | Some('b'
) |
622 Some('C'
) | Some('c'
) | Some('D'
) | Some('d'
) |
623 Some('e'
) | Some('F'
) | Some('f'
) | Some('G'
) |
624 Some('g'
) | Some('H'
) | Some('h'
) | Some('I'
) |
625 Some('j'
) | Some('k'
) | Some('l'
) | Some('M'
) |
626 Some('m'
) | Some('n'
) | Some('P'
) | Some('p'
) |
627 Some('R'
) | Some('r'
) | Some('S'
) | Some('s'
) |
628 Some('T'
) | Some('t'
) | Some('U'
) | Some('u'
) |
629 Some('V'
) | Some('v'
) | Some('W'
) | Some('w'
) |
630 Some('X'
) | Some('x'
) | Some('Y'
) | Some('y'
) |
631 Some('Z'
) | Some('z'
) | Some('
+'
) | Some('
%'
) => (),
633 Some(c
) => return Err(InvalidFormatSpecifier(c
)),
634 None
=> return Err(MissingFormatConverter
),
647 /// Formats the time according to the format string.
648 pub fn strftime(format
: &str, tm
: &Tm
) -> Result
<String
, ParseError
> {
649 tm
.strftime(format
).map(|fmt
| fmt
.to_string())
654 use super::{Timespec
, get_time
, precise_time_ns
, precise_time_s
,
655 at_utc
, at
, strptime
, PreciseTime
, SteadyTime
, ParseError
, Duration
};
656 use super::ParseError
::{InvalidTime
, InvalidYear
, MissingFormatConverter
,
657 InvalidFormatSpecifier
};
659 #[allow(deprecated)] // `Once::new` is const starting in Rust 1.32
660 use std
::sync
::ONCE_INIT
;
661 use std
::sync
::{Once, Mutex, MutexGuard, LockResult}
;
666 _tzreset
: ::sys
::TzReset
,
667 _lock
: LockResult
<MutexGuard
<'
static, ()>>,
670 fn set_time_zone_la_or_london(london
: bool
) -> TzReset
{
671 // Lock manages current timezone because some tests require LA some
673 static mut LOCK
: *mut Mutex
<()> = 0 as *mut _
;
674 #[allow(deprecated)] // `Once::new` is const starting in Rust 1.32
675 static INIT
: Once
= ONCE_INIT
;
679 LOCK
= mem
::transmute(Box
::new(Mutex
::new(())));
682 let timezone_lock
= (*LOCK
).lock();
683 let reset_func
= if london
{
684 ::sys
::set_london_with_dst_time_zone()
686 ::sys
::set_los_angeles_time_zone()
689 _lock
: timezone_lock
,
690 _tzreset
: reset_func
,
695 fn set_time_zone() -> TzReset
{
696 set_time_zone_la_or_london(false)
699 fn set_time_zone_london_dst() -> TzReset
{
700 set_time_zone_la_or_london(true)
705 static SOME_RECENT_DATE
: i64 = 1577836800i64; // 2020-01-01T00:00:00Z
706 static SOME_FUTURE_DATE
: i64 = i32::MAX
as i64; // Y2038
708 let tv1
= get_time();
709 debug
!("tv1={} sec + {} nsec", tv1
.sec
, tv1
.nsec
);
711 assert
!(tv1
.sec
> SOME_RECENT_DATE
);
712 assert
!(tv1
.nsec
< 1000000000i32);
714 let tv2
= get_time();
715 debug
!("tv2={} sec + {} nsec", tv2
.sec
, tv2
.nsec
);
717 assert
!(tv2
.sec
>= tv1
.sec
);
718 assert
!(tv2
.sec
< SOME_FUTURE_DATE
);
719 assert
!(tv2
.nsec
< 1000000000i32);
720 if tv2
.sec
== tv1
.sec
{
721 assert
!(tv2
.nsec
>= tv1
.nsec
);
726 fn test_precise_time() {
727 let s0
= precise_time_s();
728 debug
!("s0={} sec", s0
);
731 let ns0
= precise_time_ns();
732 let ns1
= precise_time_ns();
733 debug
!("ns0={} ns", ns0
);
734 debug
!("ns1={} ns", ns1
);
737 let ns2
= precise_time_ns();
738 debug
!("ns2={} ns", ns2
);
743 fn test_precise_time_to() {
744 let t0
= PreciseTime(1000);
745 let t1
= PreciseTime(1023);
746 assert_eq
!(Duration
::nanoseconds(23), t0
.to(t1
));
751 let _reset
= set_time_zone();
753 let time
= Timespec
::new(1234567890, 54321);
754 let utc
= at_utc(time
);
756 assert_eq
!(utc
.tm_sec
, 30);
757 assert_eq
!(utc
.tm_min
, 31);
758 assert_eq
!(utc
.tm_hour
, 23);
759 assert_eq
!(utc
.tm_mday
, 13);
760 assert_eq
!(utc
.tm_mon
, 1);
761 assert_eq
!(utc
.tm_year
, 109);
762 assert_eq
!(utc
.tm_wday
, 5);
763 assert_eq
!(utc
.tm_yday
, 43);
764 assert_eq
!(utc
.tm_isdst
, 0);
765 assert_eq
!(utc
.tm_utcoff
, 0);
766 assert_eq
!(utc
.tm_nsec
, 54321);
771 let _reset
= set_time_zone();
773 let time
= Timespec
::new(1234567890, 54321);
774 let local
= at(time
);
776 debug
!("time_at: {:?}", local
);
778 assert_eq
!(local
.tm_sec
, 30);
779 assert_eq
!(local
.tm_min
, 31);
780 assert_eq
!(local
.tm_hour
, 15);
781 assert_eq
!(local
.tm_mday
, 13);
782 assert_eq
!(local
.tm_mon
, 1);
783 assert_eq
!(local
.tm_year
, 109);
784 assert_eq
!(local
.tm_wday
, 5);
785 assert_eq
!(local
.tm_yday
, 43);
786 assert_eq
!(local
.tm_isdst
, 0);
787 assert_eq
!(local
.tm_utcoff
, -28800);
788 assert_eq
!(local
.tm_nsec
, 54321);
792 fn test_to_timespec() {
793 let _reset
= set_time_zone();
795 let time
= Timespec
::new(1234567890, 54321);
796 let utc
= at_utc(time
);
798 assert_eq
!(utc
.to_timespec(), time
);
799 assert_eq
!(utc
.to_local().to_timespec(), time
);
803 fn test_conversions() {
804 let _reset
= set_time_zone();
806 let time
= Timespec
::new(1234567890, 54321);
807 let utc
= at_utc(time
);
808 let local
= at(time
);
810 assert
!(local
.to_local() == local
);
811 assert
!(local
.to_utc() == utc
);
812 assert
!(local
.to_utc().to_local() == local
);
813 assert
!(utc
.to_utc() == utc
);
814 assert
!(utc
.to_local() == local
);
815 assert
!(utc
.to_local().to_utc() == utc
);
820 let _reset
= set_time_zone();
822 match strptime("", "") {
824 assert
!(tm
.tm_sec
== 0);
825 assert
!(tm
.tm_min
== 0);
826 assert
!(tm
.tm_hour
== 0);
827 assert
!(tm
.tm_mday
== 0);
828 assert
!(tm
.tm_mon
== 0);
829 assert
!(tm
.tm_year
== 0);
830 assert
!(tm
.tm_wday
== 0);
831 assert
!(tm
.tm_isdst
== 0);
832 assert
!(tm
.tm_utcoff
== 0);
833 assert
!(tm
.tm_nsec
== 0);
838 let format
= "%a %b %e %T.%f %Y";
839 assert_eq
!(strptime("", format
), Err(ParseError
::InvalidDay
));
840 assert_eq
!(strptime("Fri Feb 13 15:31:30", format
),
843 match strptime("Fri Feb 13 15:31:30.01234 2009", format
) {
844 Err(e
) => panic
!("{}", e
),
846 assert_eq
!(tm
.tm_sec
, 30);
847 assert_eq
!(tm
.tm_min
, 31);
848 assert_eq
!(tm
.tm_hour
, 15);
849 assert_eq
!(tm
.tm_mday
, 13);
850 assert_eq
!(tm
.tm_mon
, 1);
851 assert_eq
!(tm
.tm_year
, 109);
852 assert_eq
!(tm
.tm_wday
, 5);
853 assert_eq
!(tm
.tm_yday
, 0);
854 assert_eq
!(tm
.tm_isdst
, 0);
855 assert_eq
!(tm
.tm_utcoff
, 0);
856 assert_eq
!(tm
.tm_nsec
, 12340000);
860 fn test(s
: &str, format
: &str) -> bool
{
861 match strptime(s
, format
) {
863 tm
.strftime(format
).unwrap().to_string() == s
.to_string()
865 Err(e
) => panic
!("{:?}, s={:?}, format={:?}", e
, s
, format
)
869 fn test_oneway(s
: &str, format
: &str) -> bool
{
870 match strptime(s
, format
) {
872 // oneway tests are used when reformatting the parsed Tm
873 // back into a string can generate a different string
874 // from the original (i.e. leading zeroes)
877 Err(e
) => panic
!("{:?}, s={:?}, format={:?}", e
, s
, format
)
882 "Sunday".to_string(),
883 "Monday".to_string(),
884 "Tuesday".to_string(),
885 "Wednesday".to_string(),
886 "Thursday".to_string(),
887 "Friday".to_string(),
888 "Saturday".to_string()
890 for day
in days
.iter() {
891 assert
!(test(&day
, "%A"));
903 for day
in days
.iter() {
904 assert
!(test(&day
, "%a"));
908 "January".to_string(),
909 "February".to_string(),
915 "August".to_string(),
916 "September".to_string(),
917 "October".to_string(),
918 "November".to_string(),
919 "December".to_string()
921 for day
in months
.iter() {
922 assert
!(test(&day
, "%B"));
939 for day
in months
.iter() {
940 assert
!(test(&day
, "%b"));
943 assert
!(test("19", "%C"));
944 assert
!(test("Fri Feb 3 23:31:30 2009", "%c"));
945 assert
!(test("Fri Feb 13 23:31:30 2009", "%c"));
946 assert
!(test("02/13/09", "%D"));
947 assert
!(test("03", "%d"));
948 assert
!(test("13", "%d"));
949 assert
!(test(" 3", "%e"));
950 assert
!(test("13", "%e"));
951 assert
!(test("2009-02-13", "%F"));
952 assert
!(test("03", "%H"));
953 assert
!(test("13", "%H"));
954 assert
!(test("03", "%I")); // FIXME (#2350): flesh out
955 assert
!(test("11", "%I")); // FIXME (#2350): flesh out
956 assert
!(test("044", "%j"));
957 assert
!(test(" 3", "%k"));
958 assert
!(test("13", "%k"));
959 assert
!(test(" 1", "%l"));
960 assert
!(test("11", "%l"));
961 assert
!(test("03", "%M"));
962 assert
!(test("13", "%M"));
963 assert
!(test("\n", "%n"));
964 assert
!(test("am", "%P"));
965 assert
!(test("pm", "%P"));
966 assert
!(test("AM", "%p"));
967 assert
!(test("PM", "%p"));
968 assert
!(test("23:31", "%R"));
969 assert
!(test("11:31:30 AM", "%r"));
970 assert
!(test("11:31:30 PM", "%r"));
971 assert
!(test("03", "%S"));
972 assert
!(test("13", "%S"));
973 assert
!(test("15:31:30", "%T"));
974 assert
!(test("\t", "%t"));
975 assert
!(test("1", "%u"));
976 assert
!(test("7", "%u"));
977 assert
!(test("13-Feb-2009", "%v"));
978 assert
!(test("0", "%w"));
979 assert
!(test("6", "%w"));
980 assert
!(test("2009", "%Y"));
981 assert
!(test("09", "%y"));
983 assert
!(test_oneway("3", "%d"));
984 assert
!(test_oneway("3", "%H"));
985 assert
!(test_oneway("3", "%e"));
986 assert
!(test_oneway("3", "%M"));
987 assert
!(test_oneway("3", "%S"));
989 assert
!(strptime("-0000", "%z").unwrap().tm_utcoff
== 0);
990 assert
!(strptime("-00:00", "%z").unwrap().tm_utcoff
== 0);
991 assert
!(strptime("Z", "%z").unwrap().tm_utcoff
== 0);
992 assert_eq
!(-28800, strptime("-0800", "%z").unwrap().tm_utcoff
);
993 assert_eq
!(-28800, strptime("-08:00", "%z").unwrap().tm_utcoff
);
994 assert_eq
!(28800, strptime("+0800", "%z").unwrap().tm_utcoff
);
995 assert_eq
!(28800, strptime("+08:00", "%z").unwrap().tm_utcoff
);
996 assert_eq
!(5400, strptime("+0130", "%z").unwrap().tm_utcoff
);
997 assert_eq
!(5400, strptime("+01:30", "%z").unwrap().tm_utcoff
);
998 assert
!(test("%", "%%"));
1001 assert_eq
!(strptime("360", "%Y-%m-%d"), Err(InvalidYear
));
1003 // Test for epoch seconds parsing
1005 assert
!(test("1428035610", "%s"));
1006 let tm
= strptime("1428035610", "%s").unwrap();
1007 assert_eq
!(tm
.tm_utcoff
, 0);
1008 assert_eq
!(tm
.tm_isdst
, 0);
1009 assert_eq
!(tm
.tm_yday
, 92);
1010 assert_eq
!(tm
.tm_wday
, 5);
1011 assert_eq
!(tm
.tm_year
, 115);
1012 assert_eq
!(tm
.tm_mon
, 3);
1013 assert_eq
!(tm
.tm_mday
, 3);
1014 assert_eq
!(tm
.tm_hour
, 4);
1020 let _reset
= set_time_zone();
1022 let time
= Timespec
::new(1234567890, 54321);
1023 let utc
= at_utc(time
);
1024 let local
= at(time
);
1026 debug
!("test_ctime: {} {}", utc
.asctime(), local
.asctime());
1028 assert_eq
!(utc
.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string());
1029 assert_eq
!(local
.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1034 let _reset
= set_time_zone();
1036 let time
= Timespec
::new(1234567890, 54321);
1037 let utc
= at_utc(time
);
1038 let local
= at(time
);
1040 debug
!("test_ctime: {} {}", utc
.ctime(), local
.ctime());
1042 assert_eq
!(utc
.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1043 assert_eq
!(local
.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1047 fn test_strftime() {
1048 let _reset
= set_time_zone();
1050 let time
= Timespec
::new(1234567890, 54321);
1051 let utc
= at_utc(time
);
1052 let local
= at(time
);
1054 assert_eq
!(local
.strftime("").unwrap().to_string(), "".to_string());
1055 assert_eq
!(local
.strftime("%A").unwrap().to_string(), "Friday".to_string());
1056 assert_eq
!(local
.strftime("%a").unwrap().to_string(), "Fri".to_string());
1057 assert_eq
!(local
.strftime("%B").unwrap().to_string(), "February".to_string());
1058 assert_eq
!(local
.strftime("%b").unwrap().to_string(), "Feb".to_string());
1059 assert_eq
!(local
.strftime("%C").unwrap().to_string(), "20".to_string());
1060 assert_eq
!(local
.strftime("%c").unwrap().to_string(),
1061 "Fri Feb 13 15:31:30 2009".to_string());
1062 assert_eq
!(local
.strftime("%D").unwrap().to_string(), "02/13/09".to_string());
1063 assert_eq
!(local
.strftime("%d").unwrap().to_string(), "13".to_string());
1064 assert_eq
!(local
.strftime("%e").unwrap().to_string(), "13".to_string());
1065 assert_eq
!(local
.strftime("%F").unwrap().to_string(), "2009-02-13".to_string());
1066 assert_eq
!(local
.strftime("%f").unwrap().to_string(), "000054321".to_string());
1067 assert_eq
!(local
.strftime("%G").unwrap().to_string(), "2009".to_string());
1068 assert_eq
!(local
.strftime("%g").unwrap().to_string(), "09".to_string());
1069 assert_eq
!(local
.strftime("%H").unwrap().to_string(), "15".to_string());
1070 assert_eq
!(local
.strftime("%h").unwrap().to_string(), "Feb".to_string());
1071 assert_eq
!(local
.strftime("%I").unwrap().to_string(), "03".to_string());
1072 assert_eq
!(local
.strftime("%j").unwrap().to_string(), "044".to_string());
1073 assert_eq
!(local
.strftime("%k").unwrap().to_string(), "15".to_string());
1074 assert_eq
!(local
.strftime("%l").unwrap().to_string(), " 3".to_string());
1075 assert_eq
!(local
.strftime("%M").unwrap().to_string(), "31".to_string());
1076 assert_eq
!(local
.strftime("%m").unwrap().to_string(), "02".to_string());
1077 assert_eq
!(local
.strftime("%n").unwrap().to_string(), "\n".to_string());
1078 assert_eq
!(local
.strftime("%P").unwrap().to_string(), "pm".to_string());
1079 assert_eq
!(local
.strftime("%p").unwrap().to_string(), "PM".to_string());
1080 assert_eq
!(local
.strftime("%R").unwrap().to_string(), "15:31".to_string());
1081 assert_eq
!(local
.strftime("%r").unwrap().to_string(), "03:31:30 PM".to_string());
1082 assert_eq
!(local
.strftime("%S").unwrap().to_string(), "30".to_string());
1083 assert_eq
!(local
.strftime("%s").unwrap().to_string(), "1234567890".to_string());
1084 assert_eq
!(local
.strftime("%T").unwrap().to_string(), "15:31:30".to_string());
1085 assert_eq
!(local
.strftime("%t").unwrap().to_string(), "\t".to_string());
1086 assert_eq
!(local
.strftime("%U").unwrap().to_string(), "06".to_string());
1087 assert_eq
!(local
.strftime("%u").unwrap().to_string(), "5".to_string());
1088 assert_eq
!(local
.strftime("%V").unwrap().to_string(), "07".to_string());
1089 assert_eq
!(local
.strftime("%v").unwrap().to_string(), "13-Feb-2009".to_string());
1090 assert_eq
!(local
.strftime("%W").unwrap().to_string(), "06".to_string());
1091 assert_eq
!(local
.strftime("%w").unwrap().to_string(), "5".to_string());
1092 // FIXME (#2350): support locale
1093 assert_eq
!(local
.strftime("%X").unwrap().to_string(), "15:31:30".to_string());
1094 // FIXME (#2350): support locale
1095 assert_eq
!(local
.strftime("%x").unwrap().to_string(), "02/13/09".to_string());
1096 assert_eq
!(local
.strftime("%Y").unwrap().to_string(), "2009".to_string());
1097 assert_eq
!(local
.strftime("%y").unwrap().to_string(), "09".to_string());
1098 // FIXME (#2350): support locale
1099 assert_eq
!(local
.strftime("%Z").unwrap().to_string(), "".to_string());
1100 assert_eq
!(local
.strftime("%z").unwrap().to_string(), "-0800".to_string());
1101 assert_eq
!(local
.strftime("%+").unwrap().to_string(),
1102 "2009-02-13T15:31:30-08:00".to_string());
1103 assert_eq
!(local
.strftime("%%").unwrap().to_string(), "%".to_string());
1105 let invalid_specifiers
= ["%E", "%J", "%K", "%L", "%N", "%O", "%o", "%Q", "%q"];
1106 for &sp
in invalid_specifiers
.iter() {
1107 assert_eq
!(local
.strftime(sp
).unwrap_err(),
1108 InvalidFormatSpecifier(sp
[1..].chars().next().unwrap()));
1110 assert_eq
!(local
.strftime("%").unwrap_err(), MissingFormatConverter
);
1111 assert_eq
!(local
.strftime("%A %").unwrap_err(), MissingFormatConverter
);
1113 assert_eq
!(local
.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1114 assert_eq
!(local
.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1115 assert_eq
!(local
.rfc822z().to_string(), "Fri, 13 Feb 2009 15:31:30 -0800".to_string());
1116 assert_eq
!(local
.rfc3339().to_string(), "2009-02-13T15:31:30-08:00".to_string());
1118 assert_eq
!(utc
.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string());
1119 assert_eq
!(utc
.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1120 assert_eq
!(utc
.rfc822().to_string(), "Fri, 13 Feb 2009 23:31:30 GMT".to_string());
1121 assert_eq
!(utc
.rfc822z().to_string(), "Fri, 13 Feb 2009 23:31:30 -0000".to_string());
1122 assert_eq
!(utc
.rfc3339().to_string(), "2009-02-13T23:31:30Z".to_string());
1126 fn test_timespec_eq_ord() {
1127 let a
= &Timespec
::new(-2, 1);
1128 let b
= &Timespec
::new(-1, 2);
1129 let c
= &Timespec
::new(1, 2);
1130 let d
= &Timespec
::new(2, 1);
1131 let e
= &Timespec
::new(2, 1);
1158 #[allow(deprecated)]
1159 fn test_timespec_hash() {
1160 use std
::hash
::{Hash, Hasher}
;
1162 let c
= &Timespec
::new(3, 2);
1163 let d
= &Timespec
::new(2, 1);
1164 let e
= &Timespec
::new(2, 1);
1166 let mut hasher
= ::std
::hash
::SipHasher
::new();
1169 d
.hash(&mut hasher
);
1173 hasher
= ::std
::hash
::SipHasher
::new();
1176 e
.hash(&mut hasher
);
1180 hasher
= ::std
::hash
::SipHasher
::new();
1183 c
.hash(&mut hasher
);
1187 assert_eq
!(d_hash
, e_hash
);
1188 assert
!(c_hash
!= e_hash
);
1192 fn test_timespec_add() {
1193 let a
= Timespec
::new(1, 2);
1194 let b
= Duration
::seconds(2) + Duration
::nanoseconds(3);
1196 assert_eq
!(c
.sec
, 3);
1197 assert_eq
!(c
.nsec
, 5);
1199 let p
= Timespec
::new(1, super::NSEC_PER_SEC
- 2);
1200 let q
= Duration
::seconds(2) + Duration
::nanoseconds(2);
1202 assert_eq
!(r
.sec
, 4);
1203 assert_eq
!(r
.nsec
, 0);
1205 let u
= Timespec
::new(1, super::NSEC_PER_SEC
- 2);
1206 let v
= Duration
::seconds(2) + Duration
::nanoseconds(3);
1208 assert_eq
!(w
.sec
, 4);
1209 assert_eq
!(w
.nsec
, 1);
1211 let k
= Timespec
::new(1, 0);
1212 let l
= Duration
::nanoseconds(-1);
1214 assert_eq
!(m
.sec
, 0);
1215 assert_eq
!(m
.nsec
, 999_999_999);
1219 fn test_timespec_sub() {
1220 let a
= Timespec
::new(2, 3);
1221 let b
= Timespec
::new(1, 2);
1223 assert_eq
!(c
.num_nanoseconds(), Some(super::NSEC_PER_SEC
as i64 + 1));
1225 let p
= Timespec
::new(2, 0);
1226 let q
= Timespec
::new(1, 2);
1228 assert_eq
!(r
.num_nanoseconds(), Some(super::NSEC_PER_SEC
as i64 - 2));
1230 let u
= Timespec
::new(1, 2);
1231 let v
= Timespec
::new(2, 3);
1233 assert_eq
!(w
.num_nanoseconds(), Some(-super::NSEC_PER_SEC
as i64 - 1));
1237 fn test_time_sub() {
1239 let b
= at(a
.to_timespec() + Duration
::seconds(5));
1241 assert_eq
!(c
.num_nanoseconds(), Some(super::NSEC_PER_SEC
as i64 * 5));
1245 fn test_steadytime_sub() {
1246 let a
= SteadyTime
::now();
1247 let b
= a
+ Duration
::seconds(1);
1248 assert_eq
!(b
- a
, Duration
::seconds(1));
1249 assert_eq
!(a
- b
, Duration
::seconds(-1));
1253 fn test_date_before_1970() {
1254 let early
= strptime("1901-01-06", "%F").unwrap();
1255 let late
= strptime("2000-01-01", "%F").unwrap();
1256 assert
!(early
< late
);
1261 let _reset
= set_time_zone_london_dst();
1262 let utc_in_feb
= strptime("2015-02-01Z", "%F%z").unwrap();
1263 let utc_in_jun
= strptime("2015-06-01Z", "%F%z").unwrap();
1264 let utc_in_nov
= strptime("2015-11-01Z", "%F%z").unwrap();
1265 let local_in_feb
= utc_in_feb
.to_local();
1266 let local_in_jun
= utc_in_jun
.to_local();
1267 let local_in_nov
= utc_in_nov
.to_local();
1269 assert_eq
!(local_in_feb
.tm_mon
, 1);
1270 assert_eq
!(local_in_feb
.tm_hour
, 0);
1271 assert_eq
!(local_in_feb
.tm_utcoff
, 0);
1272 assert_eq
!(local_in_feb
.tm_isdst
, 0);
1274 assert_eq
!(local_in_jun
.tm_mon
, 5);
1275 assert_eq
!(local_in_jun
.tm_hour
, 1);
1276 assert_eq
!(local_in_jun
.tm_utcoff
, 3600);
1277 assert_eq
!(local_in_jun
.tm_isdst
, 1);
1279 assert_eq
!(local_in_nov
.tm_mon
, 10);
1280 assert_eq
!(local_in_nov
.tm_hour
, 0);
1281 assert_eq
!(local_in_nov
.tm_utcoff
, 0);
1282 assert_eq
!(local_in_nov
.tm_isdst
, 0)