1#![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(trivial_numeric_casts)]
37#![cfg_attr(test, deny(warnings))]
38
39#[cfg(target_os = "redox")] extern crate syscall;
40#[cfg(unix)] extern crate libc;
41#[cfg(windows)] extern crate winapi;
42#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
43
44#[cfg(test)] #[macro_use] extern crate log;
45
46use std::cmp::Ordering;
47use std::error::Error;
48use std::fmt;
49use std::ops::{Add, Sub};
50
51pub use duration::{Duration, OutOfRangeError};
52
53use self::ParseError::{InvalidDay, InvalidDayOfMonth, InvalidDayOfWeek,
54 InvalidDayOfYear, InvalidFormatSpecifier, InvalidHour,
55 InvalidMinute, InvalidMonth, InvalidSecond, InvalidTime,
56 InvalidYear, InvalidZoneOffset, InvalidSecondsSinceEpoch,
57 MissingFormatConverter, UnexpectedCharacter};
58
59pub use parse::strptime;
60
61mod display;
62mod duration;
63mod parse;
64mod sys;
65
66static NSEC_PER_SEC: i32 = 1_000_000_000;
67
68#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
74#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
75pub struct Timespec { pub sec: i64, pub nsec: i32 }
76impl Timespec {
85 pub fn new(sec: i64, nsec: i32) -> Timespec {
86 assert!(nsec >= 0 && nsec < NSEC_PER_SEC);
87 Timespec { sec: sec, nsec: nsec }
88 }
89}
90
91impl Add<Duration> for Timespec {
92 type Output = Timespec;
93
94 fn add(self, other: Duration) -> Timespec {
95 let d_sec = other.num_seconds();
96 let d_nsec = (other - Duration::seconds(d_sec))
99 .num_nanoseconds().unwrap() as i32;
100 let mut sec = self.sec + d_sec;
101 let mut nsec = self.nsec + d_nsec;
102 if nsec >= NSEC_PER_SEC {
103 nsec -= NSEC_PER_SEC;
104 sec += 1;
105 } else if nsec < 0 {
106 nsec += NSEC_PER_SEC;
107 sec -= 1;
108 }
109 Timespec::new(sec, nsec)
110 }
111}
112
113impl Sub<Duration> for Timespec {
114 type Output = Timespec;
115
116 fn sub(self, other: Duration) -> Timespec {
117 let d_sec = other.num_seconds();
118 let d_nsec = (other - Duration::seconds(d_sec))
121 .num_nanoseconds().unwrap() as i32;
122 let mut sec = self.sec - d_sec;
123 let mut nsec = self.nsec - d_nsec;
124 if nsec >= NSEC_PER_SEC {
125 nsec -= NSEC_PER_SEC;
126 sec += 1;
127 } else if nsec < 0 {
128 nsec += NSEC_PER_SEC;
129 sec -= 1;
130 }
131 Timespec::new(sec, nsec)
132 }
133}
134
135impl Sub<Timespec> for Timespec {
136 type Output = Duration;
137
138 fn sub(self, other: Timespec) -> Duration {
139 let sec = self.sec - other.sec;
140 let nsec = self.nsec - other.nsec;
141 Duration::seconds(sec) + Duration::nanoseconds(nsec as i64)
142 }
143}
144
145pub fn get_time() -> Timespec {
150 let (sec, nsec) = sys::get_time();
151 Timespec::new(sec, nsec)
152}
153
154
155#[inline]
160pub fn precise_time_ns() -> u64 {
161 sys::get_precise_ns()
162}
163
164
165pub fn precise_time_s() -> f64 {
170 return (precise_time_ns() as f64) / 1000000000.;
171}
172
173#[derive(Copy, Clone)]
193pub struct PreciseTime(u64);
194
195impl PreciseTime {
196 pub fn now() -> PreciseTime {
198 PreciseTime(precise_time_ns())
199 }
200
201 #[inline]
212 pub fn to(&self, later: PreciseTime) -> Duration {
213 Duration::nanoseconds((later.0 - self.0) as i64)
220 }
221}
222
223#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)]
243pub struct SteadyTime(sys::SteadyTime);
244
245impl SteadyTime {
246 pub fn now() -> SteadyTime {
248 SteadyTime(sys::SteadyTime::now())
249 }
250}
251
252impl fmt::Display for SteadyTime {
253 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
254 fmt::Debug::fmt(self, fmt)
256 }
257}
258
259impl Sub for SteadyTime {
260 type Output = Duration;
261
262 fn sub(self, other: SteadyTime) -> Duration {
263 self.0 - other.0
264 }
265}
266
267impl Sub<Duration> for SteadyTime {
268 type Output = SteadyTime;
269
270 fn sub(self, other: Duration) -> SteadyTime {
271 SteadyTime(self.0 - other)
272 }
273}
274
275impl Add<Duration> for SteadyTime {
276 type Output = SteadyTime;
277
278 fn add(self, other: Duration) -> SteadyTime {
279 SteadyTime(self.0 + other)
280 }
281}
282
283#[cfg(not(any(windows, target_env = "sgx")))]
284pub fn tzset() {
285 extern { fn tzset(); }
286 unsafe { tzset() }
287}
288
289
290#[cfg(any(windows, target_env = "sgx"))]
291pub fn tzset() {}
292
293#[repr(C)]
297#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
298#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
299pub struct Tm {
300 pub tm_sec: i32,
302
303 pub tm_min: i32,
305
306 pub tm_hour: i32,
308
309 pub tm_mday: i32,
311
312 pub tm_mon: i32,
314
315 pub tm_year: i32,
317
318 pub tm_wday: i32,
320
321 pub tm_yday: i32,
323
324 pub tm_isdst: i32,
330
331 pub tm_utcoff: i32,
336
337 pub tm_nsec: i32,
339}
340
341impl Add<Duration> for Tm {
342 type Output = Tm;
343
344 fn add(self, other: Duration) -> Tm {
349 at_utc(self.to_timespec() + other)
350 }
351}
352
353impl Sub<Duration> for Tm {
354 type Output = Tm;
355
356 fn sub(self, other: Duration) -> Tm {
361 at_utc(self.to_timespec() - other)
362 }
363}
364
365impl Sub<Tm> for Tm {
366 type Output = Duration;
367
368 fn sub(self, other: Tm) -> Duration {
369 self.to_timespec() - other.to_timespec()
370 }
371}
372
373impl PartialOrd for Tm {
374 fn partial_cmp(&self, other: &Tm) -> Option<Ordering> {
375 self.to_timespec().partial_cmp(&other.to_timespec())
376 }
377}
378
379impl Ord for Tm {
380 fn cmp(&self, other: &Tm) -> Ordering {
381 self.to_timespec().cmp(&other.to_timespec())
382 }
383}
384
385pub fn empty_tm() -> Tm {
386 Tm {
387 tm_sec: 0,
388 tm_min: 0,
389 tm_hour: 0,
390 tm_mday: 0,
391 tm_mon: 0,
392 tm_year: 0,
393 tm_wday: 0,
394 tm_yday: 0,
395 tm_isdst: 0,
396 tm_utcoff: 0,
397 tm_nsec: 0,
398 }
399}
400
401pub fn at_utc(clock: Timespec) -> Tm {
403 let Timespec { sec, nsec } = clock;
404 let mut tm = empty_tm();
405 sys::time_to_utc_tm(sec, &mut tm);
406 tm.tm_nsec = nsec;
407 tm
408}
409
410pub fn now_utc() -> Tm {
412 at_utc(get_time())
413}
414
415pub fn at(clock: Timespec) -> Tm {
417 let Timespec { sec, nsec } = clock;
418 let mut tm = empty_tm();
419 sys::time_to_local_tm(sec, &mut tm);
420 tm.tm_nsec = nsec;
421 tm
422}
423
424pub fn now() -> Tm {
426 at(get_time())
427}
428
429impl Tm {
430 pub fn to_timespec(&self) -> Timespec {
432 let sec = match self.tm_utcoff {
433 0 => sys::utc_tm_to_time(self),
434 _ => sys::local_tm_to_time(self)
435 };
436
437 Timespec::new(sec, self.tm_nsec)
438 }
439
440 pub fn to_local(&self) -> Tm {
442 at(self.to_timespec())
443 }
444
445 pub fn to_utc(&self) -> Tm {
447 match self.tm_utcoff {
448 0 => *self,
449 _ => at_utc(self.to_timespec())
450 }
451 }
452
453 pub fn ctime(&self) -> TmFmt {
460 TmFmt {
461 tm: self,
462 format: Fmt::Ctime,
463 }
464 }
465
466 pub fn asctime(&self) -> TmFmt {
473 TmFmt {
474 tm: self,
475 format: Fmt::Str("%c"),
476 }
477 }
478
479 pub fn strftime<'a>(&'a self, format: &'a str) -> Result<TmFmt<'a>, ParseError> {
481 validate_format(TmFmt {
482 tm: self,
483 format: Fmt::Str(format),
484 })
485 }
486
487 pub fn rfc822(&self) -> TmFmt {
494 let fmt = if self.tm_utcoff == 0 {
495 "%a, %d %b %Y %T GMT"
496 } else {
497 "%a, %d %b %Y %T %Z"
498 };
499 TmFmt {
500 tm: self,
501 format: Fmt::Str(fmt),
502 }
503 }
504
505 pub fn rfc822z(&self) -> TmFmt {
512 TmFmt {
513 tm: self,
514 format: Fmt::Str("%a, %d %b %Y %T %z"),
515 }
516 }
517
518 pub fn rfc3339<'a>(&'a self) -> TmFmt {
526 TmFmt {
527 tm: self,
528 format: Fmt::Rfc3339,
529 }
530 }
531}
532
533#[derive(Copy, PartialEq, Debug, Clone)]
534pub enum ParseError {
535 InvalidSecond,
536 InvalidMinute,
537 InvalidHour,
538 InvalidDay,
539 InvalidMonth,
540 InvalidYear,
541 InvalidDayOfWeek,
542 InvalidDayOfMonth,
543 InvalidDayOfYear,
544 InvalidZoneOffset,
545 InvalidTime,
546 InvalidSecondsSinceEpoch,
547 MissingFormatConverter,
548 InvalidFormatSpecifier(char),
549 UnexpectedCharacter(char, char),
550}
551
552impl fmt::Display for ParseError {
553 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
554 match *self {
555 InvalidFormatSpecifier(ch) => {
556 write!(f, "{}: %{}", self.description(), ch)
557 }
558 UnexpectedCharacter(a, b) => {
559 write!(f, "expected: `{}`, found: `{}`", a, b)
560 }
561 _ => write!(f, "{}", self.description())
562 }
563 }
564}
565
566impl Error for ParseError {
567 fn description(&self) -> &str {
568 match *self {
569 InvalidSecond => "Invalid second.",
570 InvalidMinute => "Invalid minute.",
571 InvalidHour => "Invalid hour.",
572 InvalidDay => "Invalid day.",
573 InvalidMonth => "Invalid month.",
574 InvalidYear => "Invalid year.",
575 InvalidDayOfWeek => "Invalid day of the week.",
576 InvalidDayOfMonth => "Invalid day of the month.",
577 InvalidDayOfYear => "Invalid day of the year.",
578 InvalidZoneOffset => "Invalid zone offset.",
579 InvalidTime => "Invalid time.",
580 InvalidSecondsSinceEpoch => "Invalid seconds since epoch.",
581 MissingFormatConverter => "missing format converter after `%`",
582 InvalidFormatSpecifier(..) => "invalid format specifier",
583 UnexpectedCharacter(..) => "Unexpected character.",
584 }
585 }
586}
587
588#[derive(Debug)]
590pub struct TmFmt<'a> {
591 tm: &'a Tm,
592 format: Fmt<'a>
593}
594
595#[derive(Debug)]
596enum Fmt<'a> {
597 Str(&'a str),
598 Rfc3339,
599 Ctime,
600}
601
602fn validate_format<'a>(fmt: TmFmt<'a>) -> Result<TmFmt<'a>, ParseError> {
603
604 match (fmt.tm.tm_wday, fmt.tm.tm_mon) {
605 (0...6, 0...11) => (),
606 (_wday, 0...11) => return Err(InvalidDayOfWeek),
607 (0...6, _mon) => return Err(InvalidMonth),
608 _ => return Err(InvalidDay)
609 }
610 match fmt.format {
611 Fmt::Str(ref s) => {
612 let mut chars = s.chars();
613 loop {
614 match chars.next() {
615 Some('%') => {
616 match chars.next() {
617 Some('A') | Some('a') | Some('B') | Some('b') |
618 Some('C') | Some('c') | Some('D') | Some('d') |
619 Some('e') | Some('F') | Some('f') | Some('G') |
620 Some('g') | Some('H') | Some('h') | Some('I') |
621 Some('j') | Some('k') | Some('l') | Some('M') |
622 Some('m') | Some('n') | Some('P') | Some('p') |
623 Some('R') | Some('r') | Some('S') | Some('s') |
624 Some('T') | Some('t') | Some('U') | Some('u') |
625 Some('V') | Some('v') | Some('W') | Some('w') |
626 Some('X') | Some('x') | Some('Y') | Some('y') |
627 Some('Z') | Some('z') | Some('+') | Some('%') => (),
628
629 Some(c) => return Err(InvalidFormatSpecifier(c)),
630 None => return Err(MissingFormatConverter),
631 }
632 },
633 None => break,
634 _ => ()
635 }
636 }
637 },
638 _ => ()
639 }
640 Ok(fmt)
641}
642
643pub fn strftime(format: &str, tm: &Tm) -> Result<String, ParseError> {
645 tm.strftime(format).map(|fmt| fmt.to_string())
646}
647
648#[cfg(test)]
649mod tests {
650 use super::{Timespec, get_time, precise_time_ns, precise_time_s,
651 at_utc, at, strptime, PreciseTime, SteadyTime, ParseError, Duration};
652 use super::ParseError::{InvalidTime, InvalidYear, MissingFormatConverter,
653 InvalidFormatSpecifier};
654
655 use std::sync::{Once, ONCE_INIT, Mutex, MutexGuard, LockResult};
656 use std::mem;
657
658 struct TzReset {
659 _tzreset: ::sys::TzReset,
660 _lock: LockResult<MutexGuard<'static, ()>>,
661 }
662
663 fn set_time_zone_la_or_london(london: bool) -> TzReset {
664 static mut LOCK: *mut Mutex<()> = 0 as *mut _;
667 static INIT: Once = ONCE_INIT;
668
669 unsafe {
670 INIT.call_once(|| {
671 LOCK = mem::transmute(Box::new(Mutex::new(())));
672 });
673
674 let timezone_lock = (*LOCK).lock();
675 let reset_func = if london {
676 ::sys::set_london_with_dst_time_zone()
677 } else {
678 ::sys::set_los_angeles_time_zone()
679 };
680 TzReset {
681 _lock: timezone_lock,
682 _tzreset: reset_func,
683 }
684 }
685 }
686
687 fn set_time_zone() -> TzReset {
688 set_time_zone_la_or_london(false)
689 }
690
691 fn set_time_zone_london_dst() -> TzReset {
692 set_time_zone_la_or_london(true)
693 }
694
695 #[test]
696 fn test_get_time() {
697 static SOME_RECENT_DATE: i64 = 1325376000i64; static SOME_FUTURE_DATE: i64 = 1577836800i64; let tv1 = get_time();
701 debug!("tv1={} sec + {} nsec", tv1.sec, tv1.nsec);
702
703 assert!(tv1.sec > SOME_RECENT_DATE);
704 assert!(tv1.nsec < 1000000000i32);
705
706 let tv2 = get_time();
707 debug!("tv2={} sec + {} nsec", tv2.sec, tv2.nsec);
708
709 assert!(tv2.sec >= tv1.sec);
710 assert!(tv2.sec < SOME_FUTURE_DATE);
711 assert!(tv2.nsec < 1000000000i32);
712 if tv2.sec == tv1.sec {
713 assert!(tv2.nsec >= tv1.nsec);
714 }
715 }
716
717 #[test]
718 fn test_precise_time() {
719 let s0 = precise_time_s();
720 debug!("s0={} sec", s0);
721 assert!(s0 > 0.);
722
723 let ns0 = precise_time_ns();
724 let ns1 = precise_time_ns();
725 debug!("ns0={} ns", ns0);
726 debug!("ns1={} ns", ns1);
727 assert!(ns1 >= ns0);
728
729 let ns2 = precise_time_ns();
730 debug!("ns2={} ns", ns2);
731 assert!(ns2 >= ns1);
732 }
733
734 #[test]
735 fn test_precise_time_to() {
736 let t0 = PreciseTime(1000);
737 let t1 = PreciseTime(1023);
738 assert_eq!(Duration::nanoseconds(23), t0.to(t1));
739 }
740
741 #[test]
742 fn test_at_utc() {
743 let _reset = set_time_zone();
744
745 let time = Timespec::new(1234567890, 54321);
746 let utc = at_utc(time);
747
748 assert_eq!(utc.tm_sec, 30);
749 assert_eq!(utc.tm_min, 31);
750 assert_eq!(utc.tm_hour, 23);
751 assert_eq!(utc.tm_mday, 13);
752 assert_eq!(utc.tm_mon, 1);
753 assert_eq!(utc.tm_year, 109);
754 assert_eq!(utc.tm_wday, 5);
755 assert_eq!(utc.tm_yday, 43);
756 assert_eq!(utc.tm_isdst, 0);
757 assert_eq!(utc.tm_utcoff, 0);
758 assert_eq!(utc.tm_nsec, 54321);
759 }
760
761 #[test]
762 fn test_at() {
763 let _reset = set_time_zone();
764
765 let time = Timespec::new(1234567890, 54321);
766 let local = at(time);
767
768 debug!("time_at: {:?}", local);
769
770 assert_eq!(local.tm_sec, 30);
771 assert_eq!(local.tm_min, 31);
772 assert_eq!(local.tm_hour, 15);
773 assert_eq!(local.tm_mday, 13);
774 assert_eq!(local.tm_mon, 1);
775 assert_eq!(local.tm_year, 109);
776 assert_eq!(local.tm_wday, 5);
777 assert_eq!(local.tm_yday, 43);
778 assert_eq!(local.tm_isdst, 0);
779 assert_eq!(local.tm_utcoff, -28800);
780 assert_eq!(local.tm_nsec, 54321);
781 }
782
783 #[test]
784 fn test_to_timespec() {
785 let _reset = set_time_zone();
786
787 let time = Timespec::new(1234567890, 54321);
788 let utc = at_utc(time);
789
790 assert_eq!(utc.to_timespec(), time);
791 assert_eq!(utc.to_local().to_timespec(), time);
792 }
793
794 #[test]
795 fn test_conversions() {
796 let _reset = set_time_zone();
797
798 let time = Timespec::new(1234567890, 54321);
799 let utc = at_utc(time);
800 let local = at(time);
801
802 assert!(local.to_local() == local);
803 assert!(local.to_utc() == utc);
804 assert!(local.to_utc().to_local() == local);
805 assert!(utc.to_utc() == utc);
806 assert!(utc.to_local() == local);
807 assert!(utc.to_local().to_utc() == utc);
808 }
809
810 #[test]
811 fn test_strptime() {
812 let _reset = set_time_zone();
813
814 match strptime("", "") {
815 Ok(ref tm) => {
816 assert!(tm.tm_sec == 0);
817 assert!(tm.tm_min == 0);
818 assert!(tm.tm_hour == 0);
819 assert!(tm.tm_mday == 0);
820 assert!(tm.tm_mon == 0);
821 assert!(tm.tm_year == 0);
822 assert!(tm.tm_wday == 0);
823 assert!(tm.tm_isdst == 0);
824 assert!(tm.tm_utcoff == 0);
825 assert!(tm.tm_nsec == 0);
826 }
827 Err(_) => ()
828 }
829
830 let format = "%a %b %e %T.%f %Y";
831 assert_eq!(strptime("", format), Err(ParseError::InvalidDay));
832 assert_eq!(strptime("Fri Feb 13 15:31:30", format),
833 Err(InvalidTime));
834
835 match strptime("Fri Feb 13 15:31:30.01234 2009", format) {
836 Err(e) => panic!("{}", e),
837 Ok(ref tm) => {
838 assert_eq!(tm.tm_sec, 30);
839 assert_eq!(tm.tm_min, 31);
840 assert_eq!(tm.tm_hour, 15);
841 assert_eq!(tm.tm_mday, 13);
842 assert_eq!(tm.tm_mon, 1);
843 assert_eq!(tm.tm_year, 109);
844 assert_eq!(tm.tm_wday, 5);
845 assert_eq!(tm.tm_yday, 0);
846 assert_eq!(tm.tm_isdst, 0);
847 assert_eq!(tm.tm_utcoff, 0);
848 assert_eq!(tm.tm_nsec, 12340000);
849 }
850 }
851
852 fn test(s: &str, format: &str) -> bool {
853 match strptime(s, format) {
854 Ok(tm) => {
855 tm.strftime(format).unwrap().to_string() == s.to_string()
856 },
857 Err(e) => panic!("{:?}, s={:?}, format={:?}", e, s, format)
858 }
859 }
860
861 fn test_oneway(s : &str, format : &str) -> bool {
862 match strptime(s, format) {
863 Ok(_) => {
864 true
868 },
869 Err(e) => panic!("{:?}, s={:?}, format={:?}", e, s, format)
870 }
871 }
872
873 let days = [
874 "Sunday".to_string(),
875 "Monday".to_string(),
876 "Tuesday".to_string(),
877 "Wednesday".to_string(),
878 "Thursday".to_string(),
879 "Friday".to_string(),
880 "Saturday".to_string()
881 ];
882 for day in days.iter() {
883 assert!(test(&day, "%A"));
884 }
885
886 let days = [
887 "Sun".to_string(),
888 "Mon".to_string(),
889 "Tue".to_string(),
890 "Wed".to_string(),
891 "Thu".to_string(),
892 "Fri".to_string(),
893 "Sat".to_string()
894 ];
895 for day in days.iter() {
896 assert!(test(&day, "%a"));
897 }
898
899 let months = [
900 "January".to_string(),
901 "February".to_string(),
902 "March".to_string(),
903 "April".to_string(),
904 "May".to_string(),
905 "June".to_string(),
906 "July".to_string(),
907 "August".to_string(),
908 "September".to_string(),
909 "October".to_string(),
910 "November".to_string(),
911 "December".to_string()
912 ];
913 for day in months.iter() {
914 assert!(test(&day, "%B"));
915 }
916
917 let months = [
918 "Jan".to_string(),
919 "Feb".to_string(),
920 "Mar".to_string(),
921 "Apr".to_string(),
922 "May".to_string(),
923 "Jun".to_string(),
924 "Jul".to_string(),
925 "Aug".to_string(),
926 "Sep".to_string(),
927 "Oct".to_string(),
928 "Nov".to_string(),
929 "Dec".to_string()
930 ];
931 for day in months.iter() {
932 assert!(test(&day, "%b"));
933 }
934
935 assert!(test("19", "%C"));
936 assert!(test("Fri Feb 3 23:31:30 2009", "%c"));
937 assert!(test("Fri Feb 13 23:31:30 2009", "%c"));
938 assert!(test("02/13/09", "%D"));
939 assert!(test("03", "%d"));
940 assert!(test("13", "%d"));
941 assert!(test(" 3", "%e"));
942 assert!(test("13", "%e"));
943 assert!(test("2009-02-13", "%F"));
944 assert!(test("03", "%H"));
945 assert!(test("13", "%H"));
946 assert!(test("03", "%I")); assert!(test("11", "%I")); assert!(test("044", "%j"));
949 assert!(test(" 3", "%k"));
950 assert!(test("13", "%k"));
951 assert!(test(" 1", "%l"));
952 assert!(test("11", "%l"));
953 assert!(test("03", "%M"));
954 assert!(test("13", "%M"));
955 assert!(test("\n", "%n"));
956 assert!(test("am", "%P"));
957 assert!(test("pm", "%P"));
958 assert!(test("AM", "%p"));
959 assert!(test("PM", "%p"));
960 assert!(test("23:31", "%R"));
961 assert!(test("11:31:30 AM", "%r"));
962 assert!(test("11:31:30 PM", "%r"));
963 assert!(test("03", "%S"));
964 assert!(test("13", "%S"));
965 assert!(test("15:31:30", "%T"));
966 assert!(test("\t", "%t"));
967 assert!(test("1", "%u"));
968 assert!(test("7", "%u"));
969 assert!(test("13-Feb-2009", "%v"));
970 assert!(test("0", "%w"));
971 assert!(test("6", "%w"));
972 assert!(test("2009", "%Y"));
973 assert!(test("09", "%y"));
974
975 assert!(test_oneway("3", "%d"));
976 assert!(test_oneway("3", "%H"));
977 assert!(test_oneway("3", "%e"));
978 assert!(test_oneway("3", "%M"));
979 assert!(test_oneway("3", "%S"));
980
981 assert!(strptime("-0000", "%z").unwrap().tm_utcoff == 0);
982 assert!(strptime("-00:00", "%z").unwrap().tm_utcoff == 0);
983 assert!(strptime("Z", "%z").unwrap().tm_utcoff == 0);
984 assert_eq!(-28800, strptime("-0800", "%z").unwrap().tm_utcoff);
985 assert_eq!(-28800, strptime("-08:00", "%z").unwrap().tm_utcoff);
986 assert_eq!(28800, strptime("+0800", "%z").unwrap().tm_utcoff);
987 assert_eq!(28800, strptime("+08:00", "%z").unwrap().tm_utcoff);
988 assert_eq!(5400, strptime("+0130", "%z").unwrap().tm_utcoff);
989 assert_eq!(5400, strptime("+01:30", "%z").unwrap().tm_utcoff);
990 assert!(test("%", "%%"));
991
992 assert_eq!(strptime("360", "%Y-%m-%d"), Err(InvalidYear));
994
995 {
997 assert!(test("1428035610", "%s"));
998 let tm = strptime("1428035610", "%s").unwrap();
999 assert_eq!(tm.tm_utcoff, 0);
1000 assert_eq!(tm.tm_isdst, 0);
1001 assert_eq!(tm.tm_yday, 92);
1002 assert_eq!(tm.tm_wday, 5);
1003 assert_eq!(tm.tm_year, 115);
1004 assert_eq!(tm.tm_mon, 3);
1005 assert_eq!(tm.tm_mday, 3);
1006 assert_eq!(tm.tm_hour, 4);
1007 }
1008 }
1009
1010 #[test]
1011 fn test_asctime() {
1012 let _reset = set_time_zone();
1013
1014 let time = Timespec::new(1234567890, 54321);
1015 let utc = at_utc(time);
1016 let local = at(time);
1017
1018 debug!("test_ctime: {} {}", utc.asctime(), local.asctime());
1019
1020 assert_eq!(utc.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string());
1021 assert_eq!(local.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1022 }
1023
1024 #[test]
1025 fn test_ctime() {
1026 let _reset = set_time_zone();
1027
1028 let time = Timespec::new(1234567890, 54321);
1029 let utc = at_utc(time);
1030 let local = at(time);
1031
1032 debug!("test_ctime: {} {}", utc.ctime(), local.ctime());
1033
1034 assert_eq!(utc.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1035 assert_eq!(local.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1036 }
1037
1038 #[test]
1039 fn test_strftime() {
1040 let _reset = set_time_zone();
1041
1042 let time = Timespec::new(1234567890, 54321);
1043 let utc = at_utc(time);
1044 let local = at(time);
1045
1046 assert_eq!(local.strftime("").unwrap().to_string(), "".to_string());
1047 assert_eq!(local.strftime("%A").unwrap().to_string(), "Friday".to_string());
1048 assert_eq!(local.strftime("%a").unwrap().to_string(), "Fri".to_string());
1049 assert_eq!(local.strftime("%B").unwrap().to_string(), "February".to_string());
1050 assert_eq!(local.strftime("%b").unwrap().to_string(), "Feb".to_string());
1051 assert_eq!(local.strftime("%C").unwrap().to_string(), "20".to_string());
1052 assert_eq!(local.strftime("%c").unwrap().to_string(),
1053 "Fri Feb 13 15:31:30 2009".to_string());
1054 assert_eq!(local.strftime("%D").unwrap().to_string(), "02/13/09".to_string());
1055 assert_eq!(local.strftime("%d").unwrap().to_string(), "13".to_string());
1056 assert_eq!(local.strftime("%e").unwrap().to_string(), "13".to_string());
1057 assert_eq!(local.strftime("%F").unwrap().to_string(), "2009-02-13".to_string());
1058 assert_eq!(local.strftime("%f").unwrap().to_string(), "000054321".to_string());
1059 assert_eq!(local.strftime("%G").unwrap().to_string(), "2009".to_string());
1060 assert_eq!(local.strftime("%g").unwrap().to_string(), "09".to_string());
1061 assert_eq!(local.strftime("%H").unwrap().to_string(), "15".to_string());
1062 assert_eq!(local.strftime("%h").unwrap().to_string(), "Feb".to_string());
1063 assert_eq!(local.strftime("%I").unwrap().to_string(), "03".to_string());
1064 assert_eq!(local.strftime("%j").unwrap().to_string(), "044".to_string());
1065 assert_eq!(local.strftime("%k").unwrap().to_string(), "15".to_string());
1066 assert_eq!(local.strftime("%l").unwrap().to_string(), " 3".to_string());
1067 assert_eq!(local.strftime("%M").unwrap().to_string(), "31".to_string());
1068 assert_eq!(local.strftime("%m").unwrap().to_string(), "02".to_string());
1069 assert_eq!(local.strftime("%n").unwrap().to_string(), "\n".to_string());
1070 assert_eq!(local.strftime("%P").unwrap().to_string(), "pm".to_string());
1071 assert_eq!(local.strftime("%p").unwrap().to_string(), "PM".to_string());
1072 assert_eq!(local.strftime("%R").unwrap().to_string(), "15:31".to_string());
1073 assert_eq!(local.strftime("%r").unwrap().to_string(), "03:31:30 PM".to_string());
1074 assert_eq!(local.strftime("%S").unwrap().to_string(), "30".to_string());
1075 assert_eq!(local.strftime("%s").unwrap().to_string(), "1234567890".to_string());
1076 assert_eq!(local.strftime("%T").unwrap().to_string(), "15:31:30".to_string());
1077 assert_eq!(local.strftime("%t").unwrap().to_string(), "\t".to_string());
1078 assert_eq!(local.strftime("%U").unwrap().to_string(), "06".to_string());
1079 assert_eq!(local.strftime("%u").unwrap().to_string(), "5".to_string());
1080 assert_eq!(local.strftime("%V").unwrap().to_string(), "07".to_string());
1081 assert_eq!(local.strftime("%v").unwrap().to_string(), "13-Feb-2009".to_string());
1082 assert_eq!(local.strftime("%W").unwrap().to_string(), "06".to_string());
1083 assert_eq!(local.strftime("%w").unwrap().to_string(), "5".to_string());
1084 assert_eq!(local.strftime("%X").unwrap().to_string(), "15:31:30".to_string());
1086 assert_eq!(local.strftime("%x").unwrap().to_string(), "02/13/09".to_string());
1088 assert_eq!(local.strftime("%Y").unwrap().to_string(), "2009".to_string());
1089 assert_eq!(local.strftime("%y").unwrap().to_string(), "09".to_string());
1090 assert_eq!(local.strftime("%Z").unwrap().to_string(), "".to_string());
1092 assert_eq!(local.strftime("%z").unwrap().to_string(), "-0800".to_string());
1093 assert_eq!(local.strftime("%+").unwrap().to_string(),
1094 "2009-02-13T15:31:30-08:00".to_string());
1095 assert_eq!(local.strftime("%%").unwrap().to_string(), "%".to_string());
1096
1097 let invalid_specifiers = ["%E", "%J", "%K", "%L", "%N", "%O", "%o", "%Q", "%q"];
1098 for &sp in invalid_specifiers.iter() {
1099 assert_eq!(local.strftime(sp).unwrap_err(),
1100 InvalidFormatSpecifier(sp[1..].chars().next().unwrap()));
1101 }
1102 assert_eq!(local.strftime("%").unwrap_err(), MissingFormatConverter);
1103 assert_eq!(local.strftime("%A %").unwrap_err(), MissingFormatConverter);
1104
1105 assert_eq!(local.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1106 assert_eq!(local.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1107 assert_eq!(local.rfc822z().to_string(), "Fri, 13 Feb 2009 15:31:30 -0800".to_string());
1108 assert_eq!(local.rfc3339().to_string(), "2009-02-13T15:31:30-08:00".to_string());
1109
1110 assert_eq!(utc.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string());
1111 assert_eq!(utc.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1112 assert_eq!(utc.rfc822().to_string(), "Fri, 13 Feb 2009 23:31:30 GMT".to_string());
1113 assert_eq!(utc.rfc822z().to_string(), "Fri, 13 Feb 2009 23:31:30 -0000".to_string());
1114 assert_eq!(utc.rfc3339().to_string(), "2009-02-13T23:31:30Z".to_string());
1115 }
1116
1117 #[test]
1118 fn test_timespec_eq_ord() {
1119 let a = &Timespec::new(-2, 1);
1120 let b = &Timespec::new(-1, 2);
1121 let c = &Timespec::new(1, 2);
1122 let d = &Timespec::new(2, 1);
1123 let e = &Timespec::new(2, 1);
1124
1125 assert!(d.eq(e));
1126 assert!(c.ne(e));
1127
1128 assert!(a.lt(b));
1129 assert!(b.lt(c));
1130 assert!(c.lt(d));
1131
1132 assert!(a.le(b));
1133 assert!(b.le(c));
1134 assert!(c.le(d));
1135 assert!(d.le(e));
1136 assert!(e.le(d));
1137
1138 assert!(b.ge(a));
1139 assert!(c.ge(b));
1140 assert!(d.ge(c));
1141 assert!(e.ge(d));
1142 assert!(d.ge(e));
1143
1144 assert!(b.gt(a));
1145 assert!(c.gt(b));
1146 assert!(d.gt(c));
1147 }
1148
1149 #[test]
1150 #[allow(deprecated)]
1151 fn test_timespec_hash() {
1152 use std::hash::{Hash, Hasher};
1153
1154 let c = &Timespec::new(3, 2);
1155 let d = &Timespec::new(2, 1);
1156 let e = &Timespec::new(2, 1);
1157
1158 let mut hasher = ::std::hash::SipHasher::new();
1159
1160 let d_hash:u64 = {
1161 d.hash(&mut hasher);
1162 hasher.finish()
1163 };
1164
1165 hasher = ::std::hash::SipHasher::new();
1166
1167 let e_hash:u64 = {
1168 e.hash(&mut hasher);
1169 hasher.finish()
1170 };
1171
1172 hasher = ::std::hash::SipHasher::new();
1173
1174 let c_hash:u64 = {
1175 c.hash(&mut hasher);
1176 hasher.finish()
1177 };
1178
1179 assert_eq!(d_hash, e_hash);
1180 assert!(c_hash != e_hash);
1181 }
1182
1183 #[test]
1184 fn test_timespec_add() {
1185 let a = Timespec::new(1, 2);
1186 let b = Duration::seconds(2) + Duration::nanoseconds(3);
1187 let c = a + b;
1188 assert_eq!(c.sec, 3);
1189 assert_eq!(c.nsec, 5);
1190
1191 let p = Timespec::new(1, super::NSEC_PER_SEC - 2);
1192 let q = Duration::seconds(2) + Duration::nanoseconds(2);
1193 let r = p + q;
1194 assert_eq!(r.sec, 4);
1195 assert_eq!(r.nsec, 0);
1196
1197 let u = Timespec::new(1, super::NSEC_PER_SEC - 2);
1198 let v = Duration::seconds(2) + Duration::nanoseconds(3);
1199 let w = u + v;
1200 assert_eq!(w.sec, 4);
1201 assert_eq!(w.nsec, 1);
1202
1203 let k = Timespec::new(1, 0);
1204 let l = Duration::nanoseconds(-1);
1205 let m = k + l;
1206 assert_eq!(m.sec, 0);
1207 assert_eq!(m.nsec, 999_999_999);
1208 }
1209
1210 #[test]
1211 fn test_timespec_sub() {
1212 let a = Timespec::new(2, 3);
1213 let b = Timespec::new(1, 2);
1214 let c = a - b;
1215 assert_eq!(c.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 + 1));
1216
1217 let p = Timespec::new(2, 0);
1218 let q = Timespec::new(1, 2);
1219 let r = p - q;
1220 assert_eq!(r.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 - 2));
1221
1222 let u = Timespec::new(1, 2);
1223 let v = Timespec::new(2, 3);
1224 let w = u - v;
1225 assert_eq!(w.num_nanoseconds(), Some(-super::NSEC_PER_SEC as i64 - 1));
1226 }
1227
1228 #[test]
1229 fn test_time_sub() {
1230 let a = ::now();
1231 let b = at(a.to_timespec() + Duration::seconds(5));
1232 let c = b - a;
1233 assert_eq!(c.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 * 5));
1234 }
1235
1236 #[test]
1237 fn test_steadytime_sub() {
1238 let a = SteadyTime::now();
1239 let b = a + Duration::seconds(1);
1240 assert_eq!(b - a, Duration::seconds(1));
1241 assert_eq!(a - b, Duration::seconds(-1));
1242 }
1243
1244 #[test]
1245 fn test_date_before_1970() {
1246 let early = strptime("1901-01-06", "%F").unwrap();
1247 let late = strptime("2000-01-01", "%F").unwrap();
1248 assert!(early < late);
1249 }
1250
1251 #[test]
1252 fn test_dst() {
1253 let _reset = set_time_zone_london_dst();
1254 let utc_in_feb = strptime("2015-02-01Z", "%F%z").unwrap();
1255 let utc_in_jun = strptime("2015-06-01Z", "%F%z").unwrap();
1256 let utc_in_nov = strptime("2015-11-01Z", "%F%z").unwrap();
1257 let local_in_feb = utc_in_feb.to_local();
1258 let local_in_jun = utc_in_jun.to_local();
1259 let local_in_nov = utc_in_nov.to_local();
1260
1261 assert_eq!(local_in_feb.tm_mon, 1);
1262 assert_eq!(local_in_feb.tm_hour, 0);
1263 assert_eq!(local_in_feb.tm_utcoff, 0);
1264 assert_eq!(local_in_feb.tm_isdst, 0);
1265
1266 assert_eq!(local_in_jun.tm_mon, 5);
1267 assert_eq!(local_in_jun.tm_hour, 1);
1268 assert_eq!(local_in_jun.tm_utcoff, 3600);
1269 assert_eq!(local_in_jun.tm_isdst, 1);
1270
1271 assert_eq!(local_in_nov.tm_mon, 10);
1272 assert_eq!(local_in_nov.tm_hour, 0);
1273 assert_eq!(local_in_nov.tm_utcoff, 0);
1274 assert_eq!(local_in_nov.tm_isdst, 0)
1275 }
1276}