• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 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 <CoreFoundation/CFDate.h>
8 #include <CoreFoundation/CFTimeZone.h>
9 #include <mach/mach_time.h>
10 #include <sys/time.h>
11 #include <time.h>
12 
13 #include "base/basictypes.h"
14 #include "base/logging.h"
15 #include "base/mac/scoped_cftyperef.h"
16 
17 namespace base {
18 
19 // The Time routines in this file use Mach and CoreFoundation APIs, since the
20 // POSIX definition of time_t in Mac OS X wraps around after 2038--and
21 // there are already cookie expiration dates, etc., past that time out in
22 // the field.  Using CFDate prevents that problem, and using mach_absolute_time
23 // for TimeTicks gives us nice high-resolution interval timing.
24 
25 // Time -----------------------------------------------------------------------
26 
27 // Core Foundation uses a double second count since 2001-01-01 00:00:00 UTC.
28 // The UNIX epoch is 1970-01-01 00:00:00 UTC.
29 // Windows uses a Gregorian epoch of 1601.  We need to match this internally
30 // so that our time representations match across all platforms.  See bug 14734.
31 //   irb(main):010:0> Time.at(0).getutc()
32 //   => Thu Jan 01 00:00:00 UTC 1970
33 //   irb(main):011:0> Time.at(-11644473600).getutc()
34 //   => Mon Jan 01 00:00:00 UTC 1601
35 static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
36 static const int64 kWindowsEpochDeltaMilliseconds =
37     kWindowsEpochDeltaSeconds * Time::kMillisecondsPerSecond;
38 
39 // static
40 const int64 Time::kWindowsEpochDeltaMicroseconds =
41     kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
42 
43 // Some functions in time.cc use time_t directly, so we provide an offset
44 // to convert from time_t (Unix epoch) and internal (Windows epoch).
45 // static
46 const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
47 
48 // static
Now()49 Time Time::Now() {
50   CFAbsoluteTime now =
51       CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
52   return Time(static_cast<int64>(now * kMicrosecondsPerSecond) +
53       kWindowsEpochDeltaMicroseconds);
54 }
55 
56 // static
NowFromSystemTime()57 Time Time::NowFromSystemTime() {
58   // Just use Now() because Now() returns the system time.
59   return Now();
60 }
61 
62 // static
FromExploded(bool is_local,const Exploded & exploded)63 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
64   CFGregorianDate date;
65   date.second = exploded.second +
66       exploded.millisecond / static_cast<double>(kMillisecondsPerSecond);
67   date.minute = exploded.minute;
68   date.hour = exploded.hour;
69   date.day = exploded.day_of_month;
70   date.month = exploded.month;
71   date.year = exploded.year;
72 
73   base::mac::ScopedCFTypeRef<CFTimeZoneRef>
74       time_zone(is_local ? CFTimeZoneCopySystem() : NULL);
75   CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) +
76       kCFAbsoluteTimeIntervalSince1970;
77   return Time(static_cast<int64>(seconds * kMicrosecondsPerSecond) +
78       kWindowsEpochDeltaMicroseconds);
79 }
80 
Explode(bool is_local,Exploded * exploded) const81 void Time::Explode(bool is_local, Exploded* exploded) const {
82   CFAbsoluteTime seconds =
83       ((static_cast<double>(us_) - kWindowsEpochDeltaMicroseconds) /
84       kMicrosecondsPerSecond) - kCFAbsoluteTimeIntervalSince1970;
85 
86   base::mac::ScopedCFTypeRef<CFTimeZoneRef>
87       time_zone(is_local ? CFTimeZoneCopySystem() : NULL);
88   CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(seconds, time_zone);
89 
90   exploded->year = date.year;
91   exploded->month = date.month;
92   exploded->day_of_month = date.day;
93   exploded->hour = date.hour;
94   exploded->minute = date.minute;
95   exploded->second = date.second;
96   exploded->millisecond  =
97       static_cast<int>(date.second * kMillisecondsPerSecond) %
98       kMillisecondsPerSecond;
99 }
100 
101 // TimeTicks ------------------------------------------------------------------
102 
103 // static
Now()104 TimeTicks TimeTicks::Now() {
105   uint64_t absolute_micro;
106 
107   static mach_timebase_info_data_t timebase_info;
108   if (timebase_info.denom == 0) {
109     // Zero-initialization of statics guarantees that denom will be 0 before
110     // calling mach_timebase_info.  mach_timebase_info will never set denom to
111     // 0 as that would be invalid, so the zero-check can be used to determine
112     // whether mach_timebase_info has already been called.  This is
113     // recommended by Apple's QA1398.
114     kern_return_t kr = mach_timebase_info(&timebase_info);
115     DCHECK(kr == KERN_SUCCESS);
116   }
117 
118   // mach_absolute_time is it when it comes to ticks on the Mac.  Other calls
119   // with less precision (such as TickCount) just call through to
120   // mach_absolute_time.
121 
122   // timebase_info converts absolute time tick units into nanoseconds.  Convert
123   // to microseconds up front to stave off overflows.
124   absolute_micro = mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
125                    timebase_info.numer / timebase_info.denom;
126 
127   // Don't bother with the rollover handling that the Windows version does.
128   // With numer and denom = 1 (the expected case), the 64-bit absolute time
129   // reported in nanoseconds is enough to last nearly 585 years.
130 
131   return TimeTicks(absolute_micro);
132 }
133 
134 // static
HighResNow()135 TimeTicks TimeTicks::HighResNow() {
136   return Now();
137 }
138 
139 }  // namespace base
140