Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/time.h"
      6 
      7 #include <sys/time.h>
      8 #include <time.h>
      9 
     10 #include <limits>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/logging.h"
     14 
     15 namespace base {
     16 
     17 #if !defined(OS_MACOSX)
     18 // The Time routines in this file use standard POSIX routines, or almost-
     19 // standard routines in the case of timegm.  We need to use a Mach-specific
     20 // function for TimeTicks::Now() on Mac OS X.
     21 
     22 // Time -----------------------------------------------------------------------
     23 
     24 // Windows uses a Gregorian epoch of 1601.  We need to match this internally
     25 // so that our time representations match across all platforms.  See bug 14734.
     26 //   irb(main):010:0> Time.at(0).getutc()
     27 //   => Thu Jan 01 00:00:00 UTC 1970
     28 //   irb(main):011:0> Time.at(-11644473600).getutc()
     29 //   => Mon Jan 01 00:00:00 UTC 1601
     30 static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
     31 static const int64 kWindowsEpochDeltaMilliseconds =
     32     kWindowsEpochDeltaSeconds * Time::kMillisecondsPerSecond;
     33 
     34 // static
     35 const int64 Time::kWindowsEpochDeltaMicroseconds =
     36     kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
     37 
     38 // Some functions in time.cc use time_t directly, so we provide an offset
     39 // to convert from time_t (Unix epoch) and internal (Windows epoch).
     40 // static
     41 const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
     42 
     43 // static
     44 Time Time::Now() {
     45   struct timeval tv;
     46   struct timezone tz = { 0, 0 };  // UTC
     47   if (gettimeofday(&tv, &tz) != 0) {
     48     DCHECK(0) << "Could not determine time of day";
     49   }
     50   // Combine seconds and microseconds in a 64-bit field containing microseconds
     51   // since the epoch.  That's enough for nearly 600 centuries.  Adjust from
     52   // Unix (1970) to Windows (1601) epoch.
     53   return Time((tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec) +
     54       kWindowsEpochDeltaMicroseconds);
     55 }
     56 
     57 // static
     58 Time Time::NowFromSystemTime() {
     59   // Just use Now() because Now() returns the system time.
     60   return Now();
     61 }
     62 
     63 // static
     64 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
     65   struct tm timestruct;
     66   timestruct.tm_sec    = exploded.second;
     67   timestruct.tm_min    = exploded.minute;
     68   timestruct.tm_hour   = exploded.hour;
     69   timestruct.tm_mday   = exploded.day_of_month;
     70   timestruct.tm_mon    = exploded.month - 1;
     71   timestruct.tm_year   = exploded.year - 1900;
     72   timestruct.tm_wday   = exploded.day_of_week;  // mktime/timegm ignore this
     73   timestruct.tm_yday   = 0;     // mktime/timegm ignore this
     74   timestruct.tm_isdst  = -1;    // attempt to figure it out
     75   timestruct.tm_gmtoff = 0;     // not a POSIX field, so mktime/timegm ignore
     76   timestruct.tm_zone   = NULL;  // not a POSIX field, so mktime/timegm ignore
     77 
     78   time_t seconds;
     79   if (is_local)
     80     seconds = mktime(&timestruct);
     81   else
     82     seconds = timegm(&timestruct);
     83 
     84   int64 milliseconds;
     85   // Handle overflow.  Clamping the range to what mktime and timegm might
     86   // return is the best that can be done here.  It's not ideal, but it's better
     87   // than failing here or ignoring the overflow case and treating each time
     88   // overflow as one second prior to the epoch.
     89   if (seconds == -1 &&
     90       (exploded.year < 1969 || exploded.year > 1970)) {
     91     // If exploded.year is 1969 or 1970, take -1 as correct, with the
     92     // time indicating 1 second prior to the epoch.  (1970 is allowed to handle
     93     // time zone and DST offsets.)  Otherwise, return the most future or past
     94     // time representable.  Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
     95     //
     96     // The minimum and maximum representible times that mktime and timegm could
     97     // return are used here instead of values outside that range to allow for
     98     // proper round-tripping between exploded and counter-type time
     99     // representations in the presence of possible truncation to time_t by
    100     // division and use with other functions that accept time_t.
    101     //
    102     // When representing the most distant time in the future, add in an extra
    103     // 999ms to avoid the time being less than any other possible value that
    104     // this function can return.
    105     if (exploded.year < 1969) {
    106       milliseconds = std::numeric_limits<time_t>::min() *
    107                      kMillisecondsPerSecond;
    108     } else {
    109       milliseconds = (std::numeric_limits<time_t>::max() *
    110                       kMillisecondsPerSecond) +
    111                      kMillisecondsPerSecond - 1;
    112     }
    113   } else {
    114     milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond;
    115   }
    116 
    117   // Adjust from Unix (1970) to Windows (1601) epoch.
    118   return Time((milliseconds * kMicrosecondsPerMillisecond) +
    119       kWindowsEpochDeltaMicroseconds);
    120 }
    121 
    122 void Time::Explode(bool is_local, Exploded* exploded) const {
    123   // Time stores times with microsecond resolution, but Exploded only carries
    124   // millisecond resolution, so begin by being lossy.  Adjust from Windows
    125   // epoch (1601) to Unix epoch (1970);
    126   int64 milliseconds = (us_ - kWindowsEpochDeltaMicroseconds) /
    127       kMicrosecondsPerMillisecond;
    128   time_t seconds = milliseconds / kMillisecondsPerSecond;
    129 
    130   struct tm timestruct;
    131   if (is_local)
    132     localtime_r(&seconds, &timestruct);
    133   else
    134     gmtime_r(&seconds, &timestruct);
    135 
    136   exploded->year         = timestruct.tm_year + 1900;
    137   exploded->month        = timestruct.tm_mon + 1;
    138   exploded->day_of_week  = timestruct.tm_wday;
    139   exploded->day_of_month = timestruct.tm_mday;
    140   exploded->hour         = timestruct.tm_hour;
    141   exploded->minute       = timestruct.tm_min;
    142   exploded->second       = timestruct.tm_sec;
    143   exploded->millisecond  = milliseconds % kMillisecondsPerSecond;
    144 }
    145 
    146 // TimeTicks ------------------------------------------------------------------
    147 // FreeBSD 6 has CLOCK_MONOLITHIC but defines _POSIX_MONOTONIC_CLOCK to -1.
    148 #if (defined(OS_POSIX) &&                                               \
    149      defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
    150     defined(OS_FREEBSD)
    151 
    152 // static
    153 TimeTicks TimeTicks::Now() {
    154   uint64_t absolute_micro;
    155 
    156   struct timespec ts;
    157   if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
    158     NOTREACHED() << "clock_gettime(CLOCK_MONOTONIC) failed.";
    159     return TimeTicks();
    160   }
    161 
    162   absolute_micro =
    163       (static_cast<int64>(ts.tv_sec) * Time::kMicrosecondsPerSecond) +
    164       (static_cast<int64>(ts.tv_nsec) / Time::kNanosecondsPerMicrosecond);
    165 
    166   return TimeTicks(absolute_micro);
    167 }
    168 
    169 #else  // _POSIX_MONOTONIC_CLOCK
    170 #error No usable tick clock function on this platform.
    171 #endif  // _POSIX_MONOTONIC_CLOCK
    172 
    173 // static
    174 TimeTicks TimeTicks::HighResNow() {
    175   return Now();
    176 }
    177 
    178 #endif  // !OS_MACOSX
    179 
    180 struct timespec TimeDelta::ToTimeSpec() const {
    181   int64 microseconds = InMicroseconds();
    182   time_t seconds = 0;
    183   if (microseconds >= Time::kMicrosecondsPerSecond) {
    184     seconds = InSeconds();
    185     microseconds -= seconds * Time::kMicrosecondsPerSecond;
    186   }
    187   struct timespec result =
    188       {seconds,
    189        microseconds * Time::kNanosecondsPerMicrosecond};
    190   return result;
    191 }
    192 
    193 }  // namespace base
    194