Home | History | Annotate | Download | only in time
      1 // Copyright (c) 2012 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/time.h"
      6 
      7 #include <CoreFoundation/CFDate.h>
      8 #include <CoreFoundation/CFTimeZone.h>
      9 #include <mach/mach_time.h>
     10 #include <sys/sysctl.h>
     11 #include <sys/time.h>
     12 #include <sys/types.h>
     13 #include <time.h>
     14 
     15 #include "base/basictypes.h"
     16 #include "base/logging.h"
     17 #include "base/mac/scoped_cftyperef.h"
     18 
     19 namespace {
     20 
     21 uint64_t ComputeCurrentTicks() {
     22 #if defined(OS_IOS)
     23   // On iOS mach_absolute_time stops while the device is sleeping. Instead use
     24   // now - KERN_BOOTTIME to get a time difference that is not impacted by clock
     25   // changes. KERN_BOOTTIME will be updated by the system whenever the system
     26   // clock change.
     27   struct timeval boottime;
     28   int mib[2] = {CTL_KERN, KERN_BOOTTIME};
     29   size_t size = sizeof(boottime);
     30   int kr = sysctl(mib, arraysize(mib), &boottime, &size, NULL, 0);
     31   DCHECK_EQ(KERN_SUCCESS, kr);
     32   base::TimeDelta time_difference = base::Time::Now() -
     33       (base::Time::FromTimeT(boottime.tv_sec) +
     34        base::TimeDelta::FromMicroseconds(boottime.tv_usec));
     35   return time_difference.InMicroseconds();
     36 #else
     37   uint64_t absolute_micro;
     38 
     39   static mach_timebase_info_data_t timebase_info;
     40   if (timebase_info.denom == 0) {
     41     // Zero-initialization of statics guarantees that denom will be 0 before
     42     // calling mach_timebase_info.  mach_timebase_info will never set denom to
     43     // 0 as that would be invalid, so the zero-check can be used to determine
     44     // whether mach_timebase_info has already been called.  This is
     45     // recommended by Apple's QA1398.
     46     kern_return_t kr = mach_timebase_info(&timebase_info);
     47     DCHECK_EQ(KERN_SUCCESS, kr);
     48   }
     49 
     50   // mach_absolute_time is it when it comes to ticks on the Mac.  Other calls
     51   // with less precision (such as TickCount) just call through to
     52   // mach_absolute_time.
     53 
     54   // timebase_info converts absolute time tick units into nanoseconds.  Convert
     55   // to microseconds up front to stave off overflows.
     56   absolute_micro =
     57       mach_absolute_time() / base::Time::kNanosecondsPerMicrosecond *
     58       timebase_info.numer / timebase_info.denom;
     59 
     60   // Don't bother with the rollover handling that the Windows version does.
     61   // With numer and denom = 1 (the expected case), the 64-bit absolute time
     62   // reported in nanoseconds is enough to last nearly 585 years.
     63   return absolute_micro;
     64 #endif  // defined(OS_IOS)
     65 }
     66 
     67 }  // namespace
     68 
     69 namespace base {
     70 
     71 // The Time routines in this file use Mach and CoreFoundation APIs, since the
     72 // POSIX definition of time_t in Mac OS X wraps around after 2038--and
     73 // there are already cookie expiration dates, etc., past that time out in
     74 // the field.  Using CFDate prevents that problem, and using mach_absolute_time
     75 // for TimeTicks gives us nice high-resolution interval timing.
     76 
     77 // Time -----------------------------------------------------------------------
     78 
     79 // Core Foundation uses a double second count since 2001-01-01 00:00:00 UTC.
     80 // The UNIX epoch is 1970-01-01 00:00:00 UTC.
     81 // Windows uses a Gregorian epoch of 1601.  We need to match this internally
     82 // so that our time representations match across all platforms.  See bug 14734.
     83 //   irb(main):010:0> Time.at(0).getutc()
     84 //   => Thu Jan 01 00:00:00 UTC 1970
     85 //   irb(main):011:0> Time.at(-11644473600).getutc()
     86 //   => Mon Jan 01 00:00:00 UTC 1601
     87 static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
     88 static const int64 kWindowsEpochDeltaMilliseconds =
     89     kWindowsEpochDeltaSeconds * Time::kMillisecondsPerSecond;
     90 
     91 // static
     92 const int64 Time::kWindowsEpochDeltaMicroseconds =
     93     kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
     94 
     95 // Some functions in time.cc use time_t directly, so we provide an offset
     96 // to convert from time_t (Unix epoch) and internal (Windows epoch).
     97 // static
     98 const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
     99 
    100 // static
    101 Time Time::Now() {
    102   return FromCFAbsoluteTime(CFAbsoluteTimeGetCurrent());
    103 }
    104 
    105 // static
    106 Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
    107   if (t == 0)
    108     return Time();  // Consider 0 as a null Time.
    109   if (t == std::numeric_limits<CFAbsoluteTime>::max())
    110     return Max();
    111   return Time(static_cast<int64>(
    112       (t + kCFAbsoluteTimeIntervalSince1970) * kMicrosecondsPerSecond) +
    113       kWindowsEpochDeltaMicroseconds);
    114 }
    115 
    116 CFAbsoluteTime Time::ToCFAbsoluteTime() const {
    117   if (is_null())
    118     return 0;  // Consider 0 as a null Time.
    119   if (is_max())
    120     return std::numeric_limits<CFAbsoluteTime>::max();
    121   return (static_cast<CFAbsoluteTime>(us_ - kWindowsEpochDeltaMicroseconds) /
    122       kMicrosecondsPerSecond) - kCFAbsoluteTimeIntervalSince1970;
    123 }
    124 
    125 // static
    126 Time Time::NowFromSystemTime() {
    127   // Just use Now() because Now() returns the system time.
    128   return Now();
    129 }
    130 
    131 // static
    132 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
    133   CFGregorianDate date;
    134   date.second = exploded.second +
    135       exploded.millisecond / static_cast<double>(kMillisecondsPerSecond);
    136   date.minute = exploded.minute;
    137   date.hour = exploded.hour;
    138   date.day = exploded.day_of_month;
    139   date.month = exploded.month;
    140   date.year = exploded.year;
    141 
    142   base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
    143       is_local ? CFTimeZoneCopySystem() : NULL);
    144   CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) +
    145       kCFAbsoluteTimeIntervalSince1970;
    146   return Time(static_cast<int64>(seconds * kMicrosecondsPerSecond) +
    147       kWindowsEpochDeltaMicroseconds);
    148 }
    149 
    150 void Time::Explode(bool is_local, Exploded* exploded) const {
    151   // Avoid rounding issues, by only putting the integral number of seconds
    152   // (rounded towards -infinity) into a |CFAbsoluteTime| (which is a |double|).
    153   int64 microsecond = us_ % kMicrosecondsPerSecond;
    154   if (microsecond < 0)
    155     microsecond += kMicrosecondsPerSecond;
    156   CFAbsoluteTime seconds = ((us_ - microsecond) / kMicrosecondsPerSecond) -
    157                            kWindowsEpochDeltaSeconds -
    158                            kCFAbsoluteTimeIntervalSince1970;
    159 
    160   base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
    161       is_local ? CFTimeZoneCopySystem() : NULL);
    162   CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(seconds, time_zone);
    163   // 1 = Monday, ..., 7 = Sunday.
    164   int cf_day_of_week = CFAbsoluteTimeGetDayOfWeek(seconds, time_zone);
    165 
    166   exploded->year = date.year;
    167   exploded->month = date.month;
    168   exploded->day_of_week = cf_day_of_week % 7;
    169   exploded->day_of_month = date.day;
    170   exploded->hour = date.hour;
    171   exploded->minute = date.minute;
    172   // Make sure seconds are rounded down towards -infinity.
    173   exploded->second = floor(date.second);
    174   // Calculate milliseconds ourselves, since we rounded the |seconds|, making
    175   // sure to round towards -infinity.
    176   exploded->millisecond =
    177       (microsecond >= 0) ? microsecond / kMicrosecondsPerMillisecond :
    178                            (microsecond - kMicrosecondsPerMillisecond + 1) /
    179                                kMicrosecondsPerMillisecond;
    180 }
    181 
    182 // TimeTicks ------------------------------------------------------------------
    183 
    184 // static
    185 TimeTicks TimeTicks::Now() {
    186   return TimeTicks(ComputeCurrentTicks());
    187 }
    188 
    189 // static
    190 TimeTicks TimeTicks::HighResNow() {
    191   return Now();
    192 }
    193 
    194 // static
    195 TimeTicks TimeTicks::ThreadNow() {
    196   NOTREACHED();
    197   return TimeTicks();
    198 }
    199 
    200 // static
    201 TimeTicks TimeTicks::NowFromSystemTraceTime() {
    202   return HighResNow();
    203 }
    204 
    205 }  // namespace base
    206