(index<- )        ./libtime/lib.rs

    1  // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
    2  // file at the top-level directory of this distribution and at
    3  // http://rust-lang.org/COPYRIGHT.
    4  //
    5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
    6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
    7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
    8  // option. This file may not be copied, modified, or distributed
    9  // except according to those terms.
   10  
   11  #![crate_id = "time#0.11-pre"]
   12  #![crate_type = "rlib"]
   13  #![crate_type = "dylib"]
   14  #![license = "MIT/ASL2"]
   15  #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
   16         html_favicon_url = "http://www.rust-lang.org/favicon.ico",
   17         html_root_url = "http://static.rust-lang.org/doc/master")]
   18  #![feature(phase)]
   19  #![deny(deprecated_owned_vector)]
   20  
   21  #[cfg(test)] #[phase(syntax, link)] extern crate log;
   22  extern crate serialize;
   23  extern crate libc;
   24  
   25  use std::io::BufReader;
   26  use std::num;
   27  use std::str;
   28  
   29  static NSEC_PER_SEC: i32 = 1_000_000_000_i32;
   30  
   31  mod rustrt {
   32      use super::Tm;
   33  
   34      extern {
   35          pub fn rust_tzset();
   36          pub fn rust_gmtime(seci64, nseci32, result&mut Tm);
   37          pub fn rust_localtime(seci64, nseci32, result&mut Tm);
   38          pub fn rust_timegm(tm&Tm) -> i64;
   39          pub fn rust_mktime(tm&Tm) -> i64;
   40      }
   41  }
   42  
   43  #[cfg(unix, not(target_os = "macos"))]
   44  mod imp {
   45      use libc::{c_int, timespec};
   46  
   47      // Apparently android provides this in some other library?
   48      #[cfg(not(target_os = "android"))]
   49      #[link(name = "rt")]
   50      extern {}
   51  
   52      extern {
   53          pub fn clock_gettime(clk_idc_int, tp*mut timespec) -> c_int;
   54      }
   55  
   56  }
   57  #[cfg(target_os = "macos")]
   58  mod imp {
   59      use libc::{timeval, timezone, c_int, mach_timebase_info};
   60  
   61      extern {
   62          pub fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int;
   63          pub fn mach_absolute_time() -> u64;
   64          pub fn mach_timebase_info(info: *mut mach_timebase_info) -> c_int;
   65      }
   66  }
   67  
   68  /// A record specifying a time value in seconds and nanoseconds.
   69  #[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, Encodable, Decodable, Show)]
   70  pub struct Timespec { pub sec: i64, pub nsec: i32 }
   71  /*
   72   * Timespec assumes that pre-epoch Timespecs have negative sec and positive
   73   * nsec fields. Darwin's and Linux's struct timespec functions handle pre-
   74   * epoch timestamps using a "two steps back, one step forward" representation,
   75   * though the man pages do not actually document this. For example, the time
   76   * -1.2 seconds before the epoch is represented by `Timespec { sec: -2_i64,
   77   * nsec: 800_000_000_i32 }`.
   78   */
   79  impl Timespec {
   80      pub fn new(seci64, nseci32) -> Timespec {
   81          assert!(nsec >= 0 && nsec < NSEC_PER_SEC);
   82          Timespec { sec: sec, nsec: nsec }
   83      }
   84  }
   85  
   86  /**
   87   * Returns the current time as a `timespec` containing the seconds and
   88   * nanoseconds since 1970-01-01T00:00:00Z.
   89   */
   90  pub fn get_time() -> Timespec {
   91      unsafe {
   92          let (sec, nsec) = os_get_time();
   93          return Timespec::new(sec, nsec);
   94      }
   95  
   96      #[cfg(windows)]
   97      unsafe fn os_get_time() -> (i64, i32) {
   98          static NANOSECONDS_FROM_1601_TO_1970: u64 = 11644473600000000;
   99  
  100          let mut time = libc::FILETIME {
  101              dwLowDateTime: 0,
  102              dwHighDateTime: 0,
  103          };
  104          libc::GetSystemTimeAsFileTime(&mut time);
  105  
  106          // A FILETIME contains a 64-bit value representing the number of
  107          // hectonanosecond (100-nanosecond) intervals since 1601-01-01T00:00:00Z.
  108          // http://support.microsoft.com/kb/167296/en-us
  109          let ns_since_1601 = ((time.dwHighDateTime as u64 << 32) |
  110                               (time.dwLowDateTime  as u64 <<  0)) / 10;
  111          let ns_since_1970 = ns_since_1601 - NANOSECONDS_FROM_1601_TO_1970;
  112  
  113          ((ns_since_1970 / 1000000) as i64,
  114           ((ns_since_1970 % 1000000) * 1000) as i32)
  115      }
  116  
  117      #[cfg(target_os = "macos")]
  118      unsafe fn os_get_time() -> (i64, i32) {
  119          use std::ptr;
  120          let mut tv = libc::timeval { tv_sec: 0, tv_usec: 0 };
  121          imp::gettimeofday(&mut tv, ptr::mut_null());
  122          (tv.tv_sec as i64, tv.tv_usec * 1000)
  123      }
  124  
  125      #[cfg(not(target_os = "macos"), not(windows))]
  126      unsafe fn os_get_time() -> (i64, i32) {
  127          let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
  128          imp::clock_gettime(libc::CLOCK_REALTIME, &mut tv);
  129          (tv.tv_sec as i64, tv.tv_nsec as i32)
  130      }
  131  }
  132  
  133  
  134  /**
  135   * Returns the current value of a high-resolution performance counter
  136   * in nanoseconds since an unspecified epoch.
  137   */
  138  pub fn precise_time_ns() -> u64 {
  139      return os_precise_time_ns();
  140  
  141      #[cfg(windows)]
  142      fn os_precise_time_ns() -> u64 {
  143          let mut ticks_per_s = 0;
  144          assert_eq!(unsafe {
  145              libc::QueryPerformanceFrequency(&mut ticks_per_s)
  146          }, 1);
  147          let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s};
  148          let mut ticks = 0;
  149          assert_eq!(unsafe {
  150              libc::QueryPerformanceCounter(&mut ticks)
  151          }, 1);
  152  
  153          return (ticks as u64 * 1000000000) / (ticks_per_s as u64);
  154      }
  155  
  156      #[cfg(target_os = "macos")]
  157      fn os_precise_time_ns() -> u64 {
  158          let time = unsafe { imp::mach_absolute_time() };
  159          let mut info = libc::mach_timebase_info { numer: 0, denom: 0 };
  160          unsafe { imp::mach_timebase_info(&mut info); }
  161          return time * ((info.numer / info.denom) as u64);
  162      }
  163  
  164      #[cfg(not(windows), not(target_os = "macos"))]
  165      fn os_precise_time_ns() -> u64 {
  166          let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
  167          unsafe {
  168              imp::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts);
  169          }
  170          return (ts.tv_sec as u64) * 1000000000 + (ts.tv_nsec as u64)
  171      }
  172  }
  173  
  174  
  175  /**
  176   * Returns the current value of a high-resolution performance counter
  177   * in seconds since an unspecified epoch.
  178   */
  179  pub fn precise_time_s() -> f64 {
  180      return (precise_time_ns() as f64) / 1000000000.;
  181  }
  182  
  183  pub fn tzset() {
  184      unsafe {
  185          rustrt::rust_tzset();
  186      }
  187  }
  188  
  189  /// Holds a calendar date and time broken down into its components (year, month, day, and so on),
  190  /// also called a broken-down time value.
  191  #[deriving(Clone, Eq, Encodable, Decodable, Show)]
  192  pub struct Tm {
  193      /// Seconds after the minute Ã¢Â€Â“ [0, 60]
  194      pub tm_sec: i32,
  195  
  196      /// Minutes after the hour Ã¢Â€Â“ [0, 59]
  197      pub tm_min: i32,
  198  
  199      /// Hours after midnight Ã¢Â€Â“ [0, 23]
  200      pub tm_hour: i32,
  201  
  202      /// Day of the month Ã¢Â€Â“ [1, 31]
  203      pub tm_mday: i32,
  204  
  205      /// Months since January Ã¢Â€Â“ [0, 11]
  206      pub tm_mon: i32,
  207  
  208      /// Years since 1900
  209      pub tm_year: i32,
  210  
  211      /// Days since Sunday Ã¢Â€Â“ [0, 6]. 0 = Sunday, 1 = Monday, Ã¢Â€Â¦, 6 = Saturday.
  212      pub tm_wday: i32,
  213  
  214      /// Days since January 1 Ã¢Â€Â“ [0, 365]
  215      pub tm_yday: i32,
  216  
  217      /// Daylight Saving Time flag.
  218      ///
  219      /// This value is positive if Daylight Saving Time is in effect, zero if Daylight Saving Time
  220      /// is not in effect, and negative if this information is not available.
  221      pub tm_isdst: i32,
  222  
  223      /// Identifies the time zone that was used to compute this broken-down time value, including any
  224      /// adjustment for Daylight Saving Time. This is the number of seconds east of UTC. For example,
  225      /// for U.S. Pacific Daylight Time, the value is -7*60*60 = -25200.
  226      pub tm_gmtoff: i32,
  227  
  228      /// Abbreviated name for the time zone that was used to compute this broken-down time value.
  229      /// For example, U.S. Pacific Daylight Time is "PDT".
  230      pub tm_zone: ~str,
  231  
  232      /// Nanoseconds after the second Ã¢Â€Â“ [0, 10<sup>9</sup> - 1]
  233      pub tm_nsec: i32,
  234  }
  235  
  236  pub fn empty_tm() -> Tm {
  237      // 64 is the max size of the timezone buffer allocated on windows
  238      // in rust_localtime. In glibc the max timezone size is supposedly 3.
  239      let zone = str::with_capacity(64);
  240      Tm {
  241          tm_sec: 0_i32,
  242          tm_min: 0_i32,
  243          tm_hour: 0_i32,
  244          tm_mday: 0_i32,
  245          tm_mon: 0_i32,
  246          tm_year: 0_i32,
  247          tm_wday: 0_i32,
  248          tm_yday: 0_i32,
  249          tm_isdst: 0_i32,
  250          tm_gmtoff: 0_i32,
  251          tm_zone: zone,
  252          tm_nsec: 0_i32,
  253      }
  254  }
  255  
  256  /// Returns the specified time in UTC
  257  pub fn at_utc(clockTimespec) -> Tm {
  258      unsafe {
  259          let Timespec { sec, nsec } = clock;
  260          let mut tm = empty_tm();
  261          rustrt::rust_gmtime(sec, nsec, &mut tm);
  262          tm
  263      }
  264  }
  265  
  266  /// Returns the current time in UTC
  267  pub fn now_utc() -> Tm {
  268      at_utc(get_time())
  269  }
  270  
  271  /// Returns the specified time in the local timezone
  272  pub fn at(clockTimespec) -> Tm {
  273      unsafe {
  274          let Timespec { sec, nsec } = clock;
  275          let mut tm = empty_tm();
  276          rustrt::rust_localtime(sec, nsec, &mut tm);
  277          tm
  278      }
  279  }
  280  
  281  /// Returns the current time in the local timezone
  282  pub fn now() -> Tm {
  283      at(get_time())
  284  }
  285  
  286  
  287  impl Tm {
  288      /// Convert time to the seconds from January 1, 1970
  289      pub fn to_timespec(&self) -> Timespec {
  290          unsafe {
  291              let sec = match self.tm_gmtoff {
  292                  0_i32 => rustrt::rust_timegm(self),
  293                  _     => rustrt::rust_mktime(self)
  294              };
  295  
  296              Timespec::new(sec, self.tm_nsec)
  297          }
  298      }
  299  
  300      /// Convert time to the local timezone
  301      pub fn to_local(&self) -> Tm {
  302          at(self.to_timespec())
  303      }
  304  
  305      /// Convert time to the UTC
  306      pub fn to_utc(&self) -> Tm {
  307          at_utc(self.to_timespec())
  308      }
  309  
  310      /**
  311       * Return a string of the current time in the form
  312       * "Thu Jan  1 00:00:00 1970".
  313       */
  314      pub fn ctime(&self) -> ~str { self.strftime("%c") }
  315  
  316      /// Formats the time according to the format string.
  317      pub fn strftime(&self, format&str) -> ~str {
  318          strftime(format, self)
  319      }
  320  
  321      /**
  322       * Returns a time string formatted according to RFC 822.
  323       *
  324       * local: "Thu, 22 Mar 2012 07:53:18 PST"
  325       * utc:   "Thu, 22 Mar 2012 14:53:18 UTC"
  326       */
  327      pub fn rfc822(&self) -> ~str {
  328          if self.tm_gmtoff == 0_i32 {
  329              self.strftime("%a, %d %b %Y %T GMT")
  330          } else {
  331              self.strftime("%a, %d %b %Y %T %Z")
  332          }
  333      }
  334  
  335      /**
  336       * Returns a time string formatted according to RFC 822 with Zulu time.
  337       *
  338       * local: "Thu, 22 Mar 2012 07:53:18 -0700"
  339       * utc:   "Thu, 22 Mar 2012 14:53:18 -0000"
  340       */
  341      pub fn rfc822z(&self) -> ~str {
  342          self.strftime("%a, %d %b %Y %T %z")
  343      }
  344  
  345      /**
  346       * Returns a time string formatted according to ISO 8601.
  347       *
  348       * local: "2012-02-22T07:53:18-07:00"
  349       * utc:   "2012-02-22T14:53:18Z"
  350       */
  351      pub fn rfc3339(&self) -> ~str {
  352          if self.tm_gmtoff == 0_i32 {
  353              self.strftime("%Y-%m-%dT%H:%M:%SZ")
  354          } else {
  355              let s = self.strftime("%Y-%m-%dT%H:%M:%S");
  356              let sign = if self.tm_gmtoff > 0_i32 { '+' } else { '-' };
  357              let mut m = num::abs(self.tm_gmtoff) / 60_i32;
  358              let h = m / 60_i32;
  359              m -= h * 60_i32;
  360              s + format!("{}{:02d}:{:02d}", sign, h as int, m as int)
  361          }
  362      }
  363  }
  364  
  365  /// Parses the time from the string according to the format string.
  366  pub fn strptime(s&str, format&str) -> Result<Tm, ~str> {
  367      fn match_str(s&str, posuint, needle&str) -> bool {
  368          let mut i = pos;
  369          for ch in needle.bytes() {
  370              if s[i] != ch {
  371                  return false;
  372              }
  373              i += 1u;
  374          }
  375          return true;
  376      }
  377  
  378      fn match_strs(ss&str, posuint, strs&[(~str, i32)])
  379        -> Option<(i32, uint)> {
  380          let mut i = 0u;
  381          let len = strs.len();
  382          while i < len {
  383              match strs[i] { // can't use let due to let-pattern bugs
  384                  (ref needle, value) => {
  385                      if match_str(ss, pos, *needle) {
  386                          return Some((value, pos + needle.len()));
  387                      }
  388                  }
  389              }
  390              i += 1u;
  391          }
  392  
  393          None
  394      }
  395  
  396      fn match_digits(ss&str, posuint, digitsuint, wsbool)
  397        -> Option<(i32, uint)> {
  398          let mut pos = pos;
  399          let len = ss.len();
  400          let mut value = 0_i32;
  401  
  402          let mut i = 0u;
  403          while i < digits {
  404              if pos >= len {
  405                  return None;
  406              }
  407              let range = ss.char_range_at(pos);
  408              pos = range.next;
  409  
  410              match range.ch {
  411                '0' .. '9' => {
  412                  value = value * 10_i32 + (range.ch as i32 - '0' as i32);
  413                }
  414                ' ' if ws => (),
  415                _ => return None
  416              }
  417              i += 1u;
  418          }
  419  
  420          Some((value, pos))
  421      }
  422  
  423      fn match_fractional_seconds(ss&str, posuint) -> (i32, uint) {
  424          let len = ss.len();
  425          let mut value = 0_i32;
  426          let mut multiplier = NSEC_PER_SEC / 10;
  427          let mut pos = pos;
  428  
  429          loop {
  430              if pos >= len {
  431                  break;
  432              }
  433              let range = ss.char_range_at(pos);
  434  
  435              match range.ch {
  436                  '0' .. '9' => {
  437                      pos = range.next;
  438                      // This will drop digits after the nanoseconds place
  439                      let digit = range.ch as i32 - '0' as i32;
  440                      value += digit * multiplier;
  441                      multiplier /= 10;
  442                  }
  443                  _ => break
  444              }
  445          }
  446  
  447          (value, pos)
  448      }
  449  
  450      fn match_digits_in_range(ss&str, posuint, digitsuint, wsbool,
  451                               mini32, maxi32) -> Option<(i32, uint)> {
  452          match match_digits(ss, pos, digits, ws) {
  453            Some((val, pos)) if val >= min && val <= max => {
  454              Some((val, pos))
  455            }
  456            _ => None
  457          }
  458      }
  459  
  460      fn parse_char(s&str, posuint, cchar) -> Result<uint, ~str> {
  461          let range = s.char_range_at(pos);
  462  
  463          if c == range.ch {
  464              Ok(range.next)
  465          } else {
  466              Err(format!("Expected {}, found {}",
  467                  str::from_char(c),
  468                  str::from_char(range.ch)))
  469          }
  470      }
  471  
  472      fn parse_type(s&str, posuint, chchar, tm&mut Tm)
  473        -> Result<uint, ~str> {
  474          match ch {
  475            'A' => match match_strs(s, pos, [
  476                (~"Sunday", 0_i32),
  477                (~"Monday", 1_i32),
  478                (~"Tuesday", 2_i32),
  479                (~"Wednesday", 3_i32),
  480                (~"Thursday", 4_i32),
  481                (~"Friday", 5_i32),
  482                (~"Saturday", 6_i32)
  483            ]) {
  484              Some(item) => { let (v, pos) = item; tm.tm_wday = v; Ok(pos) }
  485              None => Err(~"Invalid day")
  486            },
  487            'a' => match match_strs(s, pos, [
  488                (~"Sun", 0_i32),
  489                (~"Mon", 1_i32),
  490                (~"Tue", 2_i32),
  491                (~"Wed", 3_i32),
  492                (~"Thu", 4_i32),
  493                (~"Fri", 5_i32),
  494                (~"Sat", 6_i32)
  495            ]) {
  496              Some(item) => { let (v, pos) = item; tm.tm_wday = v; Ok(pos) }
  497              None => Err(~"Invalid day")
  498            },
  499            'B' => match match_strs(s, pos, [
  500                (~"January", 0_i32),
  501                (~"February", 1_i32),
  502                (~"March", 2_i32),
  503                (~"April", 3_i32),
  504                (~"May", 4_i32),
  505                (~"June", 5_i32),
  506                (~"July", 6_i32),
  507                (~"August", 7_i32),
  508                (~"September", 8_i32),
  509                (~"October", 9_i32),
  510                (~"November", 10_i32),
  511                (~"December", 11_i32)
  512            ]) {
  513              Some(item) => { let (v, pos) = item; tm.tm_mon = v; Ok(pos) }
  514              None => Err(~"Invalid month")
  515            },
  516            'b' | 'h' => match match_strs(s, pos, [
  517                (~"Jan", 0_i32),
  518                (~"Feb", 1_i32),
  519                (~"Mar", 2_i32),
  520                (~"Apr", 3_i32),
  521                (~"May", 4_i32),
  522                (~"Jun", 5_i32),
  523                (~"Jul", 6_i32),
  524                (~"Aug", 7_i32),
  525                (~"Sep", 8_i32),
  526                (~"Oct", 9_i32),
  527                (~"Nov", 10_i32),
  528                (~"Dec", 11_i32)
  529            ]) {
  530              Some(item) => { let (v, pos) = item; tm.tm_mon = v; Ok(pos) }
  531              None => Err(~"Invalid month")
  532            },
  533            'C' => match match_digits_in_range(s, pos, 2u, false, 0_i32,
  534                                               99_i32) {
  535              Some(item) => {
  536                  let (v, pos) = item;
  537                    tm.tm_year += (v * 100_i32) - 1900_i32;
  538                    Ok(pos)
  539                }
  540              None => Err(~"Invalid year")
  541            },
  542            'c' => {
  543              parse_type(s, pos, 'a', &mut *tm)
  544                  .and_then(|pos| parse_char(s, pos, ' '))
  545                  .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
  546                  .and_then(|pos| parse_char(s, pos, ' '))
  547                  .and_then(|pos| parse_type(s, pos, 'e', &mut *tm))
  548                  .and_then(|pos| parse_char(s, pos, ' '))
  549                  .and_then(|pos| parse_type(s, pos, 'T', &mut *tm))
  550                  .and_then(|pos| parse_char(s, pos, ' '))
  551                  .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
  552            }
  553            'D' | 'x' => {
  554              parse_type(s, pos, 'm', &mut *tm)
  555                  .and_then(|pos| parse_char(s, pos, '/'))
  556                  .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
  557                  .and_then(|pos| parse_char(s, pos, '/'))
  558                  .and_then(|pos| parse_type(s, pos, 'y', &mut *tm))
  559            }
  560            'd' => match match_digits_in_range(s, pos, 2u, false, 1_i32,
  561                                               31_i32) {
  562              Some(item) => { let (v, pos) = item; tm.tm_mday = v; Ok(pos) }
  563              None => Err(~"Invalid day of the month")
  564            },
  565            'e' => match match_digits_in_range(s, pos, 2u, true, 1_i32,
  566                                               31_i32) {
  567              Some(item) => { let (v, pos) = item; tm.tm_mday = v; Ok(pos) }
  568              None => Err(~"Invalid day of the month")
  569            },
  570            'f' => {
  571              let (val, pos) = match_fractional_seconds(s, pos);
  572              tm.tm_nsec = val;
  573              Ok(pos)
  574            }
  575            'F' => {
  576              parse_type(s, pos, 'Y', &mut *tm)
  577                  .and_then(|pos| parse_char(s, pos, '-'))
  578                  .and_then(|pos| parse_type(s, pos, 'm', &mut *tm))
  579                  .and_then(|pos| parse_char(s, pos, '-'))
  580                  .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
  581            }
  582            'H' => {
  583              match match_digits_in_range(s, pos, 2u, false, 0_i32, 23_i32) {
  584                Some(item) => { let (v, pos) = item; tm.tm_hour = v; Ok(pos) }
  585                None => Err(~"Invalid hour")
  586              }
  587            }
  588            'I' => {
  589              match match_digits_in_range(s, pos, 2u, false, 1_i32, 12_i32) {
  590                Some(item) => {
  591                    let (v, pos) = item;
  592                    tm.tm_hour = if v == 12_i32 { 0_i32 } else { v };
  593                    Ok(pos)
  594                }
  595                None => Err(~"Invalid hour")
  596              }
  597            }
  598            'j' => {
  599              match match_digits_in_range(s, pos, 3u, false, 1_i32, 366_i32) {
  600                Some(item) => {
  601                  let (v, pos) = item;
  602                  tm.tm_yday = v - 1_i32;
  603                  Ok(pos)
  604                }
  605                None => Err(~"Invalid day of year")
  606              }
  607            }
  608            'k' => {
  609              match match_digits_in_range(s, pos, 2u, true, 0_i32, 23_i32) {
  610                Some(item) => { let (v, pos) = item; tm.tm_hour = v; Ok(pos) }
  611                None => Err(~"Invalid hour")
  612              }
  613            }
  614            'l' => {
  615              match match_digits_in_range(s, pos, 2u, true, 1_i32, 12_i32) {
  616                Some(item) => {
  617                    let (v, pos) = item;
  618                    tm.tm_hour = if v == 12_i32 { 0_i32 } else { v };
  619                    Ok(pos)
  620                }
  621                None => Err(~"Invalid hour")
  622              }
  623            }
  624            'M' => {
  625              match match_digits_in_range(s, pos, 2u, false, 0_i32, 59_i32) {
  626                Some(item) => { let (v, pos) = item; tm.tm_min = v; Ok(pos) }
  627                None => Err(~"Invalid minute")
  628              }
  629            }
  630            'm' => {
  631              match match_digits_in_range(s, pos, 2u, false, 1_i32, 12_i32) {
  632                Some(item) => {
  633                  let (v, pos) = item;
  634                  tm.tm_mon = v - 1_i32;
  635                  Ok(pos)
  636                }
  637                None => Err(~"Invalid month")
  638              }
  639            }
  640            'n' => parse_char(s, pos, '\n'),
  641            'P' => match match_strs(s, pos,
  642                                    [(~"am", 0_i32), (~"pm", 12_i32)]) {
  643  
  644              Some(item) => { let (v, pos) = item; tm.tm_hour += v; Ok(pos) }
  645              None => Err(~"Invalid hour")
  646            },
  647            'p' => match match_strs(s, pos,
  648                                    [(~"AM", 0_i32), (~"PM", 12_i32)]) {
  649  
  650              Some(item) => { let (v, pos) = item; tm.tm_hour += v; Ok(pos) }
  651              None => Err(~"Invalid hour")
  652            },
  653            'R' => {
  654              parse_type(s, pos, 'H', &mut *tm)
  655                  .and_then(|pos| parse_char(s, pos, ':'))
  656                  .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
  657            }
  658            'r' => {
  659              parse_type(s, pos, 'I', &mut *tm)
  660                  .and_then(|pos| parse_char(s, pos, ':'))
  661                  .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
  662                  .and_then(|pos| parse_char(s, pos, ':'))
  663                  .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
  664                  .and_then(|pos| parse_char(s, pos, ' '))
  665                  .and_then(|pos| parse_type(s, pos, 'p', &mut *tm))
  666            }
  667            'S' => {
  668              match match_digits_in_range(s, pos, 2u, false, 0_i32, 60_i32) {
  669                Some(item) => {
  670                  let (v, pos) = item;
  671                  tm.tm_sec = v;
  672                  Ok(pos)
  673                }
  674                None => Err(~"Invalid second")
  675              }
  676            }
  677            //'s' {}
  678            'T' | 'X' => {
  679              parse_type(s, pos, 'H', &mut *tm)
  680                  .and_then(|pos| parse_char(s, pos, ':'))
  681                  .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
  682                  .and_then(|pos| parse_char(s, pos, ':'))
  683                  .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
  684            }
  685            't' => parse_char(s, pos, '\t'),
  686            'u' => {
  687              match match_digits_in_range(s, pos, 1u, false, 1_i32, 7_i32) {
  688                Some(item) => {
  689                  let (v, pos) = item;
  690                  tm.tm_wday = if v == 7 { 0 } else { v };
  691                  Ok(pos)
  692                }
  693                None => Err(~"Invalid day of week")
  694              }
  695            }
  696            'v' => {
  697              parse_type(s, pos, 'e', &mut *tm)
  698                  .and_then(|pos|  parse_char(s, pos, '-'))
  699                  .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
  700                  .and_then(|pos| parse_char(s, pos, '-'))
  701                  .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
  702            }
  703            //'W' {}
  704            'w' => {
  705              match match_digits_in_range(s, pos, 1u, false, 0_i32, 6_i32) {
  706                Some(item) => { let (v, pos) = item; tm.tm_wday = v; Ok(pos) }
  707                None => Err(~"Invalid day of week")
  708              }
  709            }
  710            'Y' => {
  711              match match_digits(s, pos, 4u, false) {
  712                Some(item) => {
  713                  let (v, pos) = item;
  714                  tm.tm_year = v - 1900_i32;
  715                  Ok(pos)
  716                }
  717                None => Err(~"Invalid year")
  718              }
  719            }
  720            'y' => {
  721              match match_digits_in_range(s, pos, 2u, false, 0_i32, 99_i32) {
  722                Some(item) => {
  723                  let (v, pos) = item;
  724                  tm.tm_year = v;
  725                  Ok(pos)
  726                }
  727                None => Err(~"Invalid year")
  728              }
  729            }
  730            'Z' => {
  731              if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") {
  732                  tm.tm_gmtoff = 0_i32;
  733                  tm.tm_zone = ~"UTC";
  734                  Ok(pos + 3u)
  735              } else {
  736                  // It's odd, but to maintain compatibility with c's
  737                  // strptime we ignore the timezone.
  738                  let mut pos = pos;
  739                  let len = s.len();
  740                  while pos < len {
  741                      let range = s.char_range_at(pos);
  742                      pos = range.next;
  743                      if range.ch == ' ' { break; }
  744                  }
  745  
  746                  Ok(pos)
  747              }
  748            }
  749            'z' => {
  750              let range = s.char_range_at(pos);
  751  
  752              if range.ch == '+' || range.ch == '-' {
  753                  match match_digits(s, range.next, 4u, false) {
  754                    Some(item) => {
  755                      let (v, pos) = item;
  756                      if v == 0_i32 {
  757                          tm.tm_gmtoff = 0_i32;
  758                          tm.tm_zone = ~"UTC";
  759                      }
  760  
  761                      Ok(pos)
  762                    }
  763                    None => Err(~"Invalid zone offset")
  764                  }
  765              } else {
  766                  Err(~"Invalid zone offset")
  767              }
  768            }
  769            '%' => parse_char(s, pos, '%'),
  770            ch => {
  771              Err(format!("unknown formatting type{}", str::from_char(ch)))
  772            }
  773          }
  774      }
  775  
  776      let mut rdr = BufReader::new(format.as_bytes());
  777      let mut tm = Tm {
  778          tm_sec: 0_i32,
  779          tm_min: 0_i32,
  780          tm_hour: 0_i32,
  781          tm_mday: 0_i32,
  782          tm_mon: 0_i32,
  783          tm_year: 0_i32,
  784          tm_wday: 0_i32,
  785          tm_yday: 0_i32,
  786          tm_isdst: 0_i32,
  787          tm_gmtoff: 0_i32,
  788          tm_zone: ~"",
  789          tm_nsec: 0_i32,
  790      };
  791      let mut pos = 0u;
  792      let len = s.len();
  793      let mut result = Err(~"Invalid time");
  794  
  795      while pos < len {
  796          let range = s.char_range_at(pos);
  797          let ch = range.ch;
  798          let next = range.next;
  799  
  800          let mut buf = [0];
  801          let c = match rdr.read(buf) {
  802              Ok(..) => buf[0] as char,
  803              Err(..) => break
  804          };
  805          match c {
  806              '%' => {
  807                  let ch = match rdr.read(buf) {
  808                      Ok(..) => buf[0] as char,
  809                      Err(..) => break
  810                  };
  811                  match parse_type(s, pos, ch, &mut tm) {
  812                      Ok(next) => pos = next,
  813                      Err(e) => { result = Err(e); break; }
  814                  }
  815              },
  816              c => {
  817                  if c != ch { break }
  818                  pos = next;
  819              }
  820          }
  821      }
  822  
  823      if pos == len && rdr.tell().unwrap() == format.len() as u64 {
  824          Ok(Tm {
  825              tm_sec: tm.tm_sec,
  826              tm_min: tm.tm_min,
  827              tm_hour: tm.tm_hour,
  828              tm_mday: tm.tm_mday,
  829              tm_mon: tm.tm_mon,
  830              tm_year: tm.tm_year,
  831              tm_wday: tm.tm_wday,
  832              tm_yday: tm.tm_yday,
  833              tm_isdst: tm.tm_isdst,
  834              tm_gmtoff: tm.tm_gmtoff,
  835              tm_zone: tm.tm_zone.clone(),
  836              tm_nsec: tm.tm_nsec,
  837          })
  838      } else { result }
  839  }
  840  
  841  /// Formats the time according to the format string.
  842  pub fn strftime(format&str, tm&Tm) -> ~str {
  843      fn days_in_year(yearint) -> i32 {
  844          if (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) {
  845              366    /* Days in a leap year */
  846          } else {
  847              365    /* Days in a non-leap year */
  848          }
  849      }
  850  
  851      fn iso_week_days(ydayi32, wdayi32) -> int {
  852          /* The number of days from the first day of the first ISO week of this
  853          * year to the year day YDAY with week day WDAY.
  854          * ISO weeks start on Monday. The first ISO week has the year's first
  855          * Thursday.
  856          * YDAY may be as small as yday_minimum.
  857          */
  858          let ydayint = yday as int;
  859          let wdayint = wday as int;
  860          let iso_week_start_wdayint = 1;                     /* Monday */
  861          let iso_week1_wdayint = 4;                          /* Thursday */
  862          let yday_minimumint = 366;
  863          /* Add enough to the first operand of % to make it nonnegative. */
  864          let big_enough_multiple_of_7int = (yday_minimum / 7 + 2) * 7;
  865  
  866          yday - (yday - wday + iso_week1_wday + big_enough_multiple_of_7) % 7
  867              + iso_week1_wday - iso_week_start_wday
  868      }
  869  
  870      fn iso_week(ch:char, tm&Tm) -> ~str {
  871          let mut yearint = tm.tm_year as int + 1900;
  872          let mut daysint = iso_week_days (tm.tm_yday, tm.tm_wday);
  873  
  874          if days < 0 {
  875              /* This ISO week belongs to the previous year. */
  876              year -= 1;
  877              days = iso_week_days (tm.tm_yday + (days_in_year(year)), tm.tm_wday);
  878          } else {
  879              let dint = iso_week_days (tm.tm_yday - (days_in_year(year)),
  880                                          tm.tm_wday);
  881              if 0 <= d {
  882                  /* This ISO week belongs to the next year. */
  883                  year += 1;
  884                  days = d;
  885              }
  886          }
  887  
  888          match ch {
  889              'G' => format!("{}", year),
  890              'g' => format!("{:02d}", (year % 100 + 100) % 100),
  891              'V' => format!("{:02d}", days / 7 + 1),
  892              _ => ~""
  893          }
  894      }
  895  
  896      fn parse_type(chchar, tm&Tm) -> ~str {
  897        let die = || format!("strftime: can't understand this format {} ", ch);
  898          match ch {
  899            'A' => match tm.tm_wday as int {
  900              0 => ~"Sunday",
  901              1 => ~"Monday",
  902              2 => ~"Tuesday",
  903              3 => ~"Wednesday",
  904              4 => ~"Thursday",
  905              5 => ~"Friday",
  906              6 => ~"Saturday",
  907              _ => die()
  908            },
  909           'a' => match tm.tm_wday as int {
  910              0 => ~"Sun",
  911              1 => ~"Mon",
  912              2 => ~"Tue",
  913              3 => ~"Wed",
  914              4 => ~"Thu",
  915              5 => ~"Fri",
  916              6 => ~"Sat",
  917              _ => die()
  918            },
  919            'B' => match tm.tm_mon as int {
  920              0 => ~"January",
  921              1 => ~"February",
  922              2 => ~"March",
  923              3 => ~"April",
  924              4 => ~"May",
  925              5 => ~"June",
  926              6 => ~"July",
  927              7 => ~"August",
  928              8 => ~"September",
  929              9 => ~"October",
  930              10 => ~"November",
  931              11 => ~"December",
  932              _ => die()
  933            },
  934            'b' | 'h' => match tm.tm_mon as int {
  935              0 => ~"Jan",
  936              1 => ~"Feb",
  937              2 => ~"Mar",
  938              3 => ~"Apr",
  939              4 => ~"May",
  940              5 => ~"Jun",
  941              6 => ~"Jul",
  942              7 => ~"Aug",
  943              8 => ~"Sep",
  944              9 => ~"Oct",
  945              10 => ~"Nov",
  946              11 => ~"Dec",
  947              _  => die()
  948            },
  949            'C' => format!("{:02d}", (tm.tm_year as int + 1900) / 100),
  950            'c' => {
  951              format!("{} {} {} {} {}",
  952                  parse_type('a', tm),
  953                  parse_type('b', tm),
  954                  parse_type('e', tm),
  955                  parse_type('T', tm),
  956                  parse_type('Y', tm))
  957            }
  958            'D' | 'x' => {
  959              format!("{}/{}/{}",
  960                  parse_type('m', tm),
  961                  parse_type('d', tm),
  962                  parse_type('y', tm))
  963            }
  964            'd' => format!("{:02d}", tm.tm_mday),
  965            'e' => format!("{:2d}", tm.tm_mday),
  966            'f' => format!("{:09d}", tm.tm_nsec),
  967            'F' => {
  968              format!("{}-{}-{}",
  969                  parse_type('Y', tm),
  970                  parse_type('m', tm),
  971                  parse_type('d', tm))
  972            }
  973            'G' => iso_week('G', tm),
  974            'g' => iso_week('g', tm),
  975            'H' => format!("{:02d}", tm.tm_hour),
  976            'I' => {
  977              let mut h = tm.tm_hour;
  978              if h == 0 { h = 12 }
  979              if h > 12 { h -= 12 }
  980              format!("{:02d}", h)
  981            }
  982            'j' => format!("{:03d}", tm.tm_yday + 1),
  983            'k' => format!("{:2d}", tm.tm_hour),
  984            'l' => {
  985              let mut h = tm.tm_hour;
  986              if h == 0 { h = 12 }
  987              if h > 12 { h -= 12 }
  988              format!("{:2d}", h)
  989            }
  990            'M' => format!("{:02d}", tm.tm_min),
  991            'm' => format!("{:02d}", tm.tm_mon + 1),
  992            'n' => ~"\n",
  993            'P' => if (tm.tm_hour as int) < 12 { ~"am" } else { ~"pm" },
  994            'p' => if (tm.tm_hour as int) < 12 { ~"AM" } else { ~"PM" },
  995            'R' => {
  996              format!("{}:{}",
  997                  parse_type('H', tm),
  998                  parse_type('M', tm))
  999            }
 1000            'r' => {
 1001              format!("{}:{}:{} {}",
 1002                  parse_type('I', tm),
 1003                  parse_type('M', tm),
 1004                  parse_type('S', tm),
 1005                  parse_type('p', tm))
 1006            }
 1007            'S' => format!("{:02d}", tm.tm_sec),
 1008            's' => format!("{}", tm.to_timespec().sec),
 1009            'T' | 'X' => {
 1010              format!("{}:{}:{}",
 1011                  parse_type('H', tm),
 1012                  parse_type('M', tm),
 1013                  parse_type('S', tm))
 1014            }
 1015            't' => ~"\t",
 1016            'U' => format!("{:02d}", (tm.tm_yday - tm.tm_wday + 7) / 7),
 1017            'u' => {
 1018              let i = tm.tm_wday as int;
 1019              (if i == 0 { 7 } else { i }).to_str()
 1020            }
 1021            'V' => iso_week('V', tm),
 1022            'v' => {
 1023              format!("{}-{}-{}",
 1024                  parse_type('e', tm),
 1025                  parse_type('b', tm),
 1026                  parse_type('Y', tm))
 1027            }
 1028            'W' => format!("{:02d}", (tm.tm_yday - (tm.tm_wday - 1 + 7) % 7 + 7)
 1029                           / 7),
 1030            'w' => (tm.tm_wday as int).to_str(),
 1031            'Y' => (tm.tm_year as int + 1900).to_str(),
 1032            'y' => format!("{:02d}", (tm.tm_year as int + 1900) % 100),
 1033            'Z' => tm.tm_zone.clone(),
 1034            'z' => {
 1035              let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' };
 1036              let mut m = num::abs(tm.tm_gmtoff) / 60_i32;
 1037              let h = m / 60_i32;
 1038              m -= h * 60_i32;
 1039              format!("{}{:02d}{:02d}", sign, h, m)
 1040            }
 1041            '+' => tm.rfc3339(),
 1042            '%' => ~"%",
 1043            _   => die()
 1044          }
 1045      }
 1046  
 1047      let mut buf = Vec::new();
 1048  
 1049      let mut rdr = BufReader::new(format.as_bytes());
 1050      loop {
 1051          let mut b = [0];
 1052          let ch = match rdr.read(b) {
 1053              Ok(..) => b[0],
 1054              Err(..) => break,
 1055          };
 1056          match ch as char {
 1057              '%' => {
 1058                  rdr.read(b).unwrap();
 1059                  let s = parse_type(b[0] as char, tm);
 1060                  buf.push_all(s.as_bytes());
 1061              }
 1062              ch => buf.push(ch as u8)
 1063          }
 1064      }
 1065  
 1066      str::from_utf8(buf.as_slice()).unwrap().to_str()
 1067  }
 1068  
 1069  #[cfg(test)]
 1070  mod tests {
 1071      use super::{Timespec, get_time, precise_time_ns, precise_time_s, tzset,
 1072                  at_utc, at, strptime};
 1073  
 1074      use std::f64;
 1075      use std::result::{Err, Ok};
 1076  
 1077      #[cfg(windows)]
 1078      fn set_time_zone() {
 1079          use libc;
 1080          // Windows crt doesn't see any environment variable set by
 1081          // `SetEnvironmentVariable`, which `os::setenv` internally uses.
 1082          // It is why we use `putenv` here.
 1083          extern {
 1084              fn _putenv(envstring: *libc::c_char) -> libc::c_int;
 1085          }
 1086  
 1087          unsafe {
 1088              // Windows does not understand "America/Los_Angeles".
 1089              // PST+08 may look wrong, but not! "PST" indicates
 1090              // the name of timezone. "+08" means UTC = local + 08.
 1091              "TZ=PST+08".with_c_str(|env| {
 1092                  _putenv(env);
 1093              })
 1094          }
 1095          tzset();
 1096      }
 1097      #[cfg(not(windows))]
 1098      fn set_time_zone() {
 1099          use std::os;
 1100          os::setenv("TZ", "America/Los_Angeles");
 1101          tzset();
 1102      }
 1103  
 1104      fn test_get_time() {
 1105          static SOME_RECENT_DATE: i64 = 1325376000i64; // 2012-01-01T00:00:00Z
 1106          static SOME_FUTURE_DATE: i64 = 1577836800i64; // 2020-01-01T00:00:00Z
 1107  
 1108          let tv1 = get_time();
 1109          debug!("tv1={:?} sec + {:?} nsec", tv1.sec as uint, tv1.nsec as uint);
 1110  
 1111          assert!(tv1.sec > SOME_RECENT_DATE);
 1112          assert!(tv1.nsec < 1000000000i32);
 1113  
 1114          let tv2 = get_time();
 1115          debug!("tv2={:?} sec + {:?} nsec", tv2.sec as uint, tv2.nsec as uint);
 1116  
 1117          assert!(tv2.sec >= tv1.sec);
 1118          assert!(tv2.sec < SOME_FUTURE_DATE);
 1119          assert!(tv2.nsec < 1000000000i32);
 1120          if tv2.sec == tv1.sec {
 1121              assert!(tv2.nsec >= tv1.nsec);
 1122          }
 1123      }
 1124  
 1125      fn test_precise_time() {
 1126          let s0 = precise_time_s();
 1127          debug!("s0={} sec", f64::to_str_digits(s0, 9u));
 1128          assert!(s0 > 0.);
 1129  
 1130          let ns0 = precise_time_ns();
 1131          let ns1 = precise_time_ns();
 1132          debug!("ns0={:?} ns", ns0);
 1133          debug!("ns1={:?} ns", ns1);
 1134          assert!(ns1 >= ns0);
 1135  
 1136          let ns2 = precise_time_ns();
 1137          debug!("ns2={:?} ns", ns2);
 1138          assert!(ns2 >= ns1);
 1139      }
 1140  
 1141      fn test_at_utc() {
 1142          set_time_zone();
 1143  
 1144          let time = Timespec::new(1234567890, 54321);
 1145          let utc = at_utc(time);
 1146  
 1147          assert_eq!(utc.tm_sec, 30_i32);
 1148          assert_eq!(utc.tm_min, 31_i32);
 1149          assert_eq!(utc.tm_hour, 23_i32);
 1150          assert_eq!(utc.tm_mday, 13_i32);
 1151          assert_eq!(utc.tm_mon, 1_i32);
 1152          assert_eq!(utc.tm_year, 109_i32);
 1153          assert_eq!(utc.tm_wday, 5_i32);
 1154          assert_eq!(utc.tm_yday, 43_i32);
 1155          assert_eq!(utc.tm_isdst, 0_i32);
 1156          assert_eq!(utc.tm_gmtoff, 0_i32);
 1157          assert_eq!(utc.tm_zone, ~"UTC");
 1158          assert_eq!(utc.tm_nsec, 54321_i32);
 1159      }
 1160  
 1161      fn test_at() {
 1162          set_time_zone();
 1163  
 1164          let time = Timespec::new(1234567890, 54321);
 1165          let local = at(time);
 1166  
 1167          debug!("time_at: {:?}", local);
 1168  
 1169          assert_eq!(local.tm_sec, 30_i32);
 1170          assert_eq!(local.tm_min, 31_i32);
 1171          assert_eq!(local.tm_hour, 15_i32);
 1172          assert_eq!(local.tm_mday, 13_i32);
 1173          assert_eq!(local.tm_mon, 1_i32);
 1174          assert_eq!(local.tm_year, 109_i32);
 1175          assert_eq!(local.tm_wday, 5_i32);
 1176          assert_eq!(local.tm_yday, 43_i32);
 1177          assert_eq!(local.tm_isdst, 0_i32);
 1178          assert_eq!(local.tm_gmtoff, -28800_i32);
 1179  
 1180          // FIXME (#2350): We should probably standardize on the timezone
 1181          // abbreviation.
 1182          let zone = &local.tm_zone;
 1183          assert!(*zone == ~"PST" || *zone == ~"Pacific Standard Time");
 1184  
 1185          assert_eq!(local.tm_nsec, 54321_i32);
 1186      }
 1187  
 1188      fn test_to_timespec() {
 1189          set_time_zone();
 1190  
 1191          let time = Timespec::new(1234567890, 54321);
 1192          let utc = at_utc(time);
 1193  
 1194          assert_eq!(utc.to_timespec(), time);
 1195          assert_eq!(utc.to_local().to_timespec(), time);
 1196      }
 1197  
 1198      fn test_conversions() {
 1199          set_time_zone();
 1200  
 1201          let time = Timespec::new(1234567890, 54321);
 1202          let utc = at_utc(time);
 1203          let local = at(time);
 1204  
 1205          assert!(local.to_local() == local);
 1206          assert!(local.to_utc() == utc);
 1207          assert!(local.to_utc().to_local() == local);
 1208          assert!(utc.to_utc() == utc);
 1209          assert!(utc.to_local() == local);
 1210          assert!(utc.to_local().to_utc() == utc);
 1211      }
 1212  
 1213      fn test_strptime() {
 1214          set_time_zone();
 1215  
 1216          match strptime("", "") {
 1217            Ok(ref tm) => {
 1218              assert!(tm.tm_sec == 0_i32);
 1219              assert!(tm.tm_min == 0_i32);
 1220              assert!(tm.tm_hour == 0_i32);
 1221              assert!(tm.tm_mday == 0_i32);
 1222              assert!(tm.tm_mon == 0_i32);
 1223              assert!(tm.tm_year == 0_i32);
 1224              assert!(tm.tm_wday == 0_i32);
 1225              assert!(tm.tm_isdst == 0_i32);
 1226              assert!(tm.tm_gmtoff == 0_i32);
 1227              assert!(tm.tm_zone == ~"");
 1228              assert!(tm.tm_nsec == 0_i32);
 1229            }
 1230            Err(_) => ()
 1231          }
 1232  
 1233          let format = "%a %b %e %T.%f %Y";
 1234          assert_eq!(strptime("", format), Err(~"Invalid time"));
 1235          assert!(strptime("Fri Feb 13 15:31:30", format)
 1236              == Err(~"Invalid time"));
 1237  
 1238          match strptime("Fri Feb 13 15:31:30.01234 2009", format) {
 1239            Err(e) => fail!(e),
 1240            Ok(ref tm) => {
 1241              assert!(tm.tm_sec == 30_i32);
 1242              assert!(tm.tm_min == 31_i32);
 1243              assert!(tm.tm_hour == 15_i32);
 1244              assert!(tm.tm_mday == 13_i32);
 1245              assert!(tm.tm_mon == 1_i32);
 1246              assert!(tm.tm_year == 109_i32);
 1247              assert!(tm.tm_wday == 5_i32);
 1248              assert!(tm.tm_yday == 0_i32);
 1249              assert!(tm.tm_isdst == 0_i32);
 1250              assert!(tm.tm_gmtoff == 0_i32);
 1251              assert!(tm.tm_zone == ~"");
 1252              assert!(tm.tm_nsec == 12340000_i32);
 1253            }
 1254          }
 1255  
 1256          fn test(s: &str, format: &str) -> bool {
 1257              match strptime(s, format) {
 1258                Ok(ref tm) => tm.strftime(format) == s.to_owned(),
 1259                Err(e) => fail!(e)
 1260              }
 1261          }
 1262  
 1263          let days = [
 1264              ~"Sunday",
 1265              ~"Monday",
 1266              ~"Tuesday",
 1267              ~"Wednesday",
 1268              ~"Thursday",
 1269              ~"Friday",
 1270              ~"Saturday"
 1271          ];
 1272          for day in days.iter() {
 1273              assert!(test(*day, "%A"));
 1274          }
 1275  
 1276          let days = [
 1277              ~"Sun",
 1278              ~"Mon",
 1279              ~"Tue",
 1280              ~"Wed",
 1281              ~"Thu",
 1282              ~"Fri",
 1283              ~"Sat"
 1284          ];
 1285          for day in days.iter() {
 1286              assert!(test(*day, "%a"));
 1287          }
 1288  
 1289          let months = [
 1290              ~"January",
 1291              ~"February",
 1292              ~"March",
 1293              ~"April",
 1294              ~"May",
 1295              ~"June",
 1296              ~"July",
 1297              ~"August",
 1298              ~"September",
 1299              ~"October",
 1300              ~"November",
 1301              ~"December"
 1302          ];
 1303          for day in months.iter() {
 1304              assert!(test(*day, "%B"));
 1305          }
 1306  
 1307          let months = [
 1308              ~"Jan",
 1309              ~"Feb",
 1310              ~"Mar",
 1311              ~"Apr",
 1312              ~"May",
 1313              ~"Jun",
 1314              ~"Jul",
 1315              ~"Aug",
 1316              ~"Sep",
 1317              ~"Oct",
 1318              ~"Nov",
 1319              ~"Dec"
 1320          ];
 1321          for day in months.iter() {
 1322              assert!(test(*day, "%b"));
 1323          }
 1324  
 1325          assert!(test("19", "%C"));
 1326          assert!(test("Fri Feb 13 23:31:30 2009", "%c"));
 1327          assert!(test("02/13/09", "%D"));
 1328          assert!(test("03", "%d"));
 1329          assert!(test("13", "%d"));
 1330          assert!(test(" 3", "%e"));
 1331          assert!(test("13", "%e"));
 1332          assert!(test("2009-02-13", "%F"));
 1333          assert!(test("03", "%H"));
 1334          assert!(test("13", "%H"));
 1335          assert!(test("03", "%I")); // FIXME (#2350): flesh out
 1336          assert!(test("11", "%I")); // FIXME (#2350): flesh out
 1337          assert!(test("044", "%j"));
 1338          assert!(test(" 3", "%k"));
 1339          assert!(test("13", "%k"));
 1340          assert!(test(" 1", "%l"));
 1341          assert!(test("11", "%l"));
 1342          assert!(test("03", "%M"));
 1343          assert!(test("13", "%M"));
 1344          assert!(test("\n", "%n"));
 1345          assert!(test("am", "%P"));
 1346          assert!(test("pm", "%P"));
 1347          assert!(test("AM", "%p"));
 1348          assert!(test("PM", "%p"));
 1349          assert!(test("23:31", "%R"));
 1350          assert!(test("11:31:30 AM", "%r"));
 1351          assert!(test("11:31:30 PM", "%r"));
 1352          assert!(test("03", "%S"));
 1353          assert!(test("13", "%S"));
 1354          assert!(test("15:31:30", "%T"));
 1355          assert!(test("\t", "%t"));
 1356          assert!(test("1", "%u"));
 1357          assert!(test("7", "%u"));
 1358          assert!(test("13-Feb-2009", "%v"));
 1359          assert!(test("0", "%w"));
 1360          assert!(test("6", "%w"));
 1361          assert!(test("2009", "%Y"));
 1362          assert!(test("09", "%y"));
 1363          assert!(strptime("UTC", "%Z").unwrap().tm_zone ==
 1364              ~"UTC");
 1365          assert!(strptime("PST", "%Z").unwrap().tm_zone ==
 1366              ~"");
 1367          assert!(strptime("-0000", "%z").unwrap().tm_gmtoff ==
 1368              0);
 1369          assert!(strptime("-0800", "%z").unwrap().tm_gmtoff ==
 1370              0);
 1371          assert!(test("%", "%%"));
 1372  
 1373          // Test for #7256
 1374          assert_eq!(strptime("360", "%Y-%m-%d"), Err(~"Invalid year"))
 1375      }
 1376  
 1377      fn test_ctime() {
 1378          set_time_zone();
 1379  
 1380          let time = Timespec::new(1234567890, 54321);
 1381          let utc   = at_utc(time);
 1382          let local = at(time);
 1383  
 1384          debug!("test_ctime: {:?} {:?}", utc.ctime(), local.ctime());
 1385  
 1386          assert_eq!(utc.ctime(), ~"Fri Feb 13 23:31:30 2009");
 1387          assert_eq!(local.ctime(), ~"Fri Feb 13 15:31:30 2009");
 1388      }
 1389  
 1390      fn test_strftime() {
 1391          set_time_zone();
 1392  
 1393          let time = Timespec::new(1234567890, 54321);
 1394          let utc = at_utc(time);
 1395          let local = at(time);
 1396  
 1397          assert_eq!(local.strftime(""), ~"");
 1398          assert_eq!(local.strftime("%A"), ~"Friday");
 1399          assert_eq!(local.strftime("%a"), ~"Fri");
 1400          assert_eq!(local.strftime("%B"), ~"February");
 1401          assert_eq!(local.strftime("%b"), ~"Feb");
 1402          assert_eq!(local.strftime("%C"), ~"20");
 1403          assert_eq!(local.strftime("%c"), ~"Fri Feb 13 15:31:30 2009");
 1404          assert_eq!(local.strftime("%D"), ~"02/13/09");
 1405          assert_eq!(local.strftime("%d"), ~"13");
 1406          assert_eq!(local.strftime("%e"), ~"13");
 1407          assert_eq!(local.strftime("%f"), ~"000054321");
 1408          assert_eq!(local.strftime("%F"), ~"2009-02-13");
 1409          assert_eq!(local.strftime("%G"), ~"2009");
 1410          assert_eq!(local.strftime("%g"), ~"09");
 1411          assert_eq!(local.strftime("%H"), ~"15");
 1412          assert_eq!(local.strftime("%I"), ~"03");
 1413          assert_eq!(local.strftime("%j"), ~"044");
 1414          assert_eq!(local.strftime("%k"), ~"15");
 1415          assert_eq!(local.strftime("%l"), ~" 3");
 1416          assert_eq!(local.strftime("%M"), ~"31");
 1417          assert_eq!(local.strftime("%m"), ~"02");
 1418          assert_eq!(local.strftime("%n"), ~"\n");
 1419          assert_eq!(local.strftime("%P"), ~"pm");
 1420          assert_eq!(local.strftime("%p"), ~"PM");
 1421          assert_eq!(local.strftime("%R"), ~"15:31");
 1422          assert_eq!(local.strftime("%r"), ~"03:31:30 PM");
 1423          assert_eq!(local.strftime("%S"), ~"30");
 1424          assert_eq!(local.strftime("%s"), ~"1234567890");
 1425          assert_eq!(local.strftime("%T"), ~"15:31:30");
 1426          assert_eq!(local.strftime("%t"), ~"\t");
 1427          assert_eq!(local.strftime("%U"), ~"06");
 1428          assert_eq!(local.strftime("%u"), ~"5");
 1429          assert_eq!(local.strftime("%V"), ~"07");
 1430          assert_eq!(local.strftime("%v"), ~"13-Feb-2009");
 1431          assert_eq!(local.strftime("%W"), ~"06");
 1432          assert_eq!(local.strftime("%w"), ~"5");
 1433          assert_eq!(local.strftime("%X"), ~"15:31:30"); // FIXME (#2350): support locale
 1434          assert_eq!(local.strftime("%x"), ~"02/13/09"); // FIXME (#2350): support locale
 1435          assert_eq!(local.strftime("%Y"), ~"2009");
 1436          assert_eq!(local.strftime("%y"), ~"09");
 1437          assert_eq!(local.strftime("%+"), ~"2009-02-13T15:31:30-08:00");
 1438  
 1439          // FIXME (#2350): We should probably standardize on the timezone
 1440          // abbreviation.
 1441          let zone = local.strftime("%Z");
 1442          assert!(zone == ~"PST" || zone == ~"Pacific Standard Time");
 1443  
 1444          assert_eq!(local.strftime("%z"), ~"-0800");
 1445          assert_eq!(local.strftime("%%"), ~"%");
 1446  
 1447          // FIXME (#2350): We should probably standardize on the timezone
 1448          // abbreviation.
 1449          let rfc822 = local.rfc822();
 1450          let prefix = ~"Fri, 13 Feb 2009 15:31:30 ";
 1451          assert!(rfc822 == prefix + "PST" || rfc822 == prefix + "Pacific Standard Time");
 1452  
 1453          assert_eq!(local.ctime(), ~"Fri Feb 13 15:31:30 2009");
 1454          assert_eq!(local.rfc822z(), ~"Fri, 13 Feb 2009 15:31:30 -0800");
 1455          assert_eq!(local.rfc3339(), ~"2009-02-13T15:31:30-08:00");
 1456  
 1457          assert_eq!(utc.ctime(), ~"Fri Feb 13 23:31:30 2009");
 1458          assert_eq!(utc.rfc822(), ~"Fri, 13 Feb 2009 23:31:30 GMT");
 1459          assert_eq!(utc.rfc822z(), ~"Fri, 13 Feb 2009 23:31:30 -0000");
 1460          assert_eq!(utc.rfc3339(), ~"2009-02-13T23:31:30Z");
 1461      }
 1462  
 1463      fn test_timespec_eq_ord() {
 1464          let a = &Timespec::new(-2, 1);
 1465          let b = &Timespec::new(-1, 2);
 1466          let c = &Timespec::new(1, 2);
 1467          let d = &Timespec::new(2, 1);
 1468          let e = &Timespec::new(2, 1);
 1469  
 1470          assert!(d.eq(e));
 1471          assert!(c.ne(e));
 1472  
 1473          assert!(a.lt(b));
 1474          assert!(b.lt(c));
 1475          assert!(c.lt(d));
 1476  
 1477          assert!(a.le(b));
 1478          assert!(b.le(c));
 1479          assert!(c.le(d));
 1480          assert!(d.le(e));
 1481          assert!(e.le(d));
 1482  
 1483          assert!(b.ge(a));
 1484          assert!(c.ge(b));
 1485          assert!(d.ge(c));
 1486          assert!(e.ge(d));
 1487          assert!(d.ge(e));
 1488  
 1489          assert!(b.gt(a));
 1490          assert!(c.gt(b));
 1491          assert!(d.gt(c));
 1492      }
 1493  
 1494      #[test]
 1495      #[ignore(cfg(target_os = "android"))] // FIXME #10958
 1496      fn run_tests() {
 1497          // The tests race on tzset. So instead of having many independent
 1498          // tests, we will just call the functions now.
 1499          test_get_time();
 1500          test_precise_time();
 1501          test_at_utc();
 1502          test_at();
 1503          test_to_timespec();
 1504          test_conversions();
 1505          test_strptime();
 1506          test_ctime();
 1507          test_strftime();
 1508          test_timespec_eq_ord();
 1509      }
 1510  }

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


libtime/lib.rs:235:1-235:1 -fn- definition:

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


libtime/lib.rs:423:4-423:4 -fn- definition:
    fn match_fractional_seconds(ss: &str, pos: uint) -> (i32, uint) {
        let len = ss.len();
references:-
571:             let (val, pos) = match_fractional_seconds(s, pos);


libtime/lib.rs:843:4-843:4 -fn- definition:
    fn days_in_year(year: int) -> i32 {
        if (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) {
references:-
877:             days = iso_week_days (tm.tm_yday + (days_in_year(year)), tm.tm_wday);
879:             let d: int = iso_week_days (tm.tm_yday - (days_in_year(year)),


libtime/lib.rs:367:4-367:4 -fn- definition:
    fn match_str(s: &str, pos: uint, needle: &str) -> bool {
        let mut i = pos;
references:-
385:                     if match_str(ss, pos, *needle) {
731:             if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") {
..1more..


libtime/lib.rs:450:4-450:4 -fn- definition:
    fn match_digits_in_range(ss: &str, pos: uint, digits: uint, ws: bool,
                             min: i32, max: i32) -> Option<(i32, uint)> {
references:-
560:           'd' => match match_digits_in_range(s, pos, 2u, false, 1_i32,
625:             match match_digits_in_range(s, pos, 2u, false, 0_i32, 59_i32) {
533:           'C' => match match_digits_in_range(s, pos, 2u, false, 0_i32,
668:             match match_digits_in_range(s, pos, 2u, false, 0_i32, 60_i32) {
705:             match match_digits_in_range(s, pos, 1u, false, 0_i32, 6_i32) {
599:             match match_digits_in_range(s, pos, 3u, false, 1_i32, 366_i32) {
721:             match match_digits_in_range(s, pos, 2u, false, 0_i32, 99_i32) {
631:             match match_digits_in_range(s, pos, 2u, false, 1_i32, 12_i32) {
565:           'e' => match match_digits_in_range(s, pos, 2u, true, 1_i32,
687:             match match_digits_in_range(s, pos, 1u, false, 1_i32, 7_i32) {
583:             match match_digits_in_range(s, pos, 2u, false, 0_i32, 23_i32) {
589:             match match_digits_in_range(s, pos, 2u, false, 1_i32, 12_i32) {
609:             match match_digits_in_range(s, pos, 2u, true, 0_i32, 23_i32) {
615:             match match_digits_in_range(s, pos, 2u, true, 1_i32, 12_i32) {


libtime/lib.rs:165:4-165:4 -fn- definition:
    fn os_precise_time_ns() -> u64 {
        let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
references:-
139:     return os_precise_time_ns();


libtime/lib.rs:472:4-472:4 -fn- definition:
    fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
      -> Result<uint, ~str> {
references:-
681:                 .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
551:                 .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
547:                 .and_then(|pos| parse_type(s, pos, 'e', &mut *tm))
545:                 .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
697:             parse_type(s, pos, 'e', &mut *tm)
679:             parse_type(s, pos, 'H', &mut *tm)
543:             parse_type(s, pos, 'a', &mut *tm)
699:                 .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
701:                 .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
665:                 .and_then(|pos| parse_type(s, pos, 'p', &mut *tm))
554:             parse_type(s, pos, 'm', &mut *tm)
656:                 .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
576:             parse_type(s, pos, 'Y', &mut *tm)
556:                 .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
580:                 .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
663:                 .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
683:                 .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
654:             parse_type(s, pos, 'H', &mut *tm)
558:                 .and_then(|pos| parse_type(s, pos, 'y', &mut *tm))
811:                 match parse_type(s, pos, ch, &mut tm) {
578:                 .and_then(|pos| parse_type(s, pos, 'm', &mut *tm))
659:             parse_type(s, pos, 'I', &mut *tm)
549:                 .and_then(|pos| parse_type(s, pos, 'T', &mut *tm))
661:                 .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))


libtime/lib.rs:870:4-870:4 -fn- definition:
    fn iso_week(ch:char, tm: &Tm) -> ~str {
        let mut year: int = tm.tm_year as int + 1900;
references:-
1021:           'V' => iso_week('V', tm),
973:           'G' => iso_week('G', tm),
974:           'g' => iso_week('g', tm),


libtime/lib.rs:271:53-271:53 -fn- definition:
/// Returns the specified time in the local timezone
pub fn at(clock: Timespec) -> Tm {
references:-
283:     at(get_time())
302:         at(self.to_timespec())


libtime/lib.rs:89:4-89:4 -fn- definition:
 */
pub fn get_time() -> Timespec {
references:-
268:     at_utc(get_time())
283:     at(get_time())


libtime/lib.rs:256:38-256:38 -fn- definition:
/// Returns the specified time in UTC
pub fn at_utc(clock: Timespec) -> Tm {
references:-
307:         at_utc(self.to_timespec())
268:     at_utc(get_time())


libtime/lib.rs:851:4-851:4 -fn- definition:
    fn iso_week_days(yday: i32, wday: i32) -> int {
        /* The number of days from the first day of the first ISO week of this
references:-
877:             days = iso_week_days (tm.tm_yday + (days_in_year(year)), tm.tm_wday);
879:             let d: int = iso_week_days (tm.tm_yday - (days_in_year(year)),
872:         let mut days: int = iso_week_days (tm.tm_yday, tm.tm_wday);


libtime/lib.rs:396:4-396:4 -fn- definition:
    fn match_digits(ss: &str, pos: uint, digits: uint, ws: bool)
      -> Option<(i32, uint)> {
references:-
452:         match match_digits(ss, pos, digits, ws) {
753:                 match match_digits(s, range.next, 4u, false) {
711:             match match_digits(s, pos, 4u, false) {


libtime/lib.rs:378:4-378:4 -fn- definition:
    fn match_strs(ss: &str, pos: uint, strs: &[(~str, i32)])
      -> Option<(i32, uint)> {
references:-
647:           'p' => match match_strs(s, pos,
487:           'a' => match match_strs(s, pos, [
516:           'b' | 'h' => match match_strs(s, pos, [
499:           'B' => match match_strs(s, pos, [
641:           'P' => match match_strs(s, pos,
475:           'A' => match match_strs(s, pos, [


libtime/lib.rs:69:75-69:75 -struct- definition:
#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, Encodable, Decodable, Show)]
pub struct Timespec { pub sec: i64, pub nsec: i32 }
references:-
69: pub struct Timespec { pub sec: i64, pub nsec: i32 }
257: pub fn at_utc(clock: Timespec) -> Tm {
69: pub struct Timespec { pub sec: i64, pub nsec: i32 }
79: impl Timespec {
69: pub struct Timespec { pub sec: i64, pub nsec: i32 }
259:         let Timespec { sec, nsec } = clock;
69: pub struct Timespec { pub sec: i64, pub nsec: i32 }
272: pub fn at(clock: Timespec) -> Tm {
289:     pub fn to_timespec(&self) -> Timespec {
69: pub struct Timespec { pub sec: i64, pub nsec: i32 }
274:         let Timespec { sec, nsec } = clock;
69: pub struct Timespec { pub sec: i64, pub nsec: i32 }
90: pub fn get_time() -> Timespec {
69: pub struct Timespec { pub sec: i64, pub nsec: i32 }
82:         Timespec { sec: sec, nsec: nsec }
69: pub struct Timespec { pub sec: i64, pub nsec: i32 }
80:     pub fn new(sec: i64, nsec: i32) -> Timespec {
69: pub struct Timespec { pub sec: i64, pub nsec: i32 }
..28more..


libtime/lib.rs:137:4-137:4 -fn- definition:
 */
pub fn precise_time_ns() -> u64 {
references:-
180:     return (precise_time_ns() as f64) / 1000000000.;


libtime/lib.rs:460:4-460:4 -fn- definition:
    fn parse_char(s: &str, pos: uint, c: char) -> Result<uint, ~str> {
        let range = s.char_range_at(pos);
references:-
769:           '%' => parse_char(s, pos, '%'),
698:                 .and_then(|pos|  parse_char(s, pos, '-'))
555:                 .and_then(|pos| parse_char(s, pos, '/'))
662:                 .and_then(|pos| parse_char(s, pos, ':'))
685:           't' => parse_char(s, pos, '\t'),
664:                 .and_then(|pos| parse_char(s, pos, ' '))
546:                 .and_then(|pos| parse_char(s, pos, ' '))
700:                 .and_then(|pos| parse_char(s, pos, '-'))
550:                 .and_then(|pos| parse_char(s, pos, ' '))
548:                 .and_then(|pos| parse_char(s, pos, ' '))
660:                 .and_then(|pos| parse_char(s, pos, ':'))
655:                 .and_then(|pos| parse_char(s, pos, ':'))
640:           'n' => parse_char(s, pos, '\n'),
680:                 .and_then(|pos| parse_char(s, pos, ':'))
577:                 .and_then(|pos| parse_char(s, pos, '-'))
557:                 .and_then(|pos| parse_char(s, pos, '/'))
682:                 .and_then(|pos| parse_char(s, pos, ':'))
544:                 .and_then(|pos| parse_char(s, pos, ' '))
579:                 .and_then(|pos| parse_char(s, pos, '-'))


libtime/lib.rs:896:4-896:4 -fn- definition:
    fn parse_type(ch: char, tm: &Tm) -> ~str {
      let die = || format!("strftime: can't understand this format {} ", ch);
references:-
956:                 parse_type('Y', tm))
962:                 parse_type('y', tm))
955:                 parse_type('T', tm),
971:                 parse_type('d', tm))
1011:                 parse_type('H', tm),
970:                 parse_type('m', tm),
1059:                 let s = parse_type(b[0] as char, tm);
1024:                 parse_type('e', tm),
969:                 parse_type('Y', tm),
1026:                 parse_type('Y', tm))
952:                 parse_type('a', tm),
1025:                 parse_type('b', tm),
1012:                 parse_type('M', tm),
953:                 parse_type('b', tm),
998:                 parse_type('M', tm))
1005:                 parse_type('p', tm))
1004:                 parse_type('S', tm),
997:                 parse_type('H', tm),
954:                 parse_type('e', tm),
960:                 parse_type('m', tm),
1002:                 parse_type('I', tm),
1003:                 parse_type('M', tm),
1013:                 parse_type('S', tm))
961:                 parse_type('d', tm),


libtime/lib.rs:191:51-191:51 -struct- definition:
#[deriving(Clone, Eq, Encodable, Decodable, Show)]
pub struct Tm {
references:-
472:     fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
191: pub struct Tm {
896:     fn parse_type(ch: char, tm: &Tm) -> ~str {
37:         pub fn rust_localtime(sec: i64, nsec: i32, result: &mut Tm);
777:     let mut tm = Tm {
842: pub fn strftime(format: &str, tm: &Tm) -> ~str {
236: pub fn empty_tm() -> Tm {
38:         pub fn rust_timegm(tm: &Tm) -> i64;
282: pub fn now() -> Tm {
272: pub fn at(clock: Timespec) -> Tm {
191: pub struct Tm {
267: pub fn now_utc() -> Tm {
191: pub struct Tm {
824:         Ok(Tm {
36:         pub fn rust_gmtime(sec: i64, nsec: i32, result: &mut Tm);
191: pub struct Tm {
870:     fn iso_week(ch:char, tm: &Tm) -> ~str {
191: pub struct Tm {
257: pub fn at_utc(clock: Timespec) -> Tm {
39:         pub fn rust_mktime(tm: &Tm) -> i64;
191: pub struct Tm {
287: impl Tm {
306:     pub fn to_utc(&self) -> Tm {
191: pub struct Tm {
366: pub fn strptime(s: &str, format: &str) -> Result<Tm, ~str> {
240:     Tm {
301:     pub fn to_local(&self) -> Tm {
..11more..


libtime/lib.rs:126:4-126:4 -fn- definition:
    unsafe fn os_get_time() -> (i64, i32) {
        let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
references:-
92:         let (sec, nsec) = os_get_time();