chrono/time/
mod.rs

1#![allow(missing_docs)]
2// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
3// file at the top-level directory of this distribution and at
4// http://rust-lang.org/COPYRIGHT.
5//
6// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
7// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
9// option. This file may not be copied, modified, or distributed
10// except according to those terms.
11
12//! Simple time handling.
13//! This crate uses the same syntax for format strings as the
14//! [`strftime()`](http://man7.org/linux/man-pages/man3/strftime.3.html)
15//! function from the C standard library.
16
17#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
18       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
19       html_root_url = "https://doc.rust-lang.org/time/")]
20#![allow(trivial_numeric_casts, ellipsis_inclusive_range_patterns)]
21
22mod display;
23mod duration;
24mod parse;
25mod sys;
26
27use std::cmp::Ordering;
28use std::error::Error;
29use std::fmt;
30use std::ops::{Add, Sub};
31
32pub use self::duration::{Duration, OutOfRangeError};
33
34use self::ParseError::{InvalidDay, InvalidDayOfMonth, InvalidDayOfWeek,
35                       InvalidDayOfYear, InvalidFormatSpecifier, InvalidHour,
36                       InvalidMinute, InvalidMonth, InvalidSecond, InvalidTime,
37                       InvalidYear, InvalidZoneOffset, InvalidSecondsSinceEpoch,
38                       MissingFormatConverter, UnexpectedCharacter};
39
40pub use self::parse::strptime;
41
42pub static NSEC_PER_SEC: i32 = 1_000_000_000;
43
44/// A record specifying a time value in seconds and nanoseconds, where
45/// nanoseconds represent the offset from the given second.
46///
47/// For example a timespec of 1.2 seconds after the beginning of the epoch would
48/// be represented as {sec: 1, nsec: 200000000}.
49#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
50#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
51pub struct Timespec { pub sec: i64, pub nsec: i32 }
52/*
53 * Timespec assumes that pre-epoch Timespecs have negative sec and positive
54 * nsec fields. Darwin's and Linux's struct timespec functions handle pre-
55 * epoch timestamps using a "two steps back, one step forward" representation,
56 * though the man pages do not actually document this. For example, the time
57 * -1.2 seconds before the epoch is represented by `Timespec { sec: -2_i64,
58 * nsec: 800_000_000 }`.
59 */
60impl Timespec {
61    pub fn new(sec: i64, nsec: i32) -> Timespec {
62        assert!(nsec >= 0 && nsec < NSEC_PER_SEC);
63        Timespec { sec: sec, nsec: nsec }
64    }
65}
66
67impl Add<Duration> for Timespec {
68    type Output = Timespec;
69
70    fn add(self, other: Duration) -> Timespec {
71        let d_sec = other.num_seconds();
72        // It is safe to unwrap the nanoseconds, because there cannot be
73        // more than one second left, which fits in i64 and in i32.
74        let d_nsec = (other - Duration::seconds(d_sec))
75                     .num_nanoseconds().unwrap() as i32;
76        let mut sec = self.sec + d_sec;
77        let mut nsec = self.nsec + d_nsec;
78        if nsec >= NSEC_PER_SEC {
79            nsec -= NSEC_PER_SEC;
80            sec += 1;
81        } else if nsec < 0 {
82            nsec += NSEC_PER_SEC;
83            sec -= 1;
84        }
85        Timespec::new(sec, nsec)
86    }
87}
88
89impl Sub<Duration> for Timespec {
90    type Output = Timespec;
91
92    fn sub(self, other: Duration) -> Timespec {
93        let d_sec = other.num_seconds();
94        // It is safe to unwrap the nanoseconds, because there cannot be
95        // more than one second left, which fits in i64 and in i32.
96        let d_nsec = (other - Duration::seconds(d_sec))
97                     .num_nanoseconds().unwrap() as i32;
98        let mut sec = self.sec - d_sec;
99        let mut nsec = self.nsec - d_nsec;
100        if nsec >= NSEC_PER_SEC {
101            nsec -= NSEC_PER_SEC;
102            sec += 1;
103        } else if nsec < 0 {
104            nsec += NSEC_PER_SEC;
105            sec -= 1;
106        }
107        Timespec::new(sec, nsec)
108    }
109}
110
111impl Sub<Timespec> for Timespec {
112    type Output = Duration;
113
114    fn sub(self, other: Timespec) -> Duration {
115        let sec = self.sec - other.sec;
116        let nsec = self.nsec - other.nsec;
117        Duration::seconds(sec) + Duration::nanoseconds(nsec as i64)
118    }
119}
120
121/**
122 * Returns the current time as a `timespec` containing the seconds and
123 * nanoseconds since 1970-01-01T00:00:00Z.
124 */
125pub fn get_time() -> Timespec {
126    let (sec, nsec) = sys::get_time();
127    Timespec::new(sec, nsec)
128}
129
130
131/**
132 * Returns the current value of a high-resolution performance counter
133 * in nanoseconds since an unspecified epoch.
134 */
135#[inline]
136pub fn precise_time_ns() -> u64 {
137    sys::get_precise_ns()
138}
139
140
141/**
142 * Returns the current value of a high-resolution performance counter
143 * in seconds since an unspecified epoch.
144 */
145#[allow(unused)]
146pub fn precise_time_s() -> f64 {
147    return (precise_time_ns() as f64) / 1000000000.;
148}
149
150/// An opaque structure representing a moment in time.
151///
152/// The only operation that can be performed on a `PreciseTime` is the
153/// calculation of the `Duration` of time that lies between them.
154///
155/// # Examples
156///
157/// Repeatedly call a function for 1 second:
158///
159/// ```rust
160/// use chrono::{Duration, PreciseTime};
161/// # fn do_some_work() {}
162///
163/// let start = PreciseTime::now();
164///
165/// while start.to(PreciseTime::now()) < Duration::seconds(1) {
166///     do_some_work();
167/// }
168/// ```
169#[derive(Debug, Copy, Clone)]
170pub struct PreciseTime(u64);
171
172impl PreciseTime {
173    /// Returns a `PreciseTime` representing the current moment in time.
174    pub fn now() -> PreciseTime {
175        PreciseTime(precise_time_ns())
176    }
177
178    /// Returns a `Duration` representing the span of time from the value of
179    /// `self` to the value of `later`.
180    ///
181    /// # Notes
182    ///
183    /// If `later` represents a time before `self`, the result of this method
184    /// is unspecified.
185    ///
186    /// If `later` represents a time more than 293 years after `self`, the
187    /// result of this method is unspecified.
188    #[inline]
189    pub fn to(&self, later: PreciseTime) -> Duration {
190        // NB: even if later is less than self due to overflow, this will work
191        // since the subtraction will underflow properly as well.
192        //
193        // We could deal with the overflow when casting to an i64, but all that
194        // gets us is the ability to handle intervals of up to 584 years, which
195        // seems not very useful :)
196        Duration::nanoseconds((later.0 - self.0) as i64)
197    }
198}
199
200/// A structure representing a moment in time.
201///
202/// `SteadyTime`s are generated by a "steady" clock, that is, a clock which
203/// never experiences discontinuous jumps and for which time always flows at
204/// the same rate.
205///
206/// # Examples
207///
208/// Repeatedly call a function for 1 second:
209///
210/// ```rust
211/// # use chrono::{Duration, SteadyTime};
212/// # fn do_some_work() {}
213/// let start = SteadyTime::now();
214///
215/// while SteadyTime::now() - start < Duration::seconds(1) {
216///     do_some_work();
217/// }
218/// ```
219#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)]
220pub struct SteadyTime(sys::SteadyTime);
221
222impl SteadyTime {
223    /// Returns a `SteadyTime` representing the current moment in time.
224    pub fn now() -> SteadyTime {
225        SteadyTime(sys::SteadyTime::now())
226    }
227}
228
229impl fmt::Display for SteadyTime {
230    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
231        // TODO: needs a display customization
232        fmt::Debug::fmt(self, fmt)
233    }
234}
235
236impl Sub for SteadyTime {
237    type Output = Duration;
238
239    fn sub(self, other: SteadyTime) -> Duration {
240        self.0 - other.0
241    }
242}
243
244impl Sub<Duration> for SteadyTime {
245    type Output = SteadyTime;
246
247    fn sub(self, other: Duration) -> SteadyTime {
248        SteadyTime(self.0 - other)
249    }
250}
251
252impl Add<Duration> for SteadyTime {
253    type Output = SteadyTime;
254
255    fn add(self, other: Duration) -> SteadyTime {
256        SteadyTime(self.0 + other)
257    }
258}
259
260#[cfg(not(windows))]
261#[allow(unused)]
262pub fn tzset() {
263    extern { fn tzset(); }
264    unsafe { tzset() }
265}
266
267
268#[cfg(windows)]
269pub fn tzset() {}
270
271/// Holds a calendar date and time broken down into its components (year, month,
272/// day, and so on), also called a broken-down time value.
273// FIXME: use c_int instead of i32?
274#[repr(C)]
275#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
276#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
277pub struct Tm {
278    /// Seconds after the minute - [0, 60]
279    pub tm_sec: i32,
280
281    /// Minutes after the hour - [0, 59]
282    pub tm_min: i32,
283
284    /// Hours after midnight - [0, 23]
285    pub tm_hour: i32,
286
287    /// Day of the month - [1, 31]
288    pub tm_mday: i32,
289
290    /// Months since January - [0, 11]
291    pub tm_mon: i32,
292
293    /// Years since 1900
294    pub tm_year: i32,
295
296    /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday.
297    pub tm_wday: i32,
298
299    /// Days since January 1 - [0, 365]
300    pub tm_yday: i32,
301
302    /// Daylight Saving Time flag.
303    ///
304    /// This value is positive if Daylight Saving Time is in effect, zero if
305    /// Daylight Saving Time is not in effect, and negative if this information
306    /// is not available.
307    pub tm_isdst: i32,
308
309    /// Identifies the time zone that was used to compute this broken-down time
310    /// value, including any adjustment for Daylight Saving Time. This is the
311    /// number of seconds east of UTC. For example, for U.S. Pacific Daylight
312    /// Time, the value is `-7*60*60 = -25200`.
313    pub tm_utcoff: i32,
314
315    /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1]
316    pub tm_nsec: i32,
317}
318
319impl Add<Duration> for Tm {
320    type Output = Tm;
321
322    /// The resulting Tm is in UTC.
323    // FIXME:  The resulting Tm should have the same timezone as `self`;
324    // however, we need a function such as `at_tm(clock: Timespec, offset: i32)`
325    // for this.
326    fn add(self, other: Duration) -> Tm {
327        at_utc(self.to_timespec() + other)
328    }
329}
330
331impl Sub<Duration> for Tm {
332    type Output = Tm;
333
334    /// The resulting Tm is in UTC.
335    // FIXME:  The resulting Tm should have the same timezone as `self`;
336    // however, we need a function such as `at_tm(clock: Timespec, offset: i32)`
337    // for this.
338    fn sub(self, other: Duration) -> Tm {
339        at_utc(self.to_timespec() - other)
340    }
341}
342
343impl Sub<Tm> for Tm {
344    type Output = Duration;
345
346    fn sub(self, other: Tm) -> Duration {
347        self.to_timespec() - other.to_timespec()
348    }
349}
350
351impl PartialOrd for Tm {
352    fn partial_cmp(&self, other: &Tm) -> Option<Ordering> {
353        self.to_timespec().partial_cmp(&other.to_timespec())
354    }
355}
356
357impl Ord for Tm {
358    fn cmp(&self, other: &Tm) -> Ordering {
359        self.to_timespec().cmp(&other.to_timespec())
360    }
361}
362
363pub fn empty_tm() -> Tm {
364    Tm {
365        tm_sec: 0,
366        tm_min: 0,
367        tm_hour: 0,
368        tm_mday: 0,
369        tm_mon: 0,
370        tm_year: 0,
371        tm_wday: 0,
372        tm_yday: 0,
373        tm_isdst: 0,
374        tm_utcoff: 0,
375        tm_nsec: 0,
376    }
377}
378
379/// Returns the specified time in UTC
380pub fn at_utc(clock: Timespec) -> Tm {
381    let Timespec { sec, nsec } = clock;
382    let mut tm = empty_tm();
383    sys::time_to_utc_tm(sec, &mut tm);
384    tm.tm_nsec = nsec;
385    tm
386}
387
388/// Returns the current time in UTC
389#[allow(unused)]
390pub fn now_utc() -> Tm {
391    at_utc(get_time())
392}
393
394/// Returns the specified time in the local timezone
395pub fn at(clock: Timespec) -> Tm {
396    let Timespec { sec, nsec } = clock;
397    let mut tm = empty_tm();
398    sys::time_to_local_tm(sec, &mut tm);
399    tm.tm_nsec = nsec;
400    tm
401}
402
403/// Returns the current time in the local timezone
404pub fn now() -> Tm {
405    at(get_time())
406}
407
408impl Tm {
409    /// Convert time to the seconds from January 1, 1970
410    pub fn to_timespec(&self) -> Timespec {
411        let sec = match self.tm_utcoff {
412            0 => sys::utc_tm_to_time(self),
413            _ => sys::local_tm_to_time(self)
414        };
415
416        Timespec::new(sec, self.tm_nsec)
417    }
418
419    /// Convert time to the local timezone
420    pub fn to_local(&self) -> Tm {
421        at(self.to_timespec())
422    }
423
424    /// Convert time to the UTC
425    #[allow(unused)]
426    pub fn to_utc(&self) -> Tm {
427        match self.tm_utcoff {
428            0 => *self,
429            _ => at_utc(self.to_timespec())
430        }
431    }
432
433    /**
434     * Returns a TmFmt that outputs according to the `asctime` format in ISO
435     * C, in the local timezone.
436     *
437     * Example: "Thu Jan  1 00:00:00 1970"
438     */
439    #[allow(unused)]
440    pub fn ctime(&self) -> TmFmt {
441        TmFmt {
442            tm: self,
443            format: Fmt::Ctime,
444        }
445    }
446
447    /**
448     * Returns a TmFmt that outputs according to the `asctime` format in ISO
449     * C.
450     *
451     * Example: "Thu Jan  1 00:00:00 1970"
452     */
453    pub fn asctime(&self) -> TmFmt {
454        TmFmt {
455            tm: self,
456            format: Fmt::Str("%c"),
457        }
458    }
459
460    /// Formats the time according to the format string.
461    #[allow(unused)]
462    pub fn strftime<'a>(&'a self, format: &'a str) -> Result<TmFmt<'a>, ParseError> {
463        validate_format(TmFmt {
464            tm: self,
465            format: Fmt::Str(format),
466        })
467    }
468
469    /**
470     * Returns a TmFmt that outputs according to RFC 822.
471     *
472     * local: "Thu, 22 Mar 2012 07:53:18 PST"
473     * utc:   "Thu, 22 Mar 2012 14:53:18 GMT"
474     */
475    #[allow(unused)]
476    pub fn rfc822(&self) -> TmFmt {
477        let fmt = if self.tm_utcoff == 0 {
478            "%a, %d %b %Y %T GMT"
479        } else {
480            "%a, %d %b %Y %T %Z"
481        };
482        TmFmt {
483            tm: self,
484            format: Fmt::Str(fmt),
485        }
486    }
487
488    /**
489     * Returns a TmFmt that outputs according to RFC 822 with Zulu time.
490     *
491     * local: "Thu, 22 Mar 2012 07:53:18 -0700"
492     * utc:   "Thu, 22 Mar 2012 14:53:18 -0000"
493     */
494    #[allow(unused)]
495    pub fn rfc822z(&self) -> TmFmt {
496        TmFmt {
497            tm: self,
498            format: Fmt::Str("%a, %d %b %Y %T %z"),
499        }
500    }
501
502    /**
503     * Returns a TmFmt that outputs according to RFC 3339. RFC 3339 is
504     * compatible with ISO 8601.
505     *
506     * local: "2012-02-22T07:53:18-07:00"
507     * utc:   "2012-02-22T14:53:18Z"
508     */
509    pub fn rfc3339<'a>(&'a self) -> TmFmt {
510        TmFmt {
511            tm: self,
512            format: Fmt::Rfc3339,
513        }
514    }
515}
516
517#[derive(Copy, PartialEq, Debug, Clone)]
518pub enum ParseError {
519    InvalidSecond,
520    InvalidMinute,
521    InvalidHour,
522    InvalidDay,
523    InvalidMonth,
524    InvalidYear,
525    InvalidDayOfWeek,
526    InvalidDayOfMonth,
527    InvalidDayOfYear,
528    InvalidZoneOffset,
529    InvalidTime,
530    InvalidSecondsSinceEpoch,
531    MissingFormatConverter,
532    InvalidFormatSpecifier(char),
533    UnexpectedCharacter(char, char),
534}
535
536impl fmt::Display for ParseError {
537    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
538        match *self {
539            InvalidFormatSpecifier(ch) => {
540                write!(f, "{}: %{}", self.description(), ch)
541            }
542            UnexpectedCharacter(a, b) => {
543                write!(f, "expected: `{}`, found: `{}`", a, b)
544            }
545            _ => write!(f, "{}", self.description())
546        }
547    }
548}
549
550impl Error for ParseError {
551    fn description(&self) -> &str {
552        match *self {
553            InvalidSecond => "Invalid second.",
554            InvalidMinute => "Invalid minute.",
555            InvalidHour => "Invalid hour.",
556            InvalidDay => "Invalid day.",
557            InvalidMonth => "Invalid month.",
558            InvalidYear => "Invalid year.",
559            InvalidDayOfWeek => "Invalid day of the week.",
560            InvalidDayOfMonth => "Invalid day of the month.",
561            InvalidDayOfYear => "Invalid day of the year.",
562            InvalidZoneOffset => "Invalid zone offset.",
563            InvalidTime => "Invalid time.",
564            InvalidSecondsSinceEpoch => "Invalid seconds since epoch.",
565            MissingFormatConverter => "missing format converter after `%`",
566            InvalidFormatSpecifier(..) => "invalid format specifier",
567            UnexpectedCharacter(..) => "Unexpected character.",
568        }
569    }
570}
571
572/// A wrapper around a `Tm` and format string that implements Display.
573#[derive(Debug)]
574pub struct TmFmt<'a> {
575    tm: &'a Tm,
576    format: Fmt<'a>
577}
578
579#[derive(Debug)]
580enum Fmt<'a> {
581    Str(&'a str),
582    Rfc3339,
583    Ctime,
584}
585
586fn validate_format<'a>(fmt: TmFmt<'a>) -> Result<TmFmt<'a>, ParseError> {
587
588    match (fmt.tm.tm_wday, fmt.tm.tm_mon) {
589        (0...6, 0...11) => (),
590        (_wday, 0...11) => return Err(InvalidDayOfWeek),
591        (0...6, _mon) => return Err(InvalidMonth),
592        _ => return Err(InvalidDay)
593    }
594    match fmt.format {
595        Fmt::Str(ref s) => {
596            let mut chars = s.chars();
597            loop {
598                match chars.next() {
599                    Some('%') => {
600                        match chars.next() {
601                            Some('A') | Some('a') | Some('B') | Some('b') |
602                            Some('C') | Some('c') | Some('D') | Some('d') |
603                            Some('e') | Some('F') | Some('f') | Some('G') |
604                            Some('g') | Some('H') | Some('h') | Some('I') |
605                            Some('j') | Some('k') | Some('l') | Some('M') |
606                            Some('m') | Some('n') | Some('P') | Some('p') |
607                            Some('R') | Some('r') | Some('S') | Some('s') |
608                            Some('T') | Some('t') | Some('U') | Some('u') |
609                            Some('V') | Some('v') | Some('W') | Some('w') |
610                            Some('X') | Some('x') | Some('Y') | Some('y') |
611                            Some('Z') | Some('z') | Some('+') | Some('%') => (),
612
613                            Some(c) => return Err(InvalidFormatSpecifier(c)),
614                            None => return Err(MissingFormatConverter),
615                        }
616                    },
617                    None => break,
618                    _ => ()
619                }
620            }
621        },
622        _ => ()
623    }
624    Ok(fmt)
625}
626
627/// Formats the time according to the format string.
628#[allow(unused)]
629pub fn strftime(format: &str, tm: &Tm) -> Result<String, ParseError> {
630    tm.strftime(format).map(|fmt| fmt.to_string())
631}
632
633#[cfg(test)]
634mod tests {
635    use ::time::sys;
636
637    use super::{Timespec, get_time, precise_time_ns, precise_time_s,
638                at_utc, at, strptime, PreciseTime, SteadyTime, ParseError, Duration};
639    use super::ParseError::{InvalidTime, InvalidYear, MissingFormatConverter,
640                            InvalidFormatSpecifier};
641
642    use std::sync::{Once, Mutex, MutexGuard, LockResult};
643    use std::mem;
644
645    struct TzReset {
646        _tzreset: sys::TzReset,
647        _lock: LockResult<MutexGuard<'static, ()>>,
648    }
649
650    fn set_time_zone_la_or_london(london: bool) -> TzReset {
651        // Lock manages current timezone because some tests require LA some
652        // London
653        static mut LOCK: *mut Mutex<()> = 0 as *mut _;
654        static INIT: Once = Once::new();
655
656        unsafe {
657            INIT.call_once(|| {
658                LOCK = mem::transmute(Box::new(Mutex::new(())));
659            });
660
661            let timezone_lock = (*LOCK).lock();
662            let reset_func = if london {
663                sys::set_london_with_dst_time_zone()
664            } else {
665                sys::set_los_angeles_time_zone()
666            };
667            TzReset {
668                _lock: timezone_lock,
669                _tzreset: reset_func,
670            }
671        }
672    }
673
674    fn set_time_zone() -> TzReset {
675        set_time_zone_la_or_london(false)
676    }
677
678    fn set_time_zone_london_dst() -> TzReset {
679        set_time_zone_la_or_london(true)
680    }
681
682    #[test]
683    fn test_get_time() {
684        static SOME_RECENT_DATE: i64 = 1325376000i64; // 2012-01-01T00:00:00Z
685        static SOME_FUTURE_DATE: i64 = 1577836800i64; // 2020-01-01T00:00:00Z
686
687        let tv1 = get_time();
688        debug!("tv1={} sec + {} nsec", tv1.sec, tv1.nsec);
689
690        assert!(tv1.sec > SOME_RECENT_DATE);
691        assert!(tv1.nsec < 1000000000i32);
692
693        let tv2 = get_time();
694        debug!("tv2={} sec + {} nsec", tv2.sec, tv2.nsec);
695
696        assert!(tv2.sec >= tv1.sec);
697        assert!(tv2.sec < SOME_FUTURE_DATE);
698        assert!(tv2.nsec < 1000000000i32);
699        if tv2.sec == tv1.sec {
700            assert!(tv2.nsec >= tv1.nsec);
701        }
702    }
703
704    #[test]
705    fn test_precise_time() {
706        let s0 = precise_time_s();
707        debug!("s0={} sec", s0);
708        assert!(s0 > 0.);
709
710        let ns0 = precise_time_ns();
711        let ns1 = precise_time_ns();
712        debug!("ns0={} ns", ns0);
713        debug!("ns1={} ns", ns1);
714        assert!(ns1 >= ns0);
715
716        let ns2 = precise_time_ns();
717        debug!("ns2={} ns", ns2);
718        assert!(ns2 >= ns1);
719    }
720
721    #[test]
722    fn test_precise_time_to() {
723        let t0 = PreciseTime(1000);
724        let t1 = PreciseTime(1023);
725        assert_eq!(Duration::nanoseconds(23), t0.to(t1));
726    }
727
728    #[test]
729    fn test_at_utc() {
730        let _reset = set_time_zone();
731
732        let time = Timespec::new(1234567890, 54321);
733        let utc = at_utc(time);
734
735        assert_eq!(utc.tm_sec, 30);
736        assert_eq!(utc.tm_min, 31);
737        assert_eq!(utc.tm_hour, 23);
738        assert_eq!(utc.tm_mday, 13);
739        assert_eq!(utc.tm_mon, 1);
740        assert_eq!(utc.tm_year, 109);
741        assert_eq!(utc.tm_wday, 5);
742        assert_eq!(utc.tm_yday, 43);
743        assert_eq!(utc.tm_isdst, 0);
744        assert_eq!(utc.tm_utcoff, 0);
745        assert_eq!(utc.tm_nsec, 54321);
746    }
747
748    #[test]
749    fn test_at() {
750        let _reset = set_time_zone();
751
752        let time = Timespec::new(1234567890, 54321);
753        let local = at(time);
754
755        debug!("time_at: {:?}", local);
756
757        assert_eq!(local.tm_sec, 30);
758        assert_eq!(local.tm_min, 31);
759        assert_eq!(local.tm_hour, 15);
760        assert_eq!(local.tm_mday, 13);
761        assert_eq!(local.tm_mon, 1);
762        assert_eq!(local.tm_year, 109);
763        assert_eq!(local.tm_wday, 5);
764        assert_eq!(local.tm_yday, 43);
765        assert_eq!(local.tm_isdst, 0);
766        assert_eq!(local.tm_utcoff, -28800);
767        assert_eq!(local.tm_nsec, 54321);
768    }
769
770    #[test]
771    fn test_to_timespec() {
772        let _reset = set_time_zone();
773
774        let time = Timespec::new(1234567890, 54321);
775        let utc = at_utc(time);
776
777        assert_eq!(utc.to_timespec(), time);
778        assert_eq!(utc.to_local().to_timespec(), time);
779    }
780
781    #[test]
782    fn test_conversions() {
783        let _reset = set_time_zone();
784
785        let time = Timespec::new(1234567890, 54321);
786        let utc = at_utc(time);
787        let local = at(time);
788
789        assert!(local.to_local() == local);
790        assert!(local.to_utc() == utc);
791        assert!(local.to_utc().to_local() == local);
792        assert!(utc.to_utc() == utc);
793        assert!(utc.to_local() == local);
794        assert!(utc.to_local().to_utc() == utc);
795    }
796
797    #[test]
798    fn test_strptime() {
799        let _reset = set_time_zone();
800
801        match strptime("", "") {
802            Ok(ref tm) => {
803                assert!(tm.tm_sec == 0);
804                assert!(tm.tm_min == 0);
805                assert!(tm.tm_hour == 0);
806                assert!(tm.tm_mday == 0);
807                assert!(tm.tm_mon == 0);
808                assert!(tm.tm_year == 0);
809                assert!(tm.tm_wday == 0);
810                assert!(tm.tm_isdst == 0);
811                assert!(tm.tm_utcoff == 0);
812                assert!(tm.tm_nsec == 0);
813            }
814            Err(_) => ()
815        }
816
817        let format = "%a %b %e %T.%f %Y";
818        assert_eq!(strptime("", format), Err(ParseError::InvalidDay));
819        assert_eq!(strptime("Fri Feb 13 15:31:30", format),
820                   Err(InvalidTime));
821
822        match strptime("Fri Feb 13 15:31:30.01234 2009", format) {
823            Err(e) => panic!("{}", e),
824            Ok(ref tm) => {
825                assert_eq!(tm.tm_sec, 30);
826                assert_eq!(tm.tm_min, 31);
827                assert_eq!(tm.tm_hour, 15);
828                assert_eq!(tm.tm_mday, 13);
829                assert_eq!(tm.tm_mon, 1);
830                assert_eq!(tm.tm_year, 109);
831                assert_eq!(tm.tm_wday, 5);
832                assert_eq!(tm.tm_yday, 0);
833                assert_eq!(tm.tm_isdst, 0);
834                assert_eq!(tm.tm_utcoff, 0);
835                assert_eq!(tm.tm_nsec, 12340000);
836            }
837        }
838
839        fn test(s: &str, format: &str) -> bool {
840            match strptime(s, format) {
841              Ok(tm) => {
842                tm.strftime(format).unwrap().to_string() == s.to_string()
843              },
844              Err(e) => panic!("{:?},  s={:?}, format={:?}", e, s, format)
845            }
846        }
847
848        fn test_oneway(s : &str, format : &str) -> bool {
849            match strptime(s, format) {
850              Ok(_) => {
851                // oneway tests are used when reformatting the parsed Tm
852                // back into a string can generate a different string
853                // from the original (i.e. leading zeroes)
854                true
855              },
856              Err(e) => panic!("{:?},  s={:?}, format={:?}", e, s, format)
857            }
858        }
859
860        let days = [
861            "Sunday".to_string(),
862            "Monday".to_string(),
863            "Tuesday".to_string(),
864            "Wednesday".to_string(),
865            "Thursday".to_string(),
866            "Friday".to_string(),
867            "Saturday".to_string()
868        ];
869        for day in days.iter() {
870            assert!(test(&day, "%A"));
871        }
872
873        let days = [
874            "Sun".to_string(),
875            "Mon".to_string(),
876            "Tue".to_string(),
877            "Wed".to_string(),
878            "Thu".to_string(),
879            "Fri".to_string(),
880            "Sat".to_string()
881        ];
882        for day in days.iter() {
883            assert!(test(&day, "%a"));
884        }
885
886        let months = [
887            "January".to_string(),
888            "February".to_string(),
889            "March".to_string(),
890            "April".to_string(),
891            "May".to_string(),
892            "June".to_string(),
893            "July".to_string(),
894            "August".to_string(),
895            "September".to_string(),
896            "October".to_string(),
897            "November".to_string(),
898            "December".to_string()
899        ];
900        for day in months.iter() {
901            assert!(test(&day, "%B"));
902        }
903
904        let months = [
905            "Jan".to_string(),
906            "Feb".to_string(),
907            "Mar".to_string(),
908            "Apr".to_string(),
909            "May".to_string(),
910            "Jun".to_string(),
911            "Jul".to_string(),
912            "Aug".to_string(),
913            "Sep".to_string(),
914            "Oct".to_string(),
915            "Nov".to_string(),
916            "Dec".to_string()
917        ];
918        for day in months.iter() {
919            assert!(test(&day, "%b"));
920        }
921
922        assert!(test("19", "%C"));
923        assert!(test("Fri Feb  3 23:31:30 2009", "%c"));
924        assert!(test("Fri Feb 13 23:31:30 2009", "%c"));
925        assert!(test("02/13/09", "%D"));
926        assert!(test("03", "%d"));
927        assert!(test("13", "%d"));
928        assert!(test(" 3", "%e"));
929        assert!(test("13", "%e"));
930        assert!(test("2009-02-13", "%F"));
931        assert!(test("03", "%H"));
932        assert!(test("13", "%H"));
933        assert!(test("03", "%I")); // FIXME (#2350): flesh out
934        assert!(test("11", "%I")); // FIXME (#2350): flesh out
935        assert!(test("044", "%j"));
936        assert!(test(" 3", "%k"));
937        assert!(test("13", "%k"));
938        assert!(test(" 1", "%l"));
939        assert!(test("11", "%l"));
940        assert!(test("03", "%M"));
941        assert!(test("13", "%M"));
942        assert!(test("\n", "%n"));
943        assert!(test("am", "%P"));
944        assert!(test("pm", "%P"));
945        assert!(test("AM", "%p"));
946        assert!(test("PM", "%p"));
947        assert!(test("23:31", "%R"));
948        assert!(test("11:31:30 AM", "%r"));
949        assert!(test("11:31:30 PM", "%r"));
950        assert!(test("03", "%S"));
951        assert!(test("13", "%S"));
952        assert!(test("15:31:30", "%T"));
953        assert!(test("\t", "%t"));
954        assert!(test("1", "%u"));
955        assert!(test("7", "%u"));
956        assert!(test("13-Feb-2009", "%v"));
957        assert!(test("0", "%w"));
958        assert!(test("6", "%w"));
959        assert!(test("2009", "%Y"));
960        assert!(test("09", "%y"));
961
962        assert!(test_oneway("3",  "%d"));
963        assert!(test_oneway("3",  "%H"));
964        assert!(test_oneway("3",  "%e"));
965        assert!(test_oneway("3",  "%M"));
966        assert!(test_oneway("3",  "%S"));
967
968        assert!(strptime("-0000", "%z").unwrap().tm_utcoff == 0);
969        assert!(strptime("-00:00", "%z").unwrap().tm_utcoff == 0);
970        assert!(strptime("Z", "%z").unwrap().tm_utcoff == 0);
971        assert_eq!(-28800, strptime("-0800", "%z").unwrap().tm_utcoff);
972        assert_eq!(-28800, strptime("-08:00", "%z").unwrap().tm_utcoff);
973        assert_eq!(28800, strptime("+0800", "%z").unwrap().tm_utcoff);
974        assert_eq!(28800, strptime("+08:00", "%z").unwrap().tm_utcoff);
975        assert_eq!(5400, strptime("+0130", "%z").unwrap().tm_utcoff);
976        assert_eq!(5400, strptime("+01:30", "%z").unwrap().tm_utcoff);
977        assert!(test("%", "%%"));
978
979        // Test for #7256
980        assert_eq!(strptime("360", "%Y-%m-%d"), Err(InvalidYear));
981
982        // Test for epoch seconds parsing
983        {
984            assert!(test("1428035610", "%s"));
985            let tm = strptime("1428035610", "%s").unwrap();
986            assert_eq!(tm.tm_utcoff, 0);
987            assert_eq!(tm.tm_isdst, 0);
988            assert_eq!(tm.tm_yday, 92);
989            assert_eq!(tm.tm_wday, 5);
990            assert_eq!(tm.tm_year, 115);
991            assert_eq!(tm.tm_mon, 3);
992            assert_eq!(tm.tm_mday, 3);
993            assert_eq!(tm.tm_hour, 4);
994        }
995    }
996
997    #[test]
998    fn test_asctime() {
999        let _reset = set_time_zone();
1000
1001        let time = Timespec::new(1234567890, 54321);
1002        let utc   = at_utc(time);
1003        let local = at(time);
1004
1005        debug!("test_ctime: {} {}", utc.asctime(), local.asctime());
1006
1007        assert_eq!(utc.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string());
1008        assert_eq!(local.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1009    }
1010
1011    #[test]
1012    fn test_ctime() {
1013        let _reset = set_time_zone();
1014
1015        let time = Timespec::new(1234567890, 54321);
1016        let utc   = at_utc(time);
1017        let local = at(time);
1018
1019        debug!("test_ctime: {} {}", utc.ctime(), local.ctime());
1020
1021        assert_eq!(utc.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1022        assert_eq!(local.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1023    }
1024
1025    #[test]
1026    fn test_strftime() {
1027        let _reset = set_time_zone();
1028
1029        let time = Timespec::new(1234567890, 54321);
1030        let utc = at_utc(time);
1031        let local = at(time);
1032
1033        assert_eq!(local.strftime("").unwrap().to_string(), "".to_string());
1034        assert_eq!(local.strftime("%A").unwrap().to_string(), "Friday".to_string());
1035        assert_eq!(local.strftime("%a").unwrap().to_string(), "Fri".to_string());
1036        assert_eq!(local.strftime("%B").unwrap().to_string(), "February".to_string());
1037        assert_eq!(local.strftime("%b").unwrap().to_string(), "Feb".to_string());
1038        assert_eq!(local.strftime("%C").unwrap().to_string(), "20".to_string());
1039        assert_eq!(local.strftime("%c").unwrap().to_string(),
1040                   "Fri Feb 13 15:31:30 2009".to_string());
1041        assert_eq!(local.strftime("%D").unwrap().to_string(), "02/13/09".to_string());
1042        assert_eq!(local.strftime("%d").unwrap().to_string(), "13".to_string());
1043        assert_eq!(local.strftime("%e").unwrap().to_string(), "13".to_string());
1044        assert_eq!(local.strftime("%F").unwrap().to_string(), "2009-02-13".to_string());
1045        assert_eq!(local.strftime("%f").unwrap().to_string(), "000054321".to_string());
1046        assert_eq!(local.strftime("%G").unwrap().to_string(), "2009".to_string());
1047        assert_eq!(local.strftime("%g").unwrap().to_string(), "09".to_string());
1048        assert_eq!(local.strftime("%H").unwrap().to_string(), "15".to_string());
1049        assert_eq!(local.strftime("%h").unwrap().to_string(), "Feb".to_string());
1050        assert_eq!(local.strftime("%I").unwrap().to_string(), "03".to_string());
1051        assert_eq!(local.strftime("%j").unwrap().to_string(), "044".to_string());
1052        assert_eq!(local.strftime("%k").unwrap().to_string(), "15".to_string());
1053        assert_eq!(local.strftime("%l").unwrap().to_string(), " 3".to_string());
1054        assert_eq!(local.strftime("%M").unwrap().to_string(), "31".to_string());
1055        assert_eq!(local.strftime("%m").unwrap().to_string(), "02".to_string());
1056        assert_eq!(local.strftime("%n").unwrap().to_string(), "\n".to_string());
1057        assert_eq!(local.strftime("%P").unwrap().to_string(), "pm".to_string());
1058        assert_eq!(local.strftime("%p").unwrap().to_string(), "PM".to_string());
1059        assert_eq!(local.strftime("%R").unwrap().to_string(), "15:31".to_string());
1060        assert_eq!(local.strftime("%r").unwrap().to_string(), "03:31:30 PM".to_string());
1061        assert_eq!(local.strftime("%S").unwrap().to_string(), "30".to_string());
1062        assert_eq!(local.strftime("%s").unwrap().to_string(), "1234567890".to_string());
1063        assert_eq!(local.strftime("%T").unwrap().to_string(), "15:31:30".to_string());
1064        assert_eq!(local.strftime("%t").unwrap().to_string(), "\t".to_string());
1065        assert_eq!(local.strftime("%U").unwrap().to_string(), "06".to_string());
1066        assert_eq!(local.strftime("%u").unwrap().to_string(), "5".to_string());
1067        assert_eq!(local.strftime("%V").unwrap().to_string(), "07".to_string());
1068        assert_eq!(local.strftime("%v").unwrap().to_string(), "13-Feb-2009".to_string());
1069        assert_eq!(local.strftime("%W").unwrap().to_string(), "06".to_string());
1070        assert_eq!(local.strftime("%w").unwrap().to_string(), "5".to_string());
1071        // FIXME (#2350): support locale
1072        assert_eq!(local.strftime("%X").unwrap().to_string(), "15:31:30".to_string());
1073        // FIXME (#2350): support locale
1074        assert_eq!(local.strftime("%x").unwrap().to_string(), "02/13/09".to_string());
1075        assert_eq!(local.strftime("%Y").unwrap().to_string(), "2009".to_string());
1076        assert_eq!(local.strftime("%y").unwrap().to_string(), "09".to_string());
1077        // FIXME (#2350): support locale
1078        assert_eq!(local.strftime("%Z").unwrap().to_string(), "".to_string());
1079        assert_eq!(local.strftime("%z").unwrap().to_string(), "-0800".to_string());
1080        assert_eq!(local.strftime("%+").unwrap().to_string(),
1081                   "2009-02-13T15:31:30-08:00".to_string());
1082        assert_eq!(local.strftime("%%").unwrap().to_string(), "%".to_string());
1083
1084         let invalid_specifiers = ["%E", "%J", "%K", "%L", "%N", "%O", "%o", "%Q", "%q"];
1085        for &sp in invalid_specifiers.iter() {
1086            assert_eq!(local.strftime(sp).unwrap_err(),
1087                       InvalidFormatSpecifier(sp[1..].chars().next().unwrap()));
1088        }
1089        assert_eq!(local.strftime("%").unwrap_err(), MissingFormatConverter);
1090        assert_eq!(local.strftime("%A %").unwrap_err(), MissingFormatConverter);
1091
1092        assert_eq!(local.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1093        assert_eq!(local.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1094        assert_eq!(local.rfc822z().to_string(), "Fri, 13 Feb 2009 15:31:30 -0800".to_string());
1095        assert_eq!(local.rfc3339().to_string(), "2009-02-13T15:31:30-08:00".to_string());
1096
1097        assert_eq!(utc.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string());
1098        assert_eq!(utc.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string());
1099        assert_eq!(utc.rfc822().to_string(), "Fri, 13 Feb 2009 23:31:30 GMT".to_string());
1100        assert_eq!(utc.rfc822z().to_string(), "Fri, 13 Feb 2009 23:31:30 -0000".to_string());
1101        assert_eq!(utc.rfc3339().to_string(), "2009-02-13T23:31:30Z".to_string());
1102    }
1103
1104    #[test]
1105    fn test_timespec_eq_ord() {
1106        let a = &Timespec::new(-2, 1);
1107        let b = &Timespec::new(-1, 2);
1108        let c = &Timespec::new(1, 2);
1109        let d = &Timespec::new(2, 1);
1110        let e = &Timespec::new(2, 1);
1111
1112        assert!(d.eq(e));
1113        assert!(c.ne(e));
1114
1115        assert!(a.lt(b));
1116        assert!(b.lt(c));
1117        assert!(c.lt(d));
1118
1119        assert!(a.le(b));
1120        assert!(b.le(c));
1121        assert!(c.le(d));
1122        assert!(d.le(e));
1123        assert!(e.le(d));
1124
1125        assert!(b.ge(a));
1126        assert!(c.ge(b));
1127        assert!(d.ge(c));
1128        assert!(e.ge(d));
1129        assert!(d.ge(e));
1130
1131        assert!(b.gt(a));
1132        assert!(c.gt(b));
1133        assert!(d.gt(c));
1134    }
1135
1136    #[test]
1137    #[allow(deprecated)]
1138    fn test_timespec_hash() {
1139        use std::hash::{Hash, Hasher};
1140
1141        let c = &Timespec::new(3, 2);
1142        let d = &Timespec::new(2, 1);
1143        let e = &Timespec::new(2, 1);
1144
1145        let mut hasher = ::std::hash::SipHasher::new();
1146
1147        let d_hash:u64 = {
1148          d.hash(&mut hasher);
1149          hasher.finish()
1150        };
1151
1152        hasher = ::std::hash::SipHasher::new();
1153
1154        let e_hash:u64 = {
1155          e.hash(&mut hasher);
1156          hasher.finish()
1157        };
1158
1159        hasher = ::std::hash::SipHasher::new();
1160
1161        let c_hash:u64 = {
1162          c.hash(&mut hasher);
1163          hasher.finish()
1164        };
1165
1166        assert_eq!(d_hash, e_hash);
1167        assert!(c_hash != e_hash);
1168    }
1169
1170    #[test]
1171    fn test_timespec_add() {
1172        let a = Timespec::new(1, 2);
1173        let b = Duration::seconds(2) + Duration::nanoseconds(3);
1174        let c = a + b;
1175        assert_eq!(c.sec, 3);
1176        assert_eq!(c.nsec, 5);
1177
1178        let p = Timespec::new(1, super::NSEC_PER_SEC - 2);
1179        let q = Duration::seconds(2) + Duration::nanoseconds(2);
1180        let r = p + q;
1181        assert_eq!(r.sec, 4);
1182        assert_eq!(r.nsec, 0);
1183
1184        let u = Timespec::new(1, super::NSEC_PER_SEC - 2);
1185        let v = Duration::seconds(2) + Duration::nanoseconds(3);
1186        let w = u + v;
1187        assert_eq!(w.sec, 4);
1188        assert_eq!(w.nsec, 1);
1189
1190        let k = Timespec::new(1, 0);
1191        let l = Duration::nanoseconds(-1);
1192        let m = k + l;
1193        assert_eq!(m.sec, 0);
1194        assert_eq!(m.nsec, 999_999_999);
1195    }
1196
1197    #[test]
1198    fn test_timespec_sub() {
1199        let a = Timespec::new(2, 3);
1200        let b = Timespec::new(1, 2);
1201        let c = a - b;
1202        assert_eq!(c.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 + 1));
1203
1204        let p = Timespec::new(2, 0);
1205        let q = Timespec::new(1, 2);
1206        let r = p - q;
1207        assert_eq!(r.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 - 2));
1208
1209        let u = Timespec::new(1, 2);
1210        let v = Timespec::new(2, 3);
1211        let w = u - v;
1212        assert_eq!(w.num_nanoseconds(), Some(-super::NSEC_PER_SEC as i64 - 1));
1213    }
1214
1215    #[test]
1216    fn test_time_sub() {
1217        let a = ::time::now();
1218        let b = at(a.to_timespec() + Duration::seconds(5));
1219        let c = b - a;
1220        assert_eq!(c.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 * 5));
1221    }
1222
1223    #[test]
1224    fn test_steadytime_sub() {
1225        let a = SteadyTime::now();
1226        let b = a + Duration::seconds(1);
1227        assert_eq!(b - a, Duration::seconds(1));
1228        assert_eq!(a - b, Duration::seconds(-1));
1229    }
1230
1231    #[test]
1232    fn test_date_before_1970() {
1233        let early = strptime("1901-01-06", "%F").unwrap();
1234        let late = strptime("2000-01-01", "%F").unwrap();
1235        assert!(early < late);
1236    }
1237
1238    #[test]
1239    fn test_dst() {
1240        let _reset = set_time_zone_london_dst();
1241        let utc_in_feb = strptime("2015-02-01Z", "%F%z").unwrap();
1242        let utc_in_jun = strptime("2015-06-01Z", "%F%z").unwrap();
1243        let utc_in_nov = strptime("2015-11-01Z", "%F%z").unwrap();
1244        let local_in_feb = utc_in_feb.to_local();
1245        let local_in_jun = utc_in_jun.to_local();
1246        let local_in_nov = utc_in_nov.to_local();
1247
1248        assert_eq!(local_in_feb.tm_mon, 1);
1249        assert_eq!(local_in_feb.tm_hour, 0);
1250        assert_eq!(local_in_feb.tm_utcoff, 0);
1251        assert_eq!(local_in_feb.tm_isdst, 0);
1252
1253        assert_eq!(local_in_jun.tm_mon, 5);
1254        assert_eq!(local_in_jun.tm_hour, 1);
1255        assert_eq!(local_in_jun.tm_utcoff, 3600);
1256        assert_eq!(local_in_jun.tm_isdst, 1);
1257
1258        assert_eq!(local_in_nov.tm_mon, 10);
1259        assert_eq!(local_in_nov.tm_hour, 0);
1260        assert_eq!(local_in_nov.tm_utcoff, 0);
1261        assert_eq!(local_in_nov.tm_isdst, 0)
1262    }
1263}