1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #[forbid(deprecated_mode)];
13 use core::cmp::{Eq, Ord};
15 use core::libc::{c_char, c_int, c_long, size_t, time_t};
17 use core::io::{Reader, ReaderUtil};
20 use core::result::{Result, Ok, Err};
23 const NSEC_PER_SEC: i32 = 1_000_000_000_i32;
28 unsafe fn get_time(sec: &mut i64, nsec: &mut i32);
30 unsafe fn precise_time_ns(ns: &mut u64);
32 unsafe fn rust_tzset();
33 // FIXME: The i64 values can be passed by-val when #2064 is fixed.
34 unsafe fn rust_gmtime(&&sec: i64, &&nsec: i32, &&result: Tm);
35 unsafe fn rust_localtime(&&sec: i64, &&nsec: i32, &&result: Tm);
36 unsafe fn rust_timegm(&&tm: Tm, sec: &mut i64);
37 unsafe fn rust_mktime(&&tm: Tm, sec: &mut i64);
40 /// A record specifying a time value in seconds and nanoseconds.
43 pub struct Timespec { sec: i64, nsec: i32 }
46 * Timespec assumes that pre-epoch Timespecs have negative sec and positive
47 * nsec fields. Darwin's and Linux's struct timespec functions handle pre-
48 * epoch timestamps using a "two steps back, one step forward" representation,
49 * though the man pages do not actually document this. For example, the time
50 * -1.2 seconds before the epoch is represented by `Timespec { sec: -2_i64,
51 * nsec: 800_000_000_i32 }`.
54 static pure fn new(sec: i64, nsec: i32) -> Timespec {
55 assert nsec >= 0 && nsec < NSEC_PER_SEC;
56 Timespec { sec: sec, nsec: nsec }
61 pure fn eq(&self, other: &Timespec) -> bool {
62 self.sec == other.sec && self.nsec == other.nsec
64 pure fn ne(&self, other: &Timespec) -> bool { !self.eq(other) }
68 pure fn lt(&self, other: &Timespec) -> bool {
69 self.sec < other.sec ||
70 (self.sec == other.sec && self.nsec < other.nsec)
72 pure fn le(&self, other: &Timespec) -> bool { !other.lt(self) }
73 pure fn ge(&self, other: &Timespec) -> bool { !self.lt(other) }
74 pure fn gt(&self, other: &Timespec) -> bool { !self.le(other) }
78 * Returns the current time as a `timespec` containing the seconds and
79 * nanoseconds since 1970-01-01T00:00:00Z.
81 pub fn get_time() -> Timespec {
85 rustrt::get_time(&mut sec, &mut nsec);
86 return Timespec::new(sec, nsec);
92 * Returns the current value of a high-resolution performance counter
93 * in nanoseconds since an unspecified epoch.
95 pub fn precise_time_ns() -> u64 {
98 rustrt::precise_time_ns(&mut ns);
105 * Returns the current value of a high-resolution performance counter
106 * in seconds since an unspecified epoch.
108 pub fn precise_time_s() -> float {
109 return (precise_time_ns() as float) / 1000000000.;
114 rustrt::rust_tzset();
121 tm_sec: i32, // seconds after the minute ~[0-60]
122 tm_min: i32, // minutes after the hour ~[0-59]
123 tm_hour: i32, // hours after midnight ~[0-23]
124 tm_mday: i32, // days of the month ~[1-31]
125 tm_mon: i32, // months since January ~[0-11]
126 tm_year: i32, // years since 1900
127 tm_wday: i32, // days since Sunday ~[0-6]
128 tm_yday: i32, // days since January 1 ~[0-365]
129 tm_isdst: i32, // Daylight Savings Time flag
130 tm_gmtoff: i32, // offset from UTC in seconds
131 tm_zone: ~str, // timezone abbreviation
132 tm_nsec: i32, // nanoseconds
136 pure fn eq(&self, other: &Tm) -> bool {
137 self.tm_sec == (*other).tm_sec &&
138 self.tm_min == (*other).tm_min &&
139 self.tm_hour == (*other).tm_hour &&
140 self.tm_mday == (*other).tm_mday &&
141 self.tm_mon == (*other).tm_mon &&
142 self.tm_year == (*other).tm_year &&
143 self.tm_wday == (*other).tm_wday &&
144 self.tm_yday == (*other).tm_yday &&
145 self.tm_isdst == (*other).tm_isdst &&
146 self.tm_gmtoff == (*other).tm_gmtoff &&
147 self.tm_zone == (*other).tm_zone &&
148 self.tm_nsec == (*other).tm_nsec
150 pure fn ne(&self, other: &Tm) -> bool { !self.eq(other) }
153 pub pure fn empty_tm() -> Tm {
170 /// Returns the specified time in UTC
171 pub fn at_utc(clock: Timespec) -> Tm {
173 let mut Timespec { sec, nsec } = clock;
174 let mut tm = empty_tm();
175 rustrt::rust_gmtime(sec, nsec, tm);
180 /// Returns the current time in UTC
181 pub fn now_utc() -> Tm {
185 /// Returns the specified time in the local timezone
186 pub fn at(clock: Timespec) -> Tm {
188 let mut Timespec { sec, nsec } = clock;
189 let mut tm = empty_tm();
190 rustrt::rust_localtime(sec, nsec, tm);
195 /// Returns the current time in the local timezone
200 /// Parses the time from the string according to the format string.
201 pub pure fn strptime(s: &str, format: &str) -> Result<Tm, ~str> {
202 // unsafe only because do_strptime is annoying to make pure
203 // (it does IO with a str_reader)
204 unsafe {do_strptime(s, format)}
207 /// Formats the time according to the format string.
208 pub pure fn strftime(format: &str, tm: &Tm) -> ~str {
209 // unsafe only because do_strftime is annoying to make pure
210 // (it does IO with a str_reader)
211 move unsafe { do_strftime(format, tm) }
215 /// Convert time to the seconds from January 1, 1970
216 fn to_timespec() -> Timespec {
219 if self.tm_gmtoff == 0_i32 {
220 rustrt::rust_timegm(self, &mut sec);
222 rustrt::rust_mktime(self, &mut sec);
224 Timespec::new(sec, self.tm_nsec)
228 /// Convert time to the local timezone
229 fn to_local() -> Tm {
230 at(self.to_timespec())
233 /// Convert time to the UTC
235 at_utc(self.to_timespec())
239 * Return a string of the current time in the form
240 * "Thu Jan 1 00:00:00 1970".
242 pure fn ctime() -> ~str { self.strftime(~"%c") }
244 /// Formats the time according to the format string.
245 pure fn strftime(&self, format: &str) -> ~str {
246 move strftime(format, self)
250 * Returns a time string formatted according to RFC 822.
252 * local: "Thu, 22 Mar 2012 07:53:18 PST"
253 * utc: "Thu, 22 Mar 2012 14:53:18 UTC"
255 pure fn rfc822() -> ~str {
256 if self.tm_gmtoff == 0_i32 {
257 self.strftime(~"%a, %d %b %Y %T GMT")
259 self.strftime(~"%a, %d %b %Y %T %Z")
264 * Returns a time string formatted according to RFC 822 with Zulu time.
266 * local: "Thu, 22 Mar 2012 07:53:18 -0700"
267 * utc: "Thu, 22 Mar 2012 14:53:18 -0000"
269 pure fn rfc822z() -> ~str {
270 self.strftime(~"%a, %d %b %Y %T %z")
274 * Returns a time string formatted according to ISO 8601.
276 * local: "2012-02-22T07:53:18-07:00"
277 * utc: "2012-02-22T14:53:18Z"
279 pure fn rfc3339() -> ~str {
280 if self.tm_gmtoff == 0_i32 {
281 self.strftime(~"%Y-%m-%dT%H:%M:%SZ")
283 let s = self.strftime(~"%Y-%m-%dT%H:%M:%S");
284 let sign = if self.tm_gmtoff > 0_i32 { '+' } else { '-' };
285 let mut m = i32::abs(self.tm_gmtoff) / 60_i32;
288 s + fmt!("%c%02d:%02d", sign, h as int, m as int)
293 priv fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> {
294 fn match_str(s: &str, pos: uint, needle: &str) -> bool {
296 for str::each(needle) |ch| {
305 fn match_strs(ss: &str, pos: uint, strs: &[(~str, i32)])
306 -> Option<(i32, uint)> {
308 let len = strs.len();
310 let &(needle, value) = &strs[i];
312 if match_str(ss, pos, needle) {
313 return Some((value, pos + str::len(needle)));
321 fn match_digits(ss: &str, pos: uint, digits: uint, ws: bool)
322 -> Option<(i32, uint)> {
324 let mut value = 0_i32;
328 let range = str::char_range_at(str::from_slice(ss), pos);
333 value = value * 10_i32 + (range.ch as i32 - '0' as i32);
344 fn parse_char(s: &str, pos: uint, c: char) -> Result<uint, ~str> {
345 let range = str::char_range_at(s, pos);
350 Err(fmt!("Expected %?, found %?",
352 str::from_char(range.ch)))
356 fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
357 -> Result<uint, ~str> {
359 'A' => match match_strs(s, pos, ~[
363 (~"Wednesday", 3_i32),
364 (~"Thursday", 4_i32),
368 Some(item) => { let (v, pos) = item; tm.tm_wday = v; Ok(pos) }
369 None => Err(~"Invalid day")
371 'a' => match match_strs(s, pos, ~[
380 Some(item) => { let (v, pos) = item; tm.tm_wday = v; Ok(pos) }
381 None => Err(~"Invalid day")
383 'B' => match match_strs(s, pos, ~[
385 (~"February", 1_i32),
392 (~"September", 8_i32),
394 (~"November", 10_i32),
395 (~"December", 11_i32)
397 Some(item) => { let (v, pos) = item; tm.tm_mon = v; Ok(pos) }
398 None => Err(~"Invalid month")
400 'b' | 'h' => match match_strs(s, pos, ~[
414 Some(item) => { let (v, pos) = item; tm.tm_mon = v; Ok(pos) }
415 None => Err(~"Invalid month")
417 'C' => match match_digits(s, pos, 2u, false) {
420 tm.tm_year += (v * 100_i32) - 1900_i32;
423 None => Err(~"Invalid year")
426 parse_type(s, pos, 'a', &mut *tm)
427 .chain(|pos| parse_char(s, pos, ' '))
428 .chain(|pos| parse_type(s, pos, 'b', &mut *tm))
429 .chain(|pos| parse_char(s, pos, ' '))
430 .chain(|pos| parse_type(s, pos, 'e', &mut *tm))
431 .chain(|pos| parse_char(s, pos, ' '))
432 .chain(|pos| parse_type(s, pos, 'T', &mut *tm))
433 .chain(|pos| parse_char(s, pos, ' '))
434 .chain(|pos| parse_type(s, pos, 'Y', &mut *tm))
437 parse_type(s, pos, 'm', &mut *tm)
438 .chain(|pos| parse_char(s, pos, '/'))
439 .chain(|pos| parse_type(s, pos, 'd', &mut *tm))
440 .chain(|pos| parse_char(s, pos, '/'))
441 .chain(|pos| parse_type(s, pos, 'y', &mut *tm))
443 'd' => match match_digits(s, pos, 2u, false) {
444 Some(item) => { let (v, pos) = item; tm.tm_mday = v; Ok(pos) }
445 None => Err(~"Invalid day of the month")
447 'e' => match match_digits(s, pos, 2u, true) {
448 Some(item) => { let (v, pos) = item; tm.tm_mday = v; Ok(pos) }
449 None => Err(~"Invalid day of the month")
452 parse_type(s, pos, 'Y', &mut *tm)
453 .chain(|pos| parse_char(s, pos, '-'))
454 .chain(|pos| parse_type(s, pos, 'm', &mut *tm))
455 .chain(|pos| parse_char(s, pos, '-'))
456 .chain(|pos| parse_type(s, pos, 'd', &mut *tm))
459 // FIXME (#2350): range check.
460 match match_digits(s, pos, 2u, false) {
461 Some(item) => { let (v, pos) = item; tm.tm_hour = v; Ok(pos) }
462 None => Err(~"Invalid hour")
466 // FIXME (#2350): range check.
467 match match_digits(s, pos, 2u, false) {
470 tm.tm_hour = if v == 12_i32 { 0_i32 } else { v };
473 None => Err(~"Invalid hour")
477 // FIXME (#2350): range check.
478 match match_digits(s, pos, 3u, false) {
481 tm.tm_yday = v - 1_i32;
484 None => Err(~"Invalid year")
488 // FIXME (#2350): range check.
489 match match_digits(s, pos, 2u, true) {
490 Some(item) => { let (v, pos) = item; tm.tm_hour = v; Ok(pos) }
491 None => Err(~"Invalid hour")
495 // FIXME (#2350): range check.
496 match match_digits(s, pos, 2u, true) {
499 tm.tm_hour = if v == 12_i32 { 0_i32 } else { v };
502 None => Err(~"Invalid hour")
506 // FIXME (#2350): range check.
507 match match_digits(s, pos, 2u, false) {
508 Some(item) => { let (v, pos) = item; tm.tm_min = v; Ok(pos) }
509 None => Err(~"Invalid minute")
513 // FIXME (#2350): range check.
514 match match_digits(s, pos, 2u, false) {
517 tm.tm_mon = v - 1_i32;
520 None => Err(~"Invalid month")
523 'n' => parse_char(s, pos, '\n'),
524 'P' => match match_strs(s, pos,
525 ~[(~"am", 0_i32), (~"pm", 12_i32)]) {
527 Some(item) => { let (v, pos) = item; tm.tm_hour += v; Ok(pos) }
528 None => Err(~"Invalid hour")
530 'p' => match match_strs(s, pos,
531 ~[(~"AM", 0_i32), (~"PM", 12_i32)]) {
533 Some(item) => { let (v, pos) = item; tm.tm_hour += v; Ok(pos) }
534 None => Err(~"Invalid hour")
537 parse_type(s, pos, 'H', &mut *tm)
538 .chain(|pos| parse_char(s, pos, ':'))
539 .chain(|pos| parse_type(s, pos, 'M', &mut *tm))
542 parse_type(s, pos, 'I', &mut *tm)
543 .chain(|pos| parse_char(s, pos, ':'))
544 .chain(|pos| parse_type(s, pos, 'M', &mut *tm))
545 .chain(|pos| parse_char(s, pos, ':'))
546 .chain(|pos| parse_type(s, pos, 'S', &mut *tm))
547 .chain(|pos| parse_char(s, pos, ' '))
548 .chain(|pos| parse_type(s, pos, 'p', &mut *tm))
551 // FIXME (#2350): range check.
552 match match_digits(s, pos, 2u, false) {
558 None => Err(~"Invalid second")
563 parse_type(s, pos, 'H', &mut *tm)
564 .chain(|pos| parse_char(s, pos, ':'))
565 .chain(|pos| parse_type(s, pos, 'M', &mut *tm))
566 .chain(|pos| parse_char(s, pos, ':'))
567 .chain(|pos| parse_type(s, pos, 'S', &mut *tm))
569 't' => parse_char(s, pos, '\t'),
571 // FIXME (#2350): range check.
572 match match_digits(s, pos, 1u, false) {
578 None => Err(~"Invalid weekday")
582 parse_type(s, pos, 'e', &mut *tm)
583 .chain(|pos| parse_char(s, pos, '-'))
584 .chain(|pos| parse_type(s, pos, 'b', &mut *tm))
585 .chain(|pos| parse_char(s, pos, '-'))
586 .chain(|pos| parse_type(s, pos, 'Y', &mut *tm))
590 // FIXME (#2350): range check.
591 match match_digits(s, pos, 1u, false) {
592 Some(item) => { let (v, pos) = item; tm.tm_wday = v; Ok(pos) }
593 None => Err(~"Invalid weekday")
599 // FIXME (#2350): range check.
600 match match_digits(s, pos, 4u, false) {
603 tm.tm_year = v - 1900_i32;
606 None => Err(~"Invalid weekday")
610 // FIXME (#2350): range check.
611 match match_digits(s, pos, 2u, false) {
614 tm.tm_year = v - 1900_i32;
617 None => Err(~"Invalid weekday")
621 if match_str(s, pos, ~"UTC") || match_str(s, pos, ~"GMT") {
622 tm.tm_gmtoff = 0_i32;
626 // It's odd, but to maintain compatibility with c's
627 // strptime we ignore the timezone.
629 let len = str::len(s);
631 let range = str::char_range_at(s, pos);
633 if range.ch == ' ' { break; }
640 let range = str::char_range_at(s, pos);
642 if range.ch == '+' || range.ch == '-' {
643 match match_digits(s, range.next, 4u, false) {
647 tm.tm_gmtoff = 0_i32;
653 None => Err(~"Invalid zone offset")
656 Err(~"Invalid zone offset")
659 '%' => parse_char(s, pos, '%'),
661 Err(fmt!("unknown formatting type: %?", str::from_char(ch)))
666 do io::with_str_reader(str::from_slice(format)) |rdr| {
682 let len = str::len(s);
683 let mut result = Err(~"Invalid time");
685 while !rdr.eof() && pos < len {
686 let range = str::char_range_at(s, pos);
688 let next = range.next;
690 match rdr.read_char() {
692 match parse_type(s, pos, rdr.read_char(), &mut tm) {
693 Ok(next) => pos = next,
694 Err(move e) => { result = Err(move e); break; }
704 if pos == len && rdr.eof() {
714 tm_isdst: tm.tm_isdst,
715 tm_gmtoff: tm.tm_gmtoff,
716 tm_zone: copy tm.tm_zone,
719 } else { move result }
723 priv fn do_strftime(format: &str, tm: &Tm) -> ~str {
724 fn parse_type(ch: char, tm: &Tm) -> ~str {
725 //FIXME (#2350): Implement missing types.
726 let die = || fmt!("strftime: can't understand this format %c ", ch);
728 'A' => match tm.tm_wday as int {
738 'a' => match tm.tm_wday as int {
748 'B' => match tm.tm_mon as int {
763 'b' | 'h' => match tm.tm_mon as int {
778 'C' => fmt!("%02d", (tm.tm_year as int + 1900) / 100),
780 fmt!("%s %s %s %s %s",
793 'd' => fmt!("%02d", tm.tm_mday as int),
794 'e' => fmt!("%2d", tm.tm_mday as int),
803 'H' => fmt!("%02d", tm.tm_hour as int),
805 let mut h = tm.tm_hour as int;
807 if h > 12 { h -= 12 }
810 'j' => fmt!("%03d", tm.tm_yday as int + 1),
811 'k' => fmt!("%2d", tm.tm_hour as int),
813 let mut h = tm.tm_hour as int;
815 if h > 12 { h -= 12 }
818 'M' => fmt!("%02d", tm.tm_min as int),
819 'm' => fmt!("%02d", tm.tm_mon as int + 1),
821 'P' => if tm.tm_hour as int < 12 { ~"am" } else { ~"pm" },
822 'p' => if tm.tm_hour as int < 12 { ~"AM" } else { ~"PM" },
835 'S' => fmt!("%02d", tm.tm_sec as int),
836 's' => fmt!("%d", tm.to_timespec().sec as int),
846 let i = tm.tm_wday as int;
847 int::str(if i == 0 { 7 } else { i })
857 'w' => int::str(tm.tm_wday as int),
860 'Y' => int::str(tm.tm_year as int + 1900),
861 'y' => fmt!("%02d", (tm.tm_year as int + 1900) % 100),
862 'Z' => copy tm.tm_zone,
864 let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' };
865 let mut m = i32::abs(tm.tm_gmtoff) / 60_i32;
868 fmt!("%c%02d%02d", sign, h as int, m as int)
878 do io::with_str_reader(str::from_slice(format)) |rdr| {
880 match rdr.read_char() {
881 '%' => buf += parse_type(rdr.read_char(), tm),
882 ch => str::push_char(&mut buf, ch)
906 const some_recent_date: i64 = 1325376000i64; // 2012-01-01T00:00:00Z
907 const some_future_date: i64 = 1577836800i64; // 2020-01-01T00:00:00Z
909 let tv1 = get_time();
910 log(debug, ~"tv1=" + uint::str(tv1.sec as uint) + ~" sec + "
911 + uint::str(tv1.nsec as uint) + ~" nsec");
913 assert tv1.sec > some_recent_date;
914 assert tv1.nsec < 1000000000i32;
916 let tv2 = get_time();
917 log(debug, ~"tv2=" + uint::str(tv2.sec as uint) + ~" sec + "
918 + uint::str(tv2.nsec as uint) + ~" nsec");
920 assert tv2.sec >= tv1.sec;
921 assert tv2.sec < some_future_date;
922 assert tv2.nsec < 1000000000i32;
923 if tv2.sec == tv1.sec {
924 assert tv2.nsec >= tv1.nsec;
929 fn test_precise_time() {
930 let s0 = precise_time_s();
931 let ns1 = precise_time_ns();
933 log(debug, ~"s0=" + float::to_str(s0, 9u) + ~" sec");
935 let ns0 = (s0 * 1000000000.) as u64;
936 log(debug, ~"ns0=" + u64::str(ns0) + ~" ns");
938 log(debug, ~"ns1=" + u64::str(ns1) + ~" ns");
941 let ns2 = precise_time_ns();
942 log(debug, ~"ns2=" + u64::str(ns2) + ~" ns");
948 os::setenv(~"TZ", ~"America/Los_Angeles");
951 let time = ::time::Timespec::new(1234567890, 54321);
952 let utc = at_utc(time);
954 assert utc.tm_sec == 30_i32;
955 assert utc.tm_min == 31_i32;
956 assert utc.tm_hour == 23_i32;
957 assert utc.tm_mday == 13_i32;
958 assert utc.tm_mon == 1_i32;
959 assert utc.tm_year == 109_i32;
960 assert utc.tm_wday == 5_i32;
961 assert utc.tm_yday == 43_i32;
962 assert utc.tm_isdst == 0_i32;
963 assert utc.tm_gmtoff == 0_i32;
964 assert utc.tm_zone == ~"UTC";
965 assert utc.tm_nsec == 54321_i32;
970 os::setenv(~"TZ", ~"America/Los_Angeles");
973 let time = ::time::Timespec::new(1234567890, 54321);
974 let local = at(time);
976 error!("time_at: %?", local);
978 assert local.tm_sec == 30_i32;
979 assert local.tm_min == 31_i32;
980 assert local.tm_hour == 15_i32;
981 assert local.tm_mday == 13_i32;
982 assert local.tm_mon == 1_i32;
983 assert local.tm_year == 109_i32;
984 assert local.tm_wday == 5_i32;
985 assert local.tm_yday == 43_i32;
986 assert local.tm_isdst == 0_i32;
987 assert local.tm_gmtoff == -28800_i32;
989 // FIXME (#2350): We should probably standardize on the timezone
991 let zone = &local.tm_zone;
992 assert *zone == ~"PST" || *zone == ~"Pacific Standard Time";
994 assert local.tm_nsec == 54321_i32;
998 fn test_to_timespec() {
999 os::setenv(~"TZ", ~"America/Los_Angeles");
1002 let time = ::time::Timespec::new(1234567890, 54321);
1003 let utc = at_utc(time);
1005 assert utc.to_timespec() == time;
1006 assert utc.to_local().to_timespec() == time;
1010 fn test_conversions() {
1011 os::setenv(~"TZ", ~"America/Los_Angeles");
1014 let time = ::time::Timespec::new(1234567890, 54321);
1015 let utc = at_utc(time);
1016 let local = at(time);
1018 assert local.to_local() == local;
1019 assert local.to_utc() == utc;
1020 assert local.to_utc().to_local() == local;
1021 assert utc.to_utc() == utc;
1022 assert utc.to_local() == local;
1023 assert utc.to_local().to_utc() == utc;
1027 fn test_strptime() {
1028 os::setenv(~"TZ", ~"America/Los_Angeles");
1031 match strptime(~"", ~"") {
1033 assert tm.tm_sec == 0_i32;
1034 assert tm.tm_min == 0_i32;
1035 assert tm.tm_hour == 0_i32;
1036 assert tm.tm_mday == 0_i32;
1037 assert tm.tm_mon == 0_i32;
1038 assert tm.tm_year == 0_i32;
1039 assert tm.tm_wday == 0_i32;
1040 assert tm.tm_isdst== 0_i32;
1041 assert tm.tm_gmtoff == 0_i32;
1042 assert tm.tm_zone == ~"";
1043 assert tm.tm_nsec == 0_i32;
1048 let format = ~"%a %b %e %T %Y";
1049 assert strptime(~"", format) == Err(~"Invalid time");
1050 assert strptime(~"Fri Feb 13 15:31:30", format)
1051 == Err(~"Invalid time");
1053 match strptime(~"Fri Feb 13 15:31:30 2009", format) {
1054 Err(copy e) => fail e,
1056 assert tm.tm_sec == 30_i32;
1057 assert tm.tm_min == 31_i32;
1058 assert tm.tm_hour == 15_i32;
1059 assert tm.tm_mday == 13_i32;
1060 assert tm.tm_mon == 1_i32;
1061 assert tm.tm_year == 109_i32;
1062 assert tm.tm_wday == 5_i32;
1063 assert tm.tm_yday == 0_i32;
1064 assert tm.tm_isdst == 0_i32;
1065 assert tm.tm_gmtoff == 0_i32;
1066 assert tm.tm_zone == ~"";
1067 assert tm.tm_nsec == 0_i32;
1071 fn test(s: &str, format: &str) -> bool {
1072 match strptime(s, format) {
1073 Ok(ref tm) => tm.strftime(format) == str::from_slice(s),
1074 Err(copy e) => fail e
1087 assert test(*day, ~"%A");
1099 assert test(*day, ~"%a");
1116 assert test(*day, ~"%B");
1133 assert test(*day, ~"%b");
1136 assert test(~"19", ~"%C");
1137 assert test(~"Fri Feb 13 23:31:30 2009", ~"%c");
1138 assert test(~"02/13/09", ~"%D");
1139 assert test(~"03", ~"%d");
1140 assert test(~"13", ~"%d");
1141 assert test(~" 3", ~"%e");
1142 assert test(~"13", ~"%e");
1143 assert test(~"2009-02-13", ~"%F");
1144 assert test(~"03", ~"%H");
1145 assert test(~"13", ~"%H");
1146 assert test(~"03", ~"%I"); // FIXME (#2350): flesh out
1147 assert test(~"11", ~"%I"); // FIXME (#2350): flesh out
1148 assert test(~"044", ~"%j");
1149 assert test(~" 3", ~"%k");
1150 assert test(~"13", ~"%k");
1151 assert test(~" 1", ~"%l");
1152 assert test(~"11", ~"%l");
1153 assert test(~"03", ~"%M");
1154 assert test(~"13", ~"%M");
1155 assert test(~"\n", ~"%n");
1156 assert test(~"am", ~"%P");
1157 assert test(~"pm", ~"%P");
1158 assert test(~"AM", ~"%p");
1159 assert test(~"PM", ~"%p");
1160 assert test(~"23:31", ~"%R");
1161 assert test(~"11:31:30 AM", ~"%r");
1162 assert test(~"11:31:30 PM", ~"%r");
1163 assert test(~"03", ~"%S");
1164 assert test(~"13", ~"%S");
1165 assert test(~"15:31:30", ~"%T");
1166 assert test(~"\t", ~"%t");
1167 assert test(~"1", ~"%u");
1168 assert test(~"7", ~"%u");
1169 assert test(~"13-Feb-2009", ~"%v");
1170 assert test(~"0", ~"%w");
1171 assert test(~"6", ~"%w");
1172 assert test(~"2009", ~"%Y");
1173 assert test(~"09", ~"%y");
1174 assert result::unwrap(strptime(~"UTC", ~"%Z")).tm_zone == ~"UTC";
1175 assert result::unwrap(strptime(~"PST", ~"%Z")).tm_zone == ~"";
1176 assert result::unwrap(strptime(~"-0000", ~"%z")).tm_gmtoff == 0;
1177 assert result::unwrap(strptime(~"-0800", ~"%z")).tm_gmtoff == 0;
1178 assert test(~"%", ~"%%");
1182 #[ignore(reason = "randomred")]
1184 os::setenv(~"TZ", ~"America/Los_Angeles");
1187 let time = ::time::Timespec::new(1234567890, 54321);
1188 let utc = at_utc(time);
1189 let local = at(time);
1191 error!("test_ctime: %? %?", utc.ctime(), local.ctime());
1193 assert utc.ctime() == ~"Fri Feb 13 23:31:30 2009";
1194 assert local.ctime() == ~"Fri Feb 13 15:31:30 2009";
1198 #[ignore(reason = "randomred")]
1199 fn test_strftime() {
1200 os::setenv(~"TZ", ~"America/Los_Angeles");
1203 let time = ::time::Timespec::new(1234567890, 54321);
1204 let utc = at_utc(time);
1205 let local = at(time);
1207 assert local.strftime(~"") == ~"";
1208 assert local.strftime(~"%A") == ~"Friday";
1209 assert local.strftime(~"%a") == ~"Fri";
1210 assert local.strftime(~"%B") == ~"February";
1211 assert local.strftime(~"%b") == ~"Feb";
1212 assert local.strftime(~"%C") == ~"20";
1213 assert local.strftime(~"%c") == ~"Fri Feb 13 15:31:30 2009";
1214 assert local.strftime(~"%D") == ~"02/13/09";
1215 assert local.strftime(~"%d") == ~"13";
1216 assert local.strftime(~"%e") == ~"13";
1217 assert local.strftime(~"%F") == ~"2009-02-13";
1218 // assert local.strftime("%G") == "2009";
1219 // assert local.strftime("%g") == "09";
1220 assert local.strftime(~"%H") == ~"15";
1221 assert local.strftime(~"%I") == ~"03";
1222 assert local.strftime(~"%j") == ~"044";
1223 assert local.strftime(~"%k") == ~"15";
1224 assert local.strftime(~"%l") == ~" 3";
1225 assert local.strftime(~"%M") == ~"31";
1226 assert local.strftime(~"%m") == ~"02";
1227 assert local.strftime(~"%n") == ~"\n";
1228 assert local.strftime(~"%P") == ~"pm";
1229 assert local.strftime(~"%p") == ~"PM";
1230 assert local.strftime(~"%R") == ~"15:31";
1231 assert local.strftime(~"%r") == ~"03:31:30 PM";
1232 assert local.strftime(~"%S") == ~"30";
1233 assert local.strftime(~"%s") == ~"1234567890";
1234 assert local.strftime(~"%T") == ~"15:31:30";
1235 assert local.strftime(~"%t") == ~"\t";
1236 // assert local.strftime("%U") == "06";
1237 assert local.strftime(~"%u") == ~"5";
1238 // assert local.strftime("%V") == "07";
1239 assert local.strftime(~"%v") == ~"13-Feb-2009";
1240 // assert local.strftime("%W") == "06";
1241 assert local.strftime(~"%w") == ~"5";
1244 assert local.strftime(~"%Y") == ~"2009";
1245 assert local.strftime(~"%y") == ~"09";
1247 // FIXME (#2350): We should probably standardize on the timezone
1249 let zone = local.strftime(~"%Z");
1250 assert zone == ~"PST" || zone == ~"Pacific Standard Time";
1252 assert local.strftime(~"%z") == ~"-0800";
1253 assert local.strftime(~"%%") == ~"%";
1255 // FIXME (#2350): We should probably standardize on the timezone
1257 let rfc822 = local.rfc822();
1258 let prefix = ~"Fri, 13 Feb 2009 15:31:30 ";
1259 assert rfc822 == prefix + ~"PST" ||
1260 rfc822 == prefix + ~"Pacific Standard Time";
1262 assert local.ctime() == ~"Fri Feb 13 15:31:30 2009";
1263 assert local.rfc822z() == ~"Fri, 13 Feb 2009 15:31:30 -0800";
1264 assert local.rfc3339() == ~"2009-02-13T15:31:30-08:00";
1266 assert utc.ctime() == ~"Fri Feb 13 23:31:30 2009";
1267 assert utc.rfc822() == ~"Fri, 13 Feb 2009 23:31:30 GMT";
1268 assert utc.rfc822z() == ~"Fri, 13 Feb 2009 23:31:30 -0000";
1269 assert utc.rfc3339() == ~"2009-02-13T23:31:30Z";
1273 fn test_timespec_eq_ord() {
1274 use core::cmp::{eq, ge, gt, le, lt, ne};
1276 let a = &Timespec::new(-2, 1);
1277 let b = &Timespec::new(-1, 2);
1278 let c = &Timespec::new(1, 2);
1279 let d = &Timespec::new(2, 1);
1280 let e = &Timespec::new(2, 1);