(index<- )        ./libextra/time.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  #[allow(missing_doc)];
   12  
   13  use std::io;
   14  use std::num;
   15  use std::str;
   16  
   17  static NSEC_PER_SEC: i32 = 1_000_000_000_i32;
   18  
   19  pub mod rustrt {
   20      use super::Tm;
   21  
   22      #[abi = "cdecl"]
   23      extern {
   24          pub fn get_time(sec&mut i64, nsec&mut i32);
   25          pub fn precise_time_ns(ns&mut u64);
   26          pub fn rust_tzset();
   27          pub fn rust_gmtime(seci64, nseci32, result&mut Tm);
   28          pub fn rust_localtime(seci64, nseci32, result&mut Tm);
   29          pub fn rust_timegm(tm&Tm) -> i64;
   30          pub fn rust_mktime(tm&Tm) -> i64;
   31      }
   32  }
   33  
   34  /// A record specifying a time value in seconds and nanoseconds.
   35  #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
   36  pub struct Timespec { sec: i64, nsec: i32 }
   37  
   38  /*
   39   * Timespec assumes that pre-epoch Timespecs have negative sec and positive
   40   * nsec fields. Darwin's and Linux's struct timespec functions handle pre-
   41   * epoch timestamps using a "two steps back, one step forward" representation,
   42   * though the man pages do not actually document this. For example, the time
   43   * -1.2 seconds before the epoch is represented by `Timespec { sec: -2_i64,
   44   * nsec: 800_000_000_i32 }`.
   45   */
   46  impl Timespec {
   47      pub fn new(seci64, nseci32) -> Timespec {
   48          assert!(nsec >= 0 && nsec < NSEC_PER_SEC);
   49          Timespec { sec: sec, nsec: nsec }
   50      }
   51  }
   52  
   53  impl Ord for Timespec {
   54      fn lt(&self, other&Timespec) -> bool {
   55          self.sec < other.sec ||
   56              (self.sec == other.sec && self.nsec < other.nsec)
   57      }
   58  }
   59  
   60  /**
   61   * Returns the current time as a `timespec` containing the seconds and
   62   * nanoseconds since 1970-01-01T00:00:00Z.
   63   */
   64  pub fn get_time() -> Timespec {
   65      #[fixed_stack_segment]; #[inline(never)];
   66  
   67      unsafe {
   68          let mut sec = 0i64;
   69          let mut nsec = 0i32;
   70          rustrt::get_time(&mut sec, &mut nsec);
   71          return Timespec::new(sec, nsec);
   72      }
   73  }
   74  
   75  
   76  /**
   77   * Returns the current value of a high-resolution performance counter
   78   * in nanoseconds since an unspecified epoch.
   79   */
   80  pub fn precise_time_ns() -> u64 {
   81      #[fixed_stack_segment]; #[inline(never)];
   82  
   83      unsafe {
   84          let mut ns = 0u64;
   85          rustrt::precise_time_ns(&mut ns);
   86          ns
   87      }
   88  }
   89  
   90  
   91  /**
   92   * Returns the current value of a high-resolution performance counter
   93   * in seconds since an unspecified epoch.
   94   */
   95  pub fn precise_time_s() -> float {
   96      return (precise_time_ns() as float) / 1000000000.;
   97  }
   98  
   99  pub fn tzset() {
  100      #[fixed_stack_segment]; #[inline(never)];
  101  
  102      unsafe {
  103          rustrt::rust_tzset();
  104      }
  105  }
  106  
  107  #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
  108  pub struct Tm {
  109      tm_sec: i32, // seconds after the minute ~[0-60]
  110      tm_min: i32, // minutes after the hour ~[0-59]
  111      tm_hour: i32, // hours after midnight ~[0-23]
  112      tm_mday: i32, // days of the month ~[1-31]
  113      tm_mon: i32, // months since January ~[0-11]
  114      tm_year: i32, // years since 1900
  115      tm_wday: i32, // days since Sunday ~[0-6]
  116      tm_yday: i32, // days since January 1 ~[0-365]
  117      tm_isdst: i32, // Daylight Savings Time flag
  118      tm_gmtoff: i32, // offset from UTC in seconds
  119      tm_zone: ~str, // timezone abbreviation
  120      tm_nsec: i32, // nanoseconds
  121  }
  122  
  123  pub fn empty_tm() -> Tm {
  124      // 64 is the max size of the timezone buffer allocated on windows
  125      // in rust_localtime. In glibc the max timezone size is supposedly 3.
  126      let zone = str::with_capacity(64);
  127      Tm {
  128          tm_sec: 0_i32,
  129          tm_min: 0_i32,
  130          tm_hour: 0_i32,
  131          tm_mday: 0_i32,
  132          tm_mon: 0_i32,
  133          tm_year: 0_i32,
  134          tm_wday: 0_i32,
  135          tm_yday: 0_i32,
  136          tm_isdst: 0_i32,
  137          tm_gmtoff: 0_i32,
  138          tm_zone: zone,
  139          tm_nsec: 0_i32,
  140      }
  141  }
  142  
  143  /// Returns the specified time in UTC
  144  pub fn at_utc(clockTimespec) -> Tm {
  145      #[fixed_stack_segment]; #[inline(never)];
  146  
  147      unsafe {
  148          let Timespec { sec, nsec } = clock;
  149          let mut tm = empty_tm();
  150          rustrt::rust_gmtime(sec, nsec, &mut tm);
  151          tm
  152      }
  153  }
  154  
  155  /// Returns the current time in UTC
  156  pub fn now_utc() -> Tm {
  157      at_utc(get_time())
  158  }
  159  
  160  /// Returns the specified time in the local timezone
  161  pub fn at(clockTimespec) -> Tm {
  162      #[fixed_stack_segment]; #[inline(never)];
  163  
  164      unsafe {
  165          let Timespec { sec, nsec } = clock;
  166          let mut tm = empty_tm();
  167          rustrt::rust_localtime(sec, nsec, &mut tm);
  168          tm
  169      }
  170  }
  171  
  172  /// Returns the current time in the local timezone
  173  pub fn now() -> Tm {
  174      at(get_time())
  175  }
  176  
  177  /// Parses the time from the string according to the format string.
  178  pub fn strptime(s&str, format&str) -> Result<Tm, ~str> {
  179      do_strptime(s, format)
  180  }
  181  
  182  /// Formats the time according to the format string.
  183  pub fn strftime(format&str, tm&Tm) -> ~str {
  184      do_strftime(format, tm)
  185  }
  186  
  187  impl Tm {
  188      /// Convert time to the seconds from January 1, 1970
  189      pub fn to_timespec(&self) -> Timespec {
  190          #[fixed_stack_segment]; #[inline(never)];
  191  
  192          unsafe {
  193              let sec = match self.tm_gmtoff {
  194                  0_i32 => rustrt::rust_timegm(self),
  195                  _     => rustrt::rust_mktime(self)
  196              };
  197  
  198              Timespec::new(sec, self.tm_nsec)
  199          }
  200      }
  201  
  202      /// Convert time to the local timezone
  203      pub fn to_local(&self) -> Tm {
  204          at(self.to_timespec())
  205      }
  206  
  207      /// Convert time to the UTC
  208      pub fn to_utc(&self) -> Tm {
  209          at_utc(self.to_timespec())
  210      }
  211  
  212      /**
  213       * Return a string of the current time in the form
  214       * "Thu Jan  1 00:00:00 1970".
  215       */
  216      pub fn ctime(&self) -> ~str { self.strftime("%c") }
  217  
  218      /// Formats the time according to the format string.
  219      pub fn strftime(&self, format&str) -> ~str {
  220          strftime(format, self)
  221      }
  222  
  223      /**
  224       * Returns a time string formatted according to RFC 822.
  225       *
  226       * local: "Thu, 22 Mar 2012 07:53:18 PST"
  227       * utc:   "Thu, 22 Mar 2012 14:53:18 UTC"
  228       */
  229      pub fn rfc822(&self) -> ~str {
  230          if self.tm_gmtoff == 0_i32 {
  231              self.strftime("%a, %d %b %Y %T GMT")
  232          } else {
  233              self.strftime("%a, %d %b %Y %T %Z")
  234          }
  235      }
  236  
  237      /**
  238       * Returns a time string formatted according to RFC 822 with Zulu time.
  239       *
  240       * local: "Thu, 22 Mar 2012 07:53:18 -0700"
  241       * utc:   "Thu, 22 Mar 2012 14:53:18 -0000"
  242       */
  243      pub fn rfc822z(&self) -> ~str {
  244          self.strftime("%a, %d %b %Y %T %z")
  245      }
  246  
  247      /**
  248       * Returns a time string formatted according to ISO 8601.
  249       *
  250       * local: "2012-02-22T07:53:18-07:00"
  251       * utc:   "2012-02-22T14:53:18Z"
  252       */
  253      pub fn rfc3339(&self) -> ~str {
  254          if self.tm_gmtoff == 0_i32 {
  255              self.strftime("%Y-%m-%dT%H:%M:%SZ")
  256          } else {
  257              let s = self.strftime("%Y-%m-%dT%H:%M:%S");
  258              let sign = if self.tm_gmtoff > 0_i32 { '+' } else { '-' };
  259              let mut m = num::abs(self.tm_gmtoff) / 60_i32;
  260              let h = m / 60_i32;
  261              m -= h * 60_i32;
  262              s + fmt!("%c%02d:%02d", sign, h as int, m as int)
  263          }
  264      }
  265  }
  266  
  267  fn do_strptime(s&str, format&str) -> Result<Tm, ~str> {
  268      fn match_str(s&str, posuint, needle&str) -> bool {
  269          let mut i = pos;
  270          for ch in needle.byte_iter() {
  271              if s[i] != ch {
  272                  return false;
  273              }
  274              i += 1u;
  275          }
  276          return true;
  277      }
  278  
  279      fn match_strs(ss&str, posuint, strs&[(~str, i32)])
  280        -> Option<(i32, uint)> {
  281          let mut i = 0u;
  282          let len = strs.len();
  283          while i < len {
  284              match strs[i] { // can't use let due to let-pattern bugs
  285                  (ref needle, value) => {
  286                      if match_str(ss, pos, *needle) {
  287                          return Some((value, pos + needle.len()));
  288                      }
  289                  }
  290              }
  291              i += 1u;
  292          }
  293  
  294          None
  295      }
  296  
  297      fn match_digits(ss&str, posuint, digitsuint, wsbool)
  298        -> Option<(i32, uint)> {
  299          let mut pos = pos;
  300          let len = ss.len();
  301          let mut value = 0_i32;
  302  
  303          let mut i = 0u;
  304          while i < digits {
  305              if pos >= len {
  306                  return None;
  307              }
  308              let range = ss.char_range_at(pos);
  309              pos = range.next;
  310  
  311              match range.ch {
  312                '0' .. '9' => {
  313                  value = value * 10_i32 + (range.ch as i32 - '0' as i32);
  314                }
  315                ' ' if ws => (),
  316                _ => return None
  317              }
  318              i += 1u;
  319          }
  320  
  321          Some((value, pos))
  322      }
  323  
  324      fn match_fractional_seconds(ss&str, posuint) -> (i32, uint) {
  325          let len = ss.len();
  326          let mut value = 0_i32;
  327          let mut multiplier = NSEC_PER_SEC / 10;
  328          let mut pos = pos;
  329  
  330          loop {
  331              if pos >= len {
  332                  break;
  333              }
  334              let range = ss.char_range_at(pos);
  335  
  336              match range.ch {
  337                  '0' .. '9' => {
  338                      pos = range.next;
  339                      // This will drop digits after the nanoseconds place
  340                      let digit = range.ch as i32 - '0' as i32;
  341                      value += digit * multiplier;
  342                      multiplier /= 10;
  343                  }
  344                  _ => break
  345              }
  346          }
  347  
  348          (value, pos)
  349      }
  350  
  351      fn match_digits_in_range(ss&str, posuint, digitsuint, wsbool,
  352                               mini32, maxi32) -> Option<(i32, uint)> {
  353          match match_digits(ss, pos, digits, ws) {
  354            Some((val, pos)) if val >= min && val <= max => {
  355              Some((val, pos))
  356            }
  357            _ => None
  358          }
  359      }
  360  
  361      fn parse_char(s&str, posuint, cchar) -> Result<uint, ~str> {
  362          let range = s.char_range_at(pos);
  363  
  364          if c == range.ch {
  365              Ok(range.next)
  366          } else {
  367              Err(fmt!("Expected %?, found %?",
  368                  str::from_char(c),
  369                  str::from_char(range.ch)))
  370          }
  371      }
  372  
  373      fn parse_type(s&str, posuint, chchar, tm&mut Tm)
  374        -> Result<uint, ~str> {
  375          match ch {
  376            'A' => match match_strs(s, pos, [
  377                (~"Sunday", 0_i32),
  378                (~"Monday", 1_i32),
  379                (~"Tuesday", 2_i32),
  380                (~"Wednesday", 3_i32),
  381                (~"Thursday", 4_i32),
  382                (~"Friday", 5_i32),
  383                (~"Saturday", 6_i32)
  384            ]) {
  385              Some(item) => { let (v, pos) = item; tm.tm_wday = v; Ok(pos) }
  386              None => Err(~"Invalid day")
  387            },
  388            'a' => match match_strs(s, pos, [
  389                (~"Sun", 0_i32),
  390                (~"Mon", 1_i32),
  391                (~"Tue", 2_i32),
  392                (~"Wed", 3_i32),
  393                (~"Thu", 4_i32),
  394                (~"Fri", 5_i32),
  395                (~"Sat", 6_i32)
  396            ]) {
  397              Some(item) => { let (v, pos) = item; tm.tm_wday = v; Ok(pos) }
  398              None => Err(~"Invalid day")
  399            },
  400            'B' => match match_strs(s, pos, [
  401                (~"January", 0_i32),
  402                (~"February", 1_i32),
  403                (~"March", 2_i32),
  404                (~"April", 3_i32),
  405                (~"May", 4_i32),
  406                (~"June", 5_i32),
  407                (~"July", 6_i32),
  408                (~"August", 7_i32),
  409                (~"September", 8_i32),
  410                (~"October", 9_i32),
  411                (~"November", 10_i32),
  412                (~"December", 11_i32)
  413            ]) {
  414              Some(item) => { let (v, pos) = item; tm.tm_mon = v; Ok(pos) }
  415              None => Err(~"Invalid month")
  416            },
  417            'b' | 'h' => match match_strs(s, pos, [
  418                (~"Jan", 0_i32),
  419                (~"Feb", 1_i32),
  420                (~"Mar", 2_i32),
  421                (~"Apr", 3_i32),
  422                (~"May", 4_i32),
  423                (~"Jun", 5_i32),
  424                (~"Jul", 6_i32),
  425                (~"Aug", 7_i32),
  426                (~"Sep", 8_i32),
  427                (~"Oct", 9_i32),
  428                (~"Nov", 10_i32),
  429                (~"Dec", 11_i32)
  430            ]) {
  431              Some(item) => { let (v, pos) = item; tm.tm_mon = v; Ok(pos) }
  432              None => Err(~"Invalid month")
  433            },
  434            'C' => match match_digits_in_range(s, pos, 2u, false, 0_i32,
  435                                               99_i32) {
  436              Some(item) => {
  437                  let (v, pos) = item;
  438                    tm.tm_year += (v * 100_i32) - 1900_i32;
  439                    Ok(pos)
  440                }
  441              None => Err(~"Invalid year")
  442            },
  443            'c' => {
  444              parse_type(s, pos, 'a', &mut *tm)
  445                  .and_then(|pos| parse_char(s, pos, ' '))
  446                  .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
  447                  .and_then(|pos| parse_char(s, pos, ' '))
  448                  .and_then(|pos| parse_type(s, pos, 'e', &mut *tm))
  449                  .and_then(|pos| parse_char(s, pos, ' '))
  450                  .and_then(|pos| parse_type(s, pos, 'T', &mut *tm))
  451                  .and_then(|pos| parse_char(s, pos, ' '))
  452                  .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
  453            }
  454            'D' | 'x' => {
  455              parse_type(s, pos, 'm', &mut *tm)
  456                  .and_then(|pos| parse_char(s, pos, '/'))
  457                  .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
  458                  .and_then(|pos| parse_char(s, pos, '/'))
  459                  .and_then(|pos| parse_type(s, pos, 'y', &mut *tm))
  460            }
  461            'd' => match match_digits_in_range(s, pos, 2u, false, 1_i32,
  462                                               31_i32) {
  463              Some(item) => { let (v, pos) = item; tm.tm_mday = v; Ok(pos) }
  464              None => Err(~"Invalid day of the month")
  465            },
  466            'e' => match match_digits_in_range(s, pos, 2u, true, 1_i32,
  467                                               31_i32) {
  468              Some(item) => { let (v, pos) = item; tm.tm_mday = v; Ok(pos) }
  469              None => Err(~"Invalid day of the month")
  470            },
  471            'f' => {
  472              let (val, pos) = match_fractional_seconds(s, pos);
  473              tm.tm_nsec = val;
  474              Ok(pos)
  475            }
  476            'F' => {
  477              parse_type(s, pos, 'Y', &mut *tm)
  478                  .and_then(|pos| parse_char(s, pos, '-'))
  479                  .and_then(|pos| parse_type(s, pos, 'm', &mut *tm))
  480                  .and_then(|pos| parse_char(s, pos, '-'))
  481                  .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
  482            }
  483            'H' => {
  484              match match_digits_in_range(s, pos, 2u, false, 0_i32, 23_i32) {
  485                Some(item) => { let (v, pos) = item; tm.tm_hour = v; Ok(pos) }
  486                None => Err(~"Invalid hour")
  487              }
  488            }
  489            'I' => {
  490              match match_digits_in_range(s, pos, 2u, false, 1_i32, 12_i32) {
  491                Some(item) => {
  492                    let (v, pos) = item;
  493                    tm.tm_hour = if v == 12_i32 { 0_i32 } else { v };
  494                    Ok(pos)
  495                }
  496                None => Err(~"Invalid hour")
  497              }
  498            }
  499            'j' => {
  500              match match_digits_in_range(s, pos, 3u, false, 1_i32, 366_i32) {
  501                Some(item) => {
  502                  let (v, pos) = item;
  503                  tm.tm_yday = v - 1_i32;
  504                  Ok(pos)
  505                }
  506                None => Err(~"Invalid day of year")
  507              }
  508            }
  509            'k' => {
  510              match match_digits_in_range(s, pos, 2u, true, 0_i32, 23_i32) {
  511                Some(item) => { let (v, pos) = item; tm.tm_hour = v; Ok(pos) }
  512                None => Err(~"Invalid hour")
  513              }
  514            }
  515            'l' => {
  516              match match_digits_in_range(s, pos, 2u, true, 1_i32, 12_i32) {
  517                Some(item) => {
  518                    let (v, pos) = item;
  519                    tm.tm_hour = if v == 12_i32 { 0_i32 } else { v };
  520                    Ok(pos)
  521                }
  522                None => Err(~"Invalid hour")
  523              }
  524            }
  525            'M' => {
  526              match match_digits_in_range(s, pos, 2u, false, 0_i32, 59_i32) {
  527                Some(item) => { let (v, pos) = item; tm.tm_min = v; Ok(pos) }
  528                None => Err(~"Invalid minute")
  529              }
  530            }
  531            'm' => {
  532              match match_digits_in_range(s, pos, 2u, false, 1_i32, 12_i32) {
  533                Some(item) => {
  534                  let (v, pos) = item;
  535                  tm.tm_mon = v - 1_i32;
  536                  Ok(pos)
  537                }
  538                None => Err(~"Invalid month")
  539              }
  540            }
  541            'n' => parse_char(s, pos, '\n'),
  542            'P' => match match_strs(s, pos,
  543                                    [(~"am", 0_i32), (~"pm", 12_i32)]) {
  544  
  545              Some(item) => { let (v, pos) = item; tm.tm_hour += v; Ok(pos) }
  546              None => Err(~"Invalid hour")
  547            },
  548            'p' => match match_strs(s, pos,
  549                                    [(~"AM", 0_i32), (~"PM", 12_i32)]) {
  550  
  551              Some(item) => { let (v, pos) = item; tm.tm_hour += v; Ok(pos) }
  552              None => Err(~"Invalid hour")
  553            },
  554            'R' => {
  555              parse_type(s, pos, 'H', &mut *tm)
  556                  .and_then(|pos| parse_char(s, pos, ':'))
  557                  .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
  558            }
  559            'r' => {
  560              parse_type(s, pos, 'I', &mut *tm)
  561                  .and_then(|pos| parse_char(s, pos, ':'))
  562                  .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
  563                  .and_then(|pos| parse_char(s, pos, ':'))
  564                  .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
  565                  .and_then(|pos| parse_char(s, pos, ' '))
  566                  .and_then(|pos| parse_type(s, pos, 'p', &mut *tm))
  567            }
  568            'S' => {
  569              match match_digits_in_range(s, pos, 2u, false, 0_i32, 60_i32) {
  570                Some(item) => {
  571                  let (v, pos) = item;
  572                  tm.tm_sec = v;
  573                  Ok(pos)
  574                }
  575                None => Err(~"Invalid second")
  576              }
  577            }
  578            //'s' {}
  579            'T' | 'X' => {
  580              parse_type(s, pos, 'H', &mut *tm)
  581                  .and_then(|pos| parse_char(s, pos, ':'))
  582                  .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
  583                  .and_then(|pos| parse_char(s, pos, ':'))
  584                  .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
  585            }
  586            't' => parse_char(s, pos, '\t'),
  587            'u' => {
  588              match match_digits_in_range(s, pos, 1u, false, 1_i32, 7_i32) {
  589                Some(item) => {
  590                  let (v, pos) = item;
  591                  tm.tm_wday = if v == 7 { 0 } else { v };
  592                  Ok(pos)
  593                }
  594                None => Err(~"Invalid day of week")
  595              }
  596            }
  597            'v' => {
  598              parse_type(s, pos, 'e', &mut *tm)
  599                  .and_then(|pos|  parse_char(s, pos, '-'))
  600                  .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
  601                  .and_then(|pos| parse_char(s, pos, '-'))
  602                  .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
  603            }
  604            //'W' {}
  605            'w' => {
  606              match match_digits_in_range(s, pos, 1u, false, 0_i32, 6_i32) {
  607                Some(item) => { let (v, pos) = item; tm.tm_wday = v; Ok(pos) }
  608                None => Err(~"Invalid day of week")
  609              }
  610            }
  611            //'X' {}
  612            //'x' {}
  613            'Y' => {
  614              match match_digits(s, pos, 4u, false) {
  615                Some(item) => {
  616                  let (v, pos) = item;
  617                  tm.tm_year = v - 1900_i32;
  618                  Ok(pos)
  619                }
  620                None => Err(~"Invalid year")
  621              }
  622            }
  623            'y' => {
  624              match match_digits_in_range(s, pos, 2u, false, 0_i32, 99_i32) {
  625                Some(item) => {
  626                  let (v, pos) = item;
  627                  tm.tm_year = v;
  628                  Ok(pos)
  629                }
  630                None => Err(~"Invalid year")
  631              }
  632            }
  633            'Z' => {
  634              if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") {
  635                  tm.tm_gmtoff = 0_i32;
  636                  tm.tm_zone = ~"UTC";
  637                  Ok(pos + 3u)
  638              } else {
  639                  // It's odd, but to maintain compatibility with c's
  640                  // strptime we ignore the timezone.
  641                  let mut pos = pos;
  642                  let len = s.len();
  643                  while pos < len {
  644                      let range = s.char_range_at(pos);
  645                      pos = range.next;
  646                      if range.ch == ' ' { break; }
  647                  }
  648  
  649                  Ok(pos)
  650              }
  651            }
  652            'z' => {
  653              let range = s.char_range_at(pos);
  654  
  655              if range.ch == '+' || range.ch == '-' {
  656                  match match_digits(s, range.next, 4u, false) {
  657                    Some(item) => {
  658                      let (v, pos) = item;
  659                      if v == 0_i32 {
  660                          tm.tm_gmtoff = 0_i32;
  661                          tm.tm_zone = ~"UTC";
  662                      }
  663  
  664                      Ok(pos)
  665                    }
  666                    None => Err(~"Invalid zone offset")
  667                  }
  668              } else {
  669                  Err(~"Invalid zone offset")
  670              }
  671            }
  672            '%' => parse_char(s, pos, '%'),
  673            ch => {
  674              Err(fmt!("unknown formatting type: %?", str::from_char(ch)))
  675            }
  676          }
  677      }
  678  
  679      do io::with_str_reader(format) |rdr| {
  680          let mut tm = Tm {
  681              tm_sec: 0_i32,
  682              tm_min: 0_i32,
  683              tm_hour: 0_i32,
  684              tm_mday: 0_i32,
  685              tm_mon: 0_i32,
  686              tm_year: 0_i32,
  687              tm_wday: 0_i32,
  688              tm_yday: 0_i32,
  689              tm_isdst: 0_i32,
  690              tm_gmtoff: 0_i32,
  691              tm_zone: ~"",
  692              tm_nsec: 0_i32,
  693          };
  694          let mut pos = 0u;
  695          let len = s.len();
  696          let mut result = Err(~"Invalid time");
  697  
  698          while !rdr.eof() && pos < len {
  699              let range = s.char_range_at(pos);
  700              let ch = range.ch;
  701              let next = range.next;
  702  
  703              match rdr.read_char() {
  704                  '%' => {
  705                      match parse_type(s, pos, rdr.read_char(), &mut tm) {
  706                          Ok(next) => pos = next,
  707                          Err(e) => { result = Err(e); break; }
  708                      }
  709                  },
  710                  c => {
  711                      if c != ch { break }
  712                      pos = next;
  713                  }
  714              }
  715          }
  716  
  717          if pos == len && rdr.eof() {
  718              Ok(Tm {
  719                  tm_sec: tm.tm_sec,
  720                  tm_min: tm.tm_min,
  721                  tm_hour: tm.tm_hour,
  722                  tm_mday: tm.tm_mday,
  723                  tm_mon: tm.tm_mon,
  724                  tm_year: tm.tm_year,
  725                  tm_wday: tm.tm_wday,
  726                  tm_yday: tm.tm_yday,
  727                  tm_isdst: tm.tm_isdst,
  728                  tm_gmtoff: tm.tm_gmtoff,
  729                  tm_zone: tm.tm_zone.clone(),
  730                  tm_nsec: tm.tm_nsec,
  731              })
  732          } else { result }
  733      }
  734  }
  735  
  736  fn do_strftime(format&str, tm&Tm) -> ~str {
  737      fn parse_type(chchar, tm&Tm) -> ~str {
  738          //FIXME (#2350): Implement missing types.
  739        let die = || fmt!("strftime: can't understand this format %c ", ch);
  740          match ch {
  741            'A' => match tm.tm_wday as int {
  742              0 => ~"Sunday",
  743              1 => ~"Monday",
  744              2 => ~"Tuesday",
  745              3 => ~"Wednesday",
  746              4 => ~"Thursday",
  747              5 => ~"Friday",
  748              6 => ~"Saturday",
  749              _ => die()
  750            },
  751           'a' => match tm.tm_wday as int {
  752              0 => ~"Sun",
  753              1 => ~"Mon",
  754              2 => ~"Tue",
  755              3 => ~"Wed",
  756              4 => ~"Thu",
  757              5 => ~"Fri",
  758              6 => ~"Sat",
  759              _ => die()
  760            },
  761            'B' => match tm.tm_mon as int {
  762              0 => ~"January",
  763              1 => ~"February",
  764              2 => ~"March",
  765              3 => ~"April",
  766              4 => ~"May",
  767              5 => ~"June",
  768              6 => ~"July",
  769              7 => ~"August",
  770              8 => ~"September",
  771              9 => ~"October",
  772              10 => ~"November",
  773              11 => ~"December",
  774              _ => die()
  775            },
  776            'b' | 'h' => match tm.tm_mon as int {
  777              0 => ~"Jan",
  778              1 => ~"Feb",
  779              2 => ~"Mar",
  780              3 => ~"Apr",
  781              4 => ~"May",
  782              5 => ~"Jun",
  783              6 => ~"Jul",
  784              7 => ~"Aug",
  785              8 => ~"Sep",
  786              9 => ~"Oct",
  787              10 => ~"Nov",
  788              11 => ~"Dec",
  789              _  => die()
  790            },
  791            'C' => fmt!("%02d", (tm.tm_year as int + 1900) / 100),
  792            'c' => {
  793              fmt!("%s %s %s %s %s",
  794                  parse_type('a', tm),
  795                  parse_type('b', tm),
  796                  parse_type('e', tm),
  797                  parse_type('T', tm),
  798                  parse_type('Y', tm))
  799            }
  800            'D' | 'x' => {
  801              fmt!("%s/%s/%s",
  802                  parse_type('m', tm),
  803                  parse_type('d', tm),
  804                  parse_type('y', tm))
  805            }
  806            'd' => fmt!("%02d", tm.tm_mday as int),
  807            'e' => fmt!("%2d", tm.tm_mday as int),
  808            'f' => fmt!("%09d", tm.tm_nsec as int),
  809            'F' => {
  810              fmt!("%s-%s-%s",
  811                  parse_type('Y', tm),
  812                  parse_type('m', tm),
  813                  parse_type('d', tm))
  814            }
  815            //'G' {}
  816            //'g' {}
  817            'H' => fmt!("%02d", tm.tm_hour as int),
  818            'I' => {
  819              let mut h = tm.tm_hour as int;
  820              if h == 0 { h = 12 }
  821              if h > 12 { h -= 12 }
  822              fmt!("%02d", h)
  823            }
  824            'j' => fmt!("%03d", tm.tm_yday as int + 1),
  825            'k' => fmt!("%2d", tm.tm_hour as int),
  826            'l' => {
  827              let mut h = tm.tm_hour as int;
  828              if h == 0 { h = 12 }
  829              if h > 12 { h -= 12 }
  830              fmt!("%2d", h)
  831            }
  832            'M' => fmt!("%02d", tm.tm_min as int),
  833            'm' => fmt!("%02d", tm.tm_mon as int + 1),
  834            'n' => ~"\n",
  835            'P' => if (tm.tm_hour as int) < 12 { ~"am" } else { ~"pm" },
  836            'p' => if (tm.tm_hour as int) < 12 { ~"AM" } else { ~"PM" },
  837            'R' => {
  838              fmt!("%s:%s",
  839                  parse_type('H', tm),
  840                  parse_type('M', tm))
  841            }
  842            'r' => {
  843              fmt!("%s:%s:%s %s",
  844                  parse_type('I', tm),
  845                  parse_type('M', tm),
  846                  parse_type('S', tm),
  847                  parse_type('p', tm))
  848            }
  849            'S' => fmt!("%02d", tm.tm_sec as int),
  850            's' => fmt!("%d", tm.to_timespec().sec as int),
  851            'T' | 'X' => {
  852              fmt!("%s:%s:%s",
  853                  parse_type('H', tm),
  854                  parse_type('M', tm),
  855                  parse_type('S', tm))
  856            }
  857            't' => ~"\t",
  858            //'U' {}
  859            'u' => {
  860              let i = tm.tm_wday as int;
  861              (if i == 0 { 7 } else { i }).to_str()
  862            }
  863            //'V' {}
  864            'v' => {
  865              fmt!("%s-%s-%s",
  866                  parse_type('e', tm),
  867                  parse_type('b', tm),
  868                  parse_type('Y', tm))
  869            }
  870            //'W' {}
  871            'w' => (tm.tm_wday as int).to_str(),
  872            //'X' {}
  873            //'x' {}
  874            'Y' => (tm.tm_year as int + 1900).to_str(),
  875            'y' => fmt!("%02d", (tm.tm_year as int + 1900) % 100),
  876            'Z' => tm.tm_zone.clone(),
  877            'z' => {
  878              let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' };
  879              let mut m = num::abs(tm.tm_gmtoff) / 60_i32;
  880              let h = m / 60_i32;
  881              m -= h * 60_i32;
  882              fmt!("%c%02d%02d", sign, h as int, m as int)
  883            }
  884            //'+' {}
  885            '%' => ~"%",
  886            _   => die()
  887          }
  888      }
  889  
  890      let mut buf = ~"";
  891  
  892      do io::with_str_reader(format) |rdr| {
  893          while !rdr.eof() {
  894              match rdr.read_char() {
  895                  '%' => buf.push_str(parse_type(rdr.read_char(), tm)),
  896                  ch => buf.push_char(ch)
  897              }
  898          }
  899      }
  900  
  901      buf
  902  }
  903  
  904  #[cfg(test)]
  905  mod tests {
  906      use super::*;
  907  
  908      use std::float;
  909      use std::os;
  910      use std::result::{Err, Ok};
  911  
  912      fn test_get_time() {
  913          static SOME_RECENT_DATE: i64 = 1325376000i64; // 2012-01-01T00:00:00Z
  914          static SOME_FUTURE_DATE: i64 = 1577836800i64; // 2020-01-01T00:00:00Z
  915  
  916          let tv1 = get_time();
  917          debug!("tv1=%? sec + %? nsec", tv1.sec as uint, tv1.nsec as uint);
  918  
  919          assert!(tv1.sec > SOME_RECENT_DATE);
  920          assert!(tv1.nsec < 1000000000i32);
  921  
  922          let tv2 = get_time();
  923          debug!("tv2=%? sec + %? nsec", tv2.sec as uint, tv2.nsec as uint);
  924  
  925          assert!(tv2.sec >= tv1.sec);
  926          assert!(tv2.sec < SOME_FUTURE_DATE);
  927          assert!(tv2.nsec < 1000000000i32);
  928          if tv2.sec == tv1.sec {
  929              assert!(tv2.nsec >= tv1.nsec);
  930          }
  931      }
  932  
  933      fn test_precise_time() {
  934          let s0 = precise_time_s();
  935          let ns1 = precise_time_ns();
  936  
  937          debug!("s0=%s sec", float::to_str_digits(s0, 9u));
  938          assert!(s0 > 0.);
  939          let ns0 = (s0 * 1000000000.) as u64;
  940          debug!("ns0=%? ns", ns0);
  941  
  942          debug!("ns1=%? ns", ns0);
  943          assert!(ns1 >= ns0);
  944  
  945          let ns2 = precise_time_ns();
  946          debug!("ns2=%? ns", ns0);
  947          assert!(ns2 >= ns1);
  948      }
  949  
  950      fn test_at_utc() {
  951          os::setenv("TZ", "America/Los_Angeles");
  952          tzset();
  953  
  954          let time = Timespec::new(1234567890, 54321);
  955          let utc = at_utc(time);
  956  
  957          assert!(utc.tm_sec == 30_i32);
  958          assert!(utc.tm_min == 31_i32);
  959          assert!(utc.tm_hour == 23_i32);
  960          assert!(utc.tm_mday == 13_i32);
  961          assert!(utc.tm_mon == 1_i32);
  962          assert!(utc.tm_year == 109_i32);
  963          assert!(utc.tm_wday == 5_i32);
  964          assert!(utc.tm_yday == 43_i32);
  965          assert!(utc.tm_isdst == 0_i32);
  966          assert!(utc.tm_gmtoff == 0_i32);
  967          assert!(utc.tm_zone == ~"UTC");
  968          assert!(utc.tm_nsec == 54321_i32);
  969      }
  970  
  971      fn test_at() {
  972          os::setenv("TZ", "America/Los_Angeles");
  973          tzset();
  974  
  975          let time = Timespec::new(1234567890, 54321);
  976          let local = at(time);
  977  
  978          error!("time_at: %?", local);
  979  
  980          assert!(local.tm_sec == 30_i32);
  981          assert!(local.tm_min == 31_i32);
  982          assert!(local.tm_hour == 15_i32);
  983          assert!(local.tm_mday == 13_i32);
  984          assert!(local.tm_mon == 1_i32);
  985          assert!(local.tm_year == 109_i32);
  986          assert!(local.tm_wday == 5_i32);
  987          assert!(local.tm_yday == 43_i32);
  988          assert!(local.tm_isdst == 0_i32);
  989          assert!(local.tm_gmtoff == -28800_i32);
  990  
  991          // FIXME (#2350): We should probably standardize on the timezone
  992          // abbreviation.
  993          let zone = &local.tm_zone;
  994          assert!(*zone == ~"PST" || *zone == ~"Pacific Standard Time");
  995  
  996          assert!(local.tm_nsec == 54321_i32);
  997      }
  998  
  999      fn test_to_timespec() {
 1000          os::setenv("TZ", "America/Los_Angeles");
 1001          tzset();
 1002  
 1003          let time = Timespec::new(1234567890, 54321);
 1004          let utc = at_utc(time);
 1005  
 1006          assert_eq!(utc.to_timespec(), time);
 1007          assert_eq!(utc.to_local().to_timespec(), time);
 1008      }
 1009  
 1010      fn test_conversions() {
 1011          os::setenv("TZ", "America/Los_Angeles");
 1012          tzset();
 1013  
 1014          let time = Timespec::new(1234567890, 54321);
 1015          let utc = at_utc(time);
 1016          let local = at(time);
 1017  
 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);
 1024      }
 1025  
 1026      fn test_strptime() {
 1027          os::setenv("TZ", "America/Los_Angeles");
 1028          tzset();
 1029  
 1030          match strptime("", "") {
 1031            Ok(ref tm) => {
 1032              assert!(tm.tm_sec == 0_i32);
 1033              assert!(tm.tm_min == 0_i32);
 1034              assert!(tm.tm_hour == 0_i32);
 1035              assert!(tm.tm_mday == 0_i32);
 1036              assert!(tm.tm_mon == 0_i32);
 1037              assert!(tm.tm_year == 0_i32);
 1038              assert!(tm.tm_wday == 0_i32);
 1039              assert!(tm.tm_isdst == 0_i32);
 1040              assert!(tm.tm_gmtoff == 0_i32);
 1041              assert!(tm.tm_zone == ~"");
 1042              assert!(tm.tm_nsec == 0_i32);
 1043            }
 1044            Err(_) => ()
 1045          }
 1046  
 1047          let format = "%a %b %e %T.%f %Y";
 1048          assert_eq!(strptime("", format), Err(~"Invalid time"));
 1049          assert!(strptime("Fri Feb 13 15:31:30", format)
 1050              == Err(~"Invalid time"));
 1051  
 1052          match strptime("Fri Feb 13 15:31:30.01234 2009", format) {
 1053            Err(e) => fail!(e),
 1054            Ok(ref tm) => {
 1055              assert!(tm.tm_sec == 30_i32);
 1056              assert!(tm.tm_min == 31_i32);
 1057              assert!(tm.tm_hour == 15_i32);
 1058              assert!(tm.tm_mday == 13_i32);
 1059              assert!(tm.tm_mon == 1_i32);
 1060              assert!(tm.tm_year == 109_i32);
 1061              assert!(tm.tm_wday == 5_i32);
 1062              assert!(tm.tm_yday == 0_i32);
 1063              assert!(tm.tm_isdst == 0_i32);
 1064              assert!(tm.tm_gmtoff == 0_i32);
 1065              assert!(tm.tm_zone == ~"");
 1066              assert!(tm.tm_nsec == 12340000_i32);
 1067            }
 1068          }
 1069  
 1070          fn test(s: &str, format: &str) -> bool {
 1071              match strptime(s, format) {
 1072                Ok(ref tm) => tm.strftime(format) == s.to_owned(),
 1073                Err(e) => fail!(e)
 1074              }
 1075          }
 1076  
 1077          let days = [
 1078              ~"Sunday",
 1079              ~"Monday",
 1080              ~"Tuesday",
 1081              ~"Wednesday",
 1082              ~"Thursday",
 1083              ~"Friday",
 1084              ~"Saturday"
 1085          ];
 1086          for day in days.iter() {
 1087              assert!(test(*day, "%A"));
 1088          }
 1089  
 1090          let days = [
 1091              ~"Sun",
 1092              ~"Mon",
 1093              ~"Tue",
 1094              ~"Wed",
 1095              ~"Thu",
 1096              ~"Fri",
 1097              ~"Sat"
 1098          ];
 1099          for day in days.iter() {
 1100              assert!(test(*day, "%a"));
 1101          }
 1102  
 1103          let months = [
 1104              ~"January",
 1105              ~"February",
 1106              ~"March",
 1107              ~"April",
 1108              ~"May",
 1109              ~"June",
 1110              ~"July",
 1111              ~"August",
 1112              ~"September",
 1113              ~"October",
 1114              ~"November",
 1115              ~"December"
 1116          ];
 1117          for day in months.iter() {
 1118              assert!(test(*day, "%B"));
 1119          }
 1120  
 1121          let months = [
 1122              ~"Jan",
 1123              ~"Feb",
 1124              ~"Mar",
 1125              ~"Apr",
 1126              ~"May",
 1127              ~"Jun",
 1128              ~"Jul",
 1129              ~"Aug",
 1130              ~"Sep",
 1131              ~"Oct",
 1132              ~"Nov",
 1133              ~"Dec"
 1134          ];
 1135          for day in months.iter() {
 1136              assert!(test(*day, "%b"));
 1137          }
 1138  
 1139          assert!(test("19", "%C"));
 1140          assert!(test("Fri Feb 13 23:31:30 2009", "%c"));
 1141          assert!(test("02/13/09", "%D"));
 1142          assert!(test("03", "%d"));
 1143          assert!(test("13", "%d"));
 1144          assert!(test(" 3", "%e"));
 1145          assert!(test("13", "%e"));
 1146          assert!(test("2009-02-13", "%F"));
 1147          assert!(test("03", "%H"));
 1148          assert!(test("13", "%H"));
 1149          assert!(test("03", "%I")); // FIXME (#2350): flesh out
 1150          assert!(test("11", "%I")); // FIXME (#2350): flesh out
 1151          assert!(test("044", "%j"));
 1152          assert!(test(" 3", "%k"));
 1153          assert!(test("13", "%k"));
 1154          assert!(test(" 1", "%l"));
 1155          assert!(test("11", "%l"));
 1156          assert!(test("03", "%M"));
 1157          assert!(test("13", "%M"));
 1158          assert!(test("\n", "%n"));
 1159          assert!(test("am", "%P"));
 1160          assert!(test("pm", "%P"));
 1161          assert!(test("AM", "%p"));
 1162          assert!(test("PM", "%p"));
 1163          assert!(test("23:31", "%R"));
 1164          assert!(test("11:31:30 AM", "%r"));
 1165          assert!(test("11:31:30 PM", "%r"));
 1166          assert!(test("03", "%S"));
 1167          assert!(test("13", "%S"));
 1168          assert!(test("15:31:30", "%T"));
 1169          assert!(test("\t", "%t"));
 1170          assert!(test("1", "%u"));
 1171          assert!(test("7", "%u"));
 1172          assert!(test("13-Feb-2009", "%v"));
 1173          assert!(test("0", "%w"));
 1174          assert!(test("6", "%w"));
 1175          assert!(test("2009", "%Y"));
 1176          assert!(test("09", "%y"));
 1177          assert!(strptime("UTC", "%Z").unwrap().tm_zone ==
 1178              ~"UTC");
 1179          assert!(strptime("PST", "%Z").unwrap().tm_zone ==
 1180              ~"");
 1181          assert!(strptime("-0000", "%z").unwrap().tm_gmtoff ==
 1182              0);
 1183          assert!(strptime("-0800", "%z").unwrap().tm_gmtoff ==
 1184              0);
 1185          assert!(test("%", "%%"));
 1186  
 1187          // Test for #7256
 1188          assert_eq!(strptime("360", "%Y-%m-%d"), Err(~"Invalid year"))
 1189      }
 1190  
 1191      fn test_ctime() {
 1192          os::setenv("TZ", "America/Los_Angeles");
 1193          tzset();
 1194  
 1195          let time = Timespec::new(1234567890, 54321);
 1196          let utc   = at_utc(time);
 1197          let local = at(time);
 1198  
 1199          error!("test_ctime: %? %?", utc.ctime(), local.ctime());
 1200  
 1201          assert_eq!(utc.ctime(), ~"Fri Feb 13 23:31:30 2009");
 1202          assert_eq!(local.ctime(), ~"Fri Feb 13 15:31:30 2009");
 1203      }
 1204  
 1205      fn test_strftime() {
 1206          os::setenv("TZ", "America/Los_Angeles");
 1207          tzset();
 1208  
 1209          let time = Timespec::new(1234567890, 54321);
 1210          let utc = at_utc(time);
 1211          let local = at(time);
 1212  
 1213          assert_eq!(local.strftime(""), ~"");
 1214          assert_eq!(local.strftime("%A"), ~"Friday");
 1215          assert_eq!(local.strftime("%a"), ~"Fri");
 1216          assert_eq!(local.strftime("%B"), ~"February");
 1217          assert_eq!(local.strftime("%b"), ~"Feb");
 1218          assert_eq!(local.strftime("%C"), ~"20");
 1219          assert_eq!(local.strftime("%c"), ~"Fri Feb 13 15:31:30 2009");
 1220          assert_eq!(local.strftime("%D"), ~"02/13/09");
 1221          assert_eq!(local.strftime("%d"), ~"13");
 1222          assert_eq!(local.strftime("%e"), ~"13");
 1223          assert_eq!(local.strftime("%f"), ~"000054321");
 1224          assert_eq!(local.strftime("%F"), ~"2009-02-13");
 1225          // assert!(local.strftime("%G") == "2009");
 1226          // assert!(local.strftime("%g") == "09");
 1227          assert_eq!(local.strftime("%H"), ~"15");
 1228          assert_eq!(local.strftime("%I"), ~"03");
 1229          assert_eq!(local.strftime("%j"), ~"044");
 1230          assert_eq!(local.strftime("%k"), ~"15");
 1231          assert_eq!(local.strftime("%l"), ~" 3");
 1232          assert_eq!(local.strftime("%M"), ~"31");
 1233          assert_eq!(local.strftime("%m"), ~"02");
 1234          assert_eq!(local.strftime("%n"), ~"\n");
 1235          assert_eq!(local.strftime("%P"), ~"pm");
 1236          assert_eq!(local.strftime("%p"), ~"PM");
 1237          assert_eq!(local.strftime("%R"), ~"15:31");
 1238          assert_eq!(local.strftime("%r"), ~"03:31:30 PM");
 1239          assert_eq!(local.strftime("%S"), ~"30");
 1240          assert_eq!(local.strftime("%s"), ~"1234567890");
 1241          assert_eq!(local.strftime("%T"), ~"15:31:30");
 1242          assert_eq!(local.strftime("%t"), ~"\t");
 1243          // assert!(local.strftime("%U") == "06");
 1244          assert_eq!(local.strftime("%u"), ~"5");
 1245          // assert!(local.strftime("%V") == "07");
 1246          assert_eq!(local.strftime("%v"), ~"13-Feb-2009");
 1247          // assert!(local.strftime("%W") == "06");
 1248          assert_eq!(local.strftime("%w"), ~"5");
 1249          // handle "%X"
 1250          // handle "%x"
 1251          assert_eq!(local.strftime("%Y"), ~"2009");
 1252          assert_eq!(local.strftime("%y"), ~"09");
 1253  
 1254          // FIXME (#2350): We should probably standardize on the timezone
 1255          // abbreviation.
 1256          let zone = local.strftime("%Z");
 1257          assert!(zone == ~"PST" || zone == ~"Pacific Standard Time");
 1258  
 1259          assert_eq!(local.strftime("%z"), ~"-0800");
 1260          assert_eq!(local.strftime("%%"), ~"%");
 1261  
 1262          // FIXME (#2350): We should probably standardize on the timezone
 1263          // abbreviation.
 1264          let rfc822 = local.rfc822();
 1265          let prefix = ~"Fri, 13 Feb 2009 15:31:30 ";
 1266          assert!(rfc822 == prefix + "PST" ||
 1267                       rfc822 == prefix + "Pacific Standard Time");
 1268  
 1269          assert_eq!(local.ctime(), ~"Fri Feb 13 15:31:30 2009");
 1270          assert_eq!(local.rfc822z(), ~"Fri, 13 Feb 2009 15:31:30 -0800");
 1271          assert_eq!(local.rfc3339(), ~"2009-02-13T15:31:30-08:00");
 1272  
 1273          assert_eq!(utc.ctime(), ~"Fri Feb 13 23:31:30 2009");
 1274          assert_eq!(utc.rfc822(), ~"Fri, 13 Feb 2009 23:31:30 GMT");
 1275          assert_eq!(utc.rfc822z(), ~"Fri, 13 Feb 2009 23:31:30 -0000");
 1276          assert_eq!(utc.rfc3339(), ~"2009-02-13T23:31:30Z");
 1277      }
 1278  
 1279      fn test_timespec_eq_ord() {
 1280          let a = &Timespec::new(-2, 1);
 1281          let b = &Timespec::new(-1, 2);
 1282          let c = &Timespec::new(1, 2);
 1283          let d = &Timespec::new(2, 1);
 1284          let e = &Timespec::new(2, 1);
 1285  
 1286          assert!(d.eq(e));
 1287          assert!(c.ne(e));
 1288  
 1289          assert!(a.lt(b));
 1290          assert!(b.lt(c));
 1291          assert!(c.lt(d));
 1292  
 1293          assert!(a.le(b));
 1294          assert!(b.le(c));
 1295          assert!(c.le(d));
 1296          assert!(d.le(e));
 1297          assert!(e.le(d));
 1298  
 1299          assert!(b.ge(a));
 1300          assert!(c.ge(b));
 1301          assert!(d.ge(c));
 1302          assert!(e.ge(d));
 1303          assert!(d.ge(e));
 1304  
 1305          assert!(b.gt(a));
 1306          assert!(c.gt(b));
 1307          assert!(d.gt(c));
 1308      }
 1309  
 1310      #[test]
 1311      fn run_tests() {
 1312          // The tests race on tzset. So instead of having many independent
 1313          // tests, we will just call the functions now.
 1314          test_get_time();
 1315          test_precise_time();
 1316          test_at_utc();
 1317          test_at();
 1318          test_to_timespec();
 1319          test_conversions();
 1320          test_strptime();
 1321          test_ctime();
 1322          test_strftime();
 1323          test_timespec_eq_ord();
 1324      }
 1325  }

libextra/time.rs:122:1-122:1 -fn- definition:

pub fn empty_tm() -> Tm {
references:-
166:         let mut tm = empty_tm();
149:         let mut tm = empty_tm();


libextra/time.rs:361:4-361:4 -fn- definition:
    fn parse_char(s: &str, pos: uint, c: char) -> Result<uint, ~str> {
        let range = s.char_range_at(pos);
references:-
601:                 .and_then(|pos| parse_char(s, pos, '-'))
456:                 .and_then(|pos| parse_char(s, pos, '/'))
561:                 .and_then(|pos| parse_char(s, pos, ':'))
556:                 .and_then(|pos| parse_char(s, pos, ':'))
480:                 .and_then(|pos| parse_char(s, pos, '-'))
451:                 .and_then(|pos| parse_char(s, pos, ' '))
449:                 .and_then(|pos| parse_char(s, pos, ' '))
672:           '%' => parse_char(s, pos, '%'),
583:                 .and_then(|pos| parse_char(s, pos, ':'))
563:                 .and_then(|pos| parse_char(s, pos, ':'))
447:                 .and_then(|pos| parse_char(s, pos, ' '))
581:                 .and_then(|pos| parse_char(s, pos, ':'))
599:                 .and_then(|pos|  parse_char(s, pos, '-'))
478:                 .and_then(|pos| parse_char(s, pos, '-'))
445:                 .and_then(|pos| parse_char(s, pos, ' '))
565:                 .and_then(|pos| parse_char(s, pos, ' '))
586:           't' => parse_char(s, pos, '\t'),
541:           'n' => parse_char(s, pos, '\n'),
458:                 .and_then(|pos| parse_char(s, pos, '/'))


libextra/time.rs:735:1-735:1 -fn- definition:

fn do_strftime(format: &str, tm: &Tm) -> ~str {
references:-
184:     do_strftime(format, tm)


libextra/time.rs:63:4-63:4 -fn- definition:
 */
pub fn get_time() -> Timespec {
references:-
174:     at(get_time())
157:     at_utc(get_time())


libextra/time.rs:107:56-107:56 -struct- definition:
#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
pub struct Tm {
references:-
144: pub fn at_utc(clock: Timespec) -> Tm {
203:     pub fn to_local(&self) -> Tm {
267: fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> {
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
30:         pub fn rust_mktime(tm: &Tm) -> i64;
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
736: fn do_strftime(format: &str, tm: &Tm) -> ~str {
127:     Tm {
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
183: pub fn strftime(format: &str, tm: &Tm) -> ~str {
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
27:         pub fn rust_gmtime(sec: i64, nsec: i32, result: &mut Tm);
156: pub fn now_utc() -> Tm {
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
173: pub fn now() -> Tm {
208:     pub fn to_utc(&self) -> Tm {
29:         pub fn rust_timegm(tm: &Tm) -> i64;
123: pub fn empty_tm() -> Tm {
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
178: pub fn strptime(s: &str, format: &str) -> Result<Tm, ~str> {
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
680:         let mut tm = Tm {
107: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
(718)(107)(107)(737)(107)(373)(161)(107)(187)(28)
<quote expansion>:
(2)

libextra/time.rs:266:1-266:1 -fn- definition:

fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> {
references:-
179:     do_strptime(s, format)


libextra/time.rs:35:56-35:56 -struct- definition:
#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
pub struct Timespec { sec: i64, nsec: i32 }
references:-
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
161: pub fn at(clock: Timespec) -> Tm {
49:         Timespec { sec: sec, nsec: nsec }
53: impl Ord for Timespec {
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
46: impl Timespec {
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
189:     pub fn to_timespec(&self) -> Timespec {
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
64: pub fn get_time() -> Timespec {
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
47:     pub fn new(sec: i64, nsec: i32) -> Timespec {
54:     fn lt(&self, other: &Timespec) -> bool {
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
144: pub fn at_utc(clock: Timespec) -> Tm {
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
165:         let Timespec { sec, nsec } = clock;
148:         let Timespec { sec, nsec } = clock;
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
35: #[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
<quote expansion>:
(2)

libextra/time.rs:351:4-351:4 -fn- definition:
    fn match_digits_in_range(ss: &str, pos: uint, digits: uint, ws: bool,
                             min: i32, max: i32) -> Option<(i32, uint)> {
references:-
484:             match match_digits_in_range(s, pos, 2u, false, 0_i32, 23_i32) {
588:             match match_digits_in_range(s, pos, 1u, false, 1_i32, 7_i32) {
490:             match match_digits_in_range(s, pos, 2u, false, 1_i32, 12_i32) {
510:             match match_digits_in_range(s, pos, 2u, true, 0_i32, 23_i32) {
526:             match match_digits_in_range(s, pos, 2u, false, 0_i32, 59_i32) {
606:             match match_digits_in_range(s, pos, 1u, false, 0_i32, 6_i32) {
532:             match match_digits_in_range(s, pos, 2u, false, 1_i32, 12_i32) {
434:           'C' => match match_digits_in_range(s, pos, 2u, false, 0_i32,
500:             match match_digits_in_range(s, pos, 3u, false, 1_i32, 366_i32) {
461:           'd' => match match_digits_in_range(s, pos, 2u, false, 1_i32,
466:           'e' => match match_digits_in_range(s, pos, 2u, true, 1_i32,
569:             match match_digits_in_range(s, pos, 2u, false, 0_i32, 60_i32) {
516:             match match_digits_in_range(s, pos, 2u, true, 1_i32, 12_i32) {
624:             match match_digits_in_range(s, pos, 2u, false, 0_i32, 99_i32) {


libextra/time.rs:143:38-143:38 -fn- definition:
/// Returns the specified time in UTC
pub fn at_utc(clock: Timespec) -> Tm {
references:-
157:     at_utc(get_time())
209:         at_utc(self.to_timespec())


libextra/time.rs:79:4-79:4 -fn- definition:
 */
pub fn precise_time_ns() -> u64 {
references:-
96:     return (precise_time_ns() as float) / 1000000000.;
libextra/test.rs:
1091:             let now = precise_time_ns();
1023:         self.ns_end = precise_time_ns();
1067:             let loop_start = precise_time_ns();
1018:         self.ns_start = precise_time_ns();


libextra/time.rs:737:4-737:4 -fn- definition:
    fn parse_type(ch: char, tm: &Tm) -> ~str {
        //FIXME (#2350): Implement missing types.
references:-
794:                 parse_type('a', tm),
867:                 parse_type('b', tm),
847:                 parse_type('p', tm))
797:                 parse_type('T', tm),
796:                 parse_type('e', tm),
795:                 parse_type('b', tm),
855:                 parse_type('S', tm))
895:                 '%' => buf.push_str(parse_type(rdr.read_char(), tm)),
812:                 parse_type('m', tm),
813:                 parse_type('d', tm))
854:                 parse_type('M', tm),
866:                 parse_type('e', tm),
811:                 parse_type('Y', tm),
840:                 parse_type('M', tm))
846:                 parse_type('S', tm),
845:                 parse_type('M', tm),
798:                 parse_type('Y', tm))
839:                 parse_type('H', tm),
804:                 parse_type('y', tm))
803:                 parse_type('d', tm),
868:                 parse_type('Y', tm))
853:                 parse_type('H', tm),
844:                 parse_type('I', tm),
802:                 parse_type('m', tm),


libextra/time.rs:268:4-268:4 -fn- definition:
    fn match_str(s: &str, pos: uint, needle: &str) -> bool {
        let mut i = pos;
references:-
634:             if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") {
286:                     if match_str(ss, pos, *needle) {
634:             if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") {


libextra/time.rs:160:53-160:53 -fn- definition:
/// Returns the specified time in the local timezone
pub fn at(clock: Timespec) -> Tm {
references:-
174:     at(get_time())
204:         at(self.to_timespec())


libextra/time.rs:324:4-324:4 -fn- definition:
    fn match_fractional_seconds(ss: &str, pos: uint) -> (i32, uint) {
        let len = ss.len();
references:-
472:             let (val, pos) = match_fractional_seconds(s, pos);


libextra/time.rs:297:4-297:4 -fn- definition:
    fn match_digits(ss: &str, pos: uint, digits: uint, ws: bool)
      -> Option<(i32, uint)> {
references:-
614:             match match_digits(s, pos, 4u, false) {
656:                 match match_digits(s, range.next, 4u, false) {
353:         match match_digits(ss, pos, digits, ws) {


libextra/time.rs:279:4-279:4 -fn- definition:
    fn match_strs(ss: &str, pos: uint, strs: &[(~str, i32)])
      -> Option<(i32, uint)> {
references:-
548:           'p' => match match_strs(s, pos,
388:           'a' => match match_strs(s, pos, [
417:           'b' | 'h' => match match_strs(s, pos, [
400:           'B' => match match_strs(s, pos, [
376:           'A' => match match_strs(s, pos, [
542:           'P' => match match_strs(s, pos,


libextra/time.rs:373:4-373:4 -fn- definition:
    fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
      -> Result<uint, ~str> {
references:-
446:                 .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
580:             parse_type(s, pos, 'H', &mut *tm)
477:             parse_type(s, pos, 'Y', &mut *tm)
705:                     match parse_type(s, pos, rdr.read_char(), &mut tm) {
582:                 .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
455:             parse_type(s, pos, 'm', &mut *tm)
584:                 .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
555:             parse_type(s, pos, 'H', &mut *tm)
450:                 .and_then(|pos| parse_type(s, pos, 'T', &mut *tm))
564:                 .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
459:                 .and_then(|pos| parse_type(s, pos, 'y', &mut *tm))
557:                 .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
602:                 .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
562:                 .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
448:                 .and_then(|pos| parse_type(s, pos, 'e', &mut *tm))
457:                 .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
479:                 .and_then(|pos| parse_type(s, pos, 'm', &mut *tm))
566:                 .and_then(|pos| parse_type(s, pos, 'p', &mut *tm))
560:             parse_type(s, pos, 'I', &mut *tm)
452:                 .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
481:                 .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
600:                 .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
598:             parse_type(s, pos, 'e', &mut *tm)
444:             parse_type(s, pos, 'a', &mut *tm)


libextra/time.rs:182:53-182:53 -fn- definition:
/// Formats the time according to the format string.
pub fn strftime(format: &str, tm: &Tm) -> ~str {
references:-
220:         strftime(format, self)