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