time_preview/
lib.rs

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.
4//
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.
10
11//! Simple time handling.
12//!
13//! # Usage
14//!
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`.
17//!
18//! ```toml
19//! [dependencies]
20//! time = "0.1"
21//! ```
22//!
23//! And this in your crate root:
24//!
25//! ```rust
26//! extern crate time;
27//! ```
28//!
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.
32
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(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/// A record specifying a time value in seconds and nanoseconds, where
69/// nanoseconds represent the offset from the given second.
70///
71/// For example a timespec of 1.2 seconds after the beginning of the epoch would
72/// be represented as {sec: 1, nsec: 200000000}.
73#[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 }
76/*
77 * Timespec assumes that pre-epoch Timespecs have negative sec and positive
78 * nsec fields. Darwin's and Linux's struct timespec functions handle pre-
79 * epoch timestamps using a "two steps back, one step forward" representation,
80 * though the man pages do not actually document this. For example, the time
81 * -1.2 seconds before the epoch is represented by `Timespec { sec: -2_i64,
82 * nsec: 800_000_000 }`.
83 */
84impl 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        // It is safe to unwrap the nanoseconds, because there cannot be
97        // more than one second left, which fits in i64 and in i32.
98        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        // It is safe to unwrap the nanoseconds, because there cannot be
119        // more than one second left, which fits in i64 and in i32.
120        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
145/**
146 * Returns the current time as a `timespec` containing the seconds and
147 * nanoseconds since 1970-01-01T00:00:00Z.
148 */
149pub fn get_time() -> Timespec {
150    let (sec, nsec) = sys::get_time();
151    Timespec::new(sec, nsec)
152}
153
154
155/**
156 * Returns the current value of a high-resolution performance counter
157 * in nanoseconds since an unspecified epoch.
158 */
159#[inline]
160pub fn precise_time_ns() -> u64 {
161    sys::get_precise_ns()
162}
163
164
165/**
166 * Returns the current value of a high-resolution performance counter
167 * in seconds since an unspecified epoch.
168 */
169pub fn precise_time_s() -> f64 {
170    return (precise_time_ns() as f64) / 1000000000.;
171}
172
173/// An opaque structure representing a moment in time.
174///
175/// The only operation that can be performed on a `PreciseTime` is the
176/// calculation of the `Duration` of time that lies between them.
177///
178/// # Examples
179///
180/// Repeatedly call a function for 1 second:
181///
182/// ```rust
183/// use time::{Duration, PreciseTime};
184/// # fn do_some_work() {}
185///
186/// let start = PreciseTime::now();
187///
188/// while start.to(PreciseTime::now()) < Duration::seconds(1) {
189///     do_some_work();
190/// }
191/// ```
192#[derive(Copy, Clone)]
193pub struct PreciseTime(u64);
194
195impl PreciseTime {
196    /// Returns a `PreciseTime` representing the current moment in time.
197    pub fn now() -> PreciseTime {
198        PreciseTime(precise_time_ns())
199    }
200
201    /// Returns a `Duration` representing the span of time from the value of
202    /// `self` to the value of `later`.
203    ///
204    /// # Notes
205    ///
206    /// If `later` represents a time before `self`, the result of this method
207    /// is unspecified.
208    ///
209    /// If `later` represents a time more than 293 years after `self`, the
210    /// result of this method is unspecified.
211    #[inline]
212    pub fn to(&self, later: PreciseTime) -> Duration {
213        // NB: even if later is less than self due to overflow, this will work
214        // since the subtraction will underflow properly as well.
215        //
216        // We could deal with the overflow when casting to an i64, but all that
217        // gets us is the ability to handle intervals of up to 584 years, which
218        // seems not very useful :)
219        Duration::nanoseconds((later.0 - self.0) as i64)
220    }
221}
222
223/// A structure representing a moment in time.
224///
225/// `SteadyTime`s are generated by a "steady" clock, that is, a clock which
226/// never experiences discontinuous jumps and for which time always flows at
227/// the same rate.
228///
229/// # Examples
230///
231/// Repeatedly call a function for 1 second:
232///
233/// ```rust
234/// # use time::{Duration, SteadyTime};
235/// # fn do_some_work() {}
236/// let start = SteadyTime::now();
237///
238/// while SteadyTime::now() - start < Duration::seconds(1) {
239///     do_some_work();
240/// }
241/// ```
242#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)]
243pub struct SteadyTime(sys::SteadyTime);
244
245impl SteadyTime {
246    /// Returns a `SteadyTime` representing the current moment in time.
247    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        // TODO: needs a display customization
255        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/// Holds a calendar date and time broken down into its components (year, month,
294/// day, and so on), also called a broken-down time value.
295// FIXME: use c_int instead of i32?
296#[repr(C)]
297#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
298#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
299pub struct Tm {
300    /// Seconds after the minute - [0, 60]
301    pub tm_sec: i32,
302
303    /// Minutes after the hour - [0, 59]
304    pub tm_min: i32,
305
306    /// Hours after midnight - [0, 23]
307    pub tm_hour: i32,
308
309    /// Day of the month - [1, 31]
310    pub tm_mday: i32,
311
312    /// Months since January - [0, 11]
313    pub tm_mon: i32,
314
315    /// Years since 1900
316    pub tm_year: i32,
317
318    /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday.
319    pub tm_wday: i32,
320
321    /// Days since January 1 - [0, 365]
322    pub tm_yday: i32,
323
324    /// Daylight Saving Time flag.
325    ///
326    /// This value is positive if Daylight Saving Time is in effect, zero if
327    /// Daylight Saving Time is not in effect, and negative if this information
328    /// is not available.
329    pub tm_isdst: i32,
330
331    /// Identifies the time zone that was used to compute this broken-down time
332    /// value, including any adjustment for Daylight Saving Time. This is the
333    /// number of seconds east of UTC. For example, for U.S. Pacific Daylight
334    /// Time, the value is `-7*60*60 = -25200`.
335    pub tm_utcoff: i32,
336
337    /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1]
338    pub tm_nsec: i32,
339}
340
341impl Add<Duration> for Tm {
342    type Output = Tm;
343
344    /// The resulting Tm is in UTC.
345    // FIXME:  The resulting Tm should have the same timezone as `self`;
346    // however, we need a function such as `at_tm(clock: Timespec, offset: i32)`
347    // for this.
348    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    /// The resulting Tm is in UTC.
357    // FIXME:  The resulting Tm should have the same timezone as `self`;
358    // however, we need a function such as `at_tm(clock: Timespec, offset: i32)`
359    // for this.
360    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
401/// Returns the specified time in UTC
402pub 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
410/// Returns the current time in UTC
411pub fn now_utc() -> Tm {
412    at_utc(get_time())
413}
414
415/// Returns the specified time in the local timezone
416pub 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
424/// Returns the current time in the local timezone
425pub fn now() -> Tm {
426    at(get_time())
427}
428
429impl Tm {
430    /// Convert time to the seconds from January 1, 1970
431    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    /// Convert time to the local timezone
441    pub fn to_local(&self) -> Tm {
442        at(self.to_timespec())
443    }
444
445    /// Convert time to the UTC
446    pub fn to_utc(&self) -> Tm {
447        match self.tm_utcoff {
448            0 => *self,
449            _ => at_utc(self.to_timespec())
450        }
451    }
452
453    /**
454     * Returns a TmFmt that outputs according to the `asctime` format in ISO
455     * C, in the local timezone.
456     *
457     * Example: "Thu Jan  1 00:00:00 1970"
458     */
459    pub fn ctime(&self) -> TmFmt {
460        TmFmt {
461            tm: self,
462            format: Fmt::Ctime,
463        }
464    }
465
466    /**
467     * Returns a TmFmt that outputs according to the `asctime` format in ISO
468     * C.
469     *
470     * Example: "Thu Jan  1 00:00:00 1970"
471     */
472    pub fn asctime(&self) -> TmFmt {
473        TmFmt {
474            tm: self,
475            format: Fmt::Str("%c"),
476        }
477    }
478
479    /// Formats the time according to the format string.
480    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    /**
488     * Returns a TmFmt that outputs according to RFC 822.
489     *
490     * local: "Thu, 22 Mar 2012 07:53:18 PST"
491     * utc:   "Thu, 22 Mar 2012 14:53:18 GMT"
492     */
493    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    /**
506     * Returns a TmFmt that outputs according to RFC 822 with Zulu time.
507     *
508     * local: "Thu, 22 Mar 2012 07:53:18 -0700"
509     * utc:   "Thu, 22 Mar 2012 14:53:18 -0000"
510     */
511    pub fn rfc822z(&self) -> TmFmt {
512        TmFmt {
513            tm: self,
514            format: Fmt::Str("%a, %d %b %Y %T %z"),
515        }
516    }
517
518    /**
519     * Returns a TmFmt that outputs according to RFC 3339. RFC 3339 is
520     * compatible with ISO 8601.
521     *
522     * local: "2012-02-22T07:53:18-07:00"
523     * utc:   "2012-02-22T14:53:18Z"
524     */
525    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/// A wrapper around a `Tm` and format string that implements Display.
589#[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
643/// Formats the time according to the format string.
644pub 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        // Lock manages current timezone because some tests require LA some
665        // London
666        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; // 2012-01-01T00:00:00Z
698        static SOME_FUTURE_DATE: i64 = 1577836800i64; // 2020-01-01T00:00:00Z
699
700        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                // oneway tests are used when reformatting the parsed Tm
865                // back into a string can generate a different string
866                // from the original (i.e. leading zeroes)
867                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")); // FIXME (#2350): flesh out
947        assert!(test("11", "%I")); // FIXME (#2350): flesh out
948        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        // Test for #7256
993        assert_eq!(strptime("360", "%Y-%m-%d"), Err(InvalidYear));
994
995        // Test for epoch seconds parsing
996        {
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        // FIXME (#2350): support locale
1085        assert_eq!(local.strftime("%X").unwrap().to_string(), "15:31:30".to_string());
1086        // FIXME (#2350): support locale
1087        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        // FIXME (#2350): support locale
1091        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}