OLD | NEW |
| (Empty) |
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.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::NowFromSystemTraceTime() { | |
196 return HighResNow(); | |
197 } | |
198 | |
199 } // namespace base | |
OLD | NEW |