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 <cmath>
8 #include <ios>
9 #include <limits>
10 #include <ostream>
11 #include <sstream>
12
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/no_destructor.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/third_party/nspr/prtime.h"
18 #include "base/time/time_override.h"
19 #include "build/build_config.h"
20
21 namespace base {
22
23 namespace internal {
24
25 TimeNowFunction g_time_now_function = &subtle::TimeNowIgnoringOverride;
26
27 TimeNowFunction g_time_now_from_system_time_function =
28 &subtle::TimeNowFromSystemTimeIgnoringOverride;
29
30 TimeTicksNowFunction g_time_ticks_now_function =
31 &subtle::TimeTicksNowIgnoringOverride;
32
33 ThreadTicksNowFunction g_thread_ticks_now_function =
34 &subtle::ThreadTicksNowIgnoringOverride;
35
36 } // namespace internal
37
38 // TimeDelta ------------------------------------------------------------------
39
InDays() const40 int TimeDelta::InDays() const {
41 if (is_max()) {
42 // Preserve max to prevent overflow.
43 return std::numeric_limits<int>::max();
44 }
45 return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
46 }
47
InDaysFloored() const48 int TimeDelta::InDaysFloored() const {
49 if (is_max()) {
50 // Preserve max to prevent overflow.
51 return std::numeric_limits<int>::max();
52 }
53 int result = delta_ / Time::kMicrosecondsPerDay;
54 int64_t remainder = delta_ - (result * Time::kMicrosecondsPerDay);
55 if (remainder < 0) {
56 --result; // Use floor(), not trunc() rounding behavior.
57 }
58 return result;
59 }
60
InHours() const61 int TimeDelta::InHours() const {
62 if (is_max()) {
63 // Preserve max to prevent overflow.
64 return std::numeric_limits<int>::max();
65 }
66 return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
67 }
68
InMinutes() const69 int TimeDelta::InMinutes() const {
70 if (is_max()) {
71 // Preserve max to prevent overflow.
72 return std::numeric_limits<int>::max();
73 }
74 return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
75 }
76
InSecondsF() const77 double TimeDelta::InSecondsF() const {
78 if (is_max()) {
79 // Preserve max to prevent overflow.
80 return std::numeric_limits<double>::infinity();
81 }
82 return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
83 }
84
InSeconds() const85 int64_t TimeDelta::InSeconds() const {
86 if (is_max()) {
87 // Preserve max to prevent overflow.
88 return std::numeric_limits<int64_t>::max();
89 }
90 return delta_ / Time::kMicrosecondsPerSecond;
91 }
92
InMillisecondsF() const93 double TimeDelta::InMillisecondsF() const {
94 if (is_max()) {
95 // Preserve max to prevent overflow.
96 return std::numeric_limits<double>::infinity();
97 }
98 return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
99 }
100
InMilliseconds() const101 int64_t TimeDelta::InMilliseconds() const {
102 if (is_max()) {
103 // Preserve max to prevent overflow.
104 return std::numeric_limits<int64_t>::max();
105 }
106 return delta_ / Time::kMicrosecondsPerMillisecond;
107 }
108
InMillisecondsRoundedUp() const109 int64_t TimeDelta::InMillisecondsRoundedUp() const {
110 if (is_max()) {
111 // Preserve max to prevent overflow.
112 return std::numeric_limits<int64_t>::max();
113 }
114 int64_t result = delta_ / Time::kMicrosecondsPerMillisecond;
115 int64_t remainder = delta_ - (result * Time::kMicrosecondsPerMillisecond);
116 if (remainder > 0) {
117 ++result; // Use ceil(), not trunc() rounding behavior.
118 }
119 return result;
120 }
121
InMicrosecondsF() const122 double TimeDelta::InMicrosecondsF() const {
123 if (is_max()) {
124 // Preserve max to prevent overflow.
125 return std::numeric_limits<double>::infinity();
126 }
127 return static_cast<double>(delta_);
128 }
129
InNanoseconds() const130 int64_t TimeDelta::InNanoseconds() const {
131 if (is_max()) {
132 // Preserve max to prevent overflow.
133 return std::numeric_limits<int64_t>::max();
134 }
135 return delta_ * Time::kNanosecondsPerMicrosecond;
136 }
137
operator <<(std::ostream & os,TimeDelta time_delta)138 std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
139 return os << time_delta.InSecondsF() << " s";
140 }
141
142 // Time -----------------------------------------------------------------------
143
144 // static
Now()145 Time Time::Now() {
146 return internal::g_time_now_function();
147 }
148
149 // static
NowFromSystemTime()150 Time Time::NowFromSystemTime() {
151 // Just use g_time_now_function because it returns the system time.
152 return internal::g_time_now_from_system_time_function();
153 }
154
155 // static
FromDeltaSinceWindowsEpoch(TimeDelta delta)156 Time Time::FromDeltaSinceWindowsEpoch(TimeDelta delta) {
157 return Time(delta.InMicroseconds());
158 }
159
ToDeltaSinceWindowsEpoch() const160 TimeDelta Time::ToDeltaSinceWindowsEpoch() const {
161 return TimeDelta::FromMicroseconds(us_);
162 }
163
164 // static
FromTimeT(time_t tt)165 Time Time::FromTimeT(time_t tt) {
166 if (tt == 0)
167 return Time(); // Preserve 0 so we can tell it doesn't exist.
168 if (tt == std::numeric_limits<time_t>::max())
169 return Max();
170 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt);
171 }
172
ToTimeT() const173 time_t Time::ToTimeT() const {
174 if (is_null())
175 return 0; // Preserve 0 so we can tell it doesn't exist.
176 if (is_max()) {
177 // Preserve max without offset to prevent overflow.
178 return std::numeric_limits<time_t>::max();
179 }
180 if (std::numeric_limits<int64_t>::max() - kTimeTToMicrosecondsOffset <= us_) {
181 DLOG(WARNING) << "Overflow when converting base::Time with internal " <<
182 "value " << us_ << " to time_t.";
183 return std::numeric_limits<time_t>::max();
184 }
185 return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond;
186 }
187
188 // static
FromDoubleT(double dt)189 Time Time::FromDoubleT(double dt) {
190 if (dt == 0 || std::isnan(dt))
191 return Time(); // Preserve 0 so we can tell it doesn't exist.
192 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt);
193 }
194
ToDoubleT() const195 double Time::ToDoubleT() const {
196 if (is_null())
197 return 0; // Preserve 0 so we can tell it doesn't exist.
198 if (is_max()) {
199 // Preserve max without offset to prevent overflow.
200 return std::numeric_limits<double>::infinity();
201 }
202 return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
203 static_cast<double>(kMicrosecondsPerSecond));
204 }
205
206 #if defined(OS_POSIX)
207 // static
FromTimeSpec(const timespec & ts)208 Time Time::FromTimeSpec(const timespec& ts) {
209 return FromDoubleT(ts.tv_sec +
210 static_cast<double>(ts.tv_nsec) /
211 base::Time::kNanosecondsPerSecond);
212 }
213 #endif
214
215 // static
FromJsTime(double ms_since_epoch)216 Time Time::FromJsTime(double ms_since_epoch) {
217 // The epoch is a valid time, so this constructor doesn't interpret
218 // 0 as the null time.
219 return Time(kTimeTToMicrosecondsOffset) +
220 TimeDelta::FromMillisecondsD(ms_since_epoch);
221 }
222
ToJsTime() const223 double Time::ToJsTime() const {
224 if (is_null()) {
225 // Preserve 0 so the invalid result doesn't depend on the platform.
226 return 0;
227 }
228 return ToJsTimeIgnoringNull();
229 }
230
ToJsTimeIgnoringNull() const231 double Time::ToJsTimeIgnoringNull() const {
232 if (is_max()) {
233 // Preserve max without offset to prevent overflow.
234 return std::numeric_limits<double>::infinity();
235 }
236 return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
237 kMicrosecondsPerMillisecond);
238 }
239
FromJavaTime(int64_t ms_since_epoch)240 Time Time::FromJavaTime(int64_t ms_since_epoch) {
241 return base::Time::UnixEpoch() +
242 base::TimeDelta::FromMilliseconds(ms_since_epoch);
243 }
244
ToJavaTime() const245 int64_t Time::ToJavaTime() const {
246 if (is_null()) {
247 // Preserve 0 so the invalid result doesn't depend on the platform.
248 return 0;
249 }
250 if (is_max()) {
251 // Preserve max without offset to prevent overflow.
252 return std::numeric_limits<int64_t>::max();
253 }
254 return ((us_ - kTimeTToMicrosecondsOffset) /
255 kMicrosecondsPerMillisecond);
256 }
257
258 // static
UnixEpoch()259 Time Time::UnixEpoch() {
260 Time time;
261 time.us_ = kTimeTToMicrosecondsOffset;
262 return time;
263 }
264
Midnight(bool is_local) const265 Time Time::Midnight(bool is_local) const {
266 Exploded exploded;
267 Explode(is_local, &exploded);
268 exploded.hour = 0;
269 exploded.minute = 0;
270 exploded.second = 0;
271 exploded.millisecond = 0;
272 Time out_time;
273 if (FromExploded(is_local, exploded, &out_time)) {
274 return out_time;
275 } else if (is_local) {
276 // Hitting this branch means 00:00:00am of the current day
277 // does not exist (due to Daylight Saving Time in some countries
278 // where clocks are shifted at midnight). In this case, midnight
279 // should be defined as 01:00:00am.
280 exploded.hour = 1;
281 if (FromExploded(is_local, exploded, &out_time))
282 return out_time;
283 }
284 // This function must not fail.
285 NOTREACHED();
286 return Time();
287 }
288
289 #if !defined(MOZ_SANDBOX)
290 // static
FromStringInternal(const char * time_string,bool is_local,Time * parsed_time)291 bool Time::FromStringInternal(const char* time_string,
292 bool is_local,
293 Time* parsed_time) {
294 DCHECK((time_string != nullptr) && (parsed_time != nullptr));
295
296 if (time_string[0] == '\0')
297 return false;
298
299 PRTime result_time = 0;
300 PRStatus result = PR_ParseTimeString(time_string,
301 is_local ? PR_FALSE : PR_TRUE,
302 &result_time);
303 if (PR_SUCCESS != result)
304 return false;
305
306 result_time += kTimeTToMicrosecondsOffset;
307 *parsed_time = Time(result_time);
308 return true;
309 }
310 #endif
311
312 // static
ExplodedMostlyEquals(const Exploded & lhs,const Exploded & rhs)313 bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) {
314 return lhs.year == rhs.year && lhs.month == rhs.month &&
315 lhs.day_of_month == rhs.day_of_month && lhs.hour == rhs.hour &&
316 lhs.minute == rhs.minute && lhs.second == rhs.second &&
317 lhs.millisecond == rhs.millisecond;
318 }
319
320 // static
FromMillisecondsSinceUnixEpoch(int64_t unix_milliseconds,Time * time)321 bool Time::FromMillisecondsSinceUnixEpoch(int64_t unix_milliseconds,
322 Time* time) {
323 // Adjust the provided time from milliseconds since the Unix epoch (1970) to
324 // microseconds since the Windows epoch (1601), avoiding overflows.
325 base::CheckedNumeric<int64_t> checked_microseconds_win_epoch =
326 unix_milliseconds;
327 checked_microseconds_win_epoch *= kMicrosecondsPerMillisecond;
328 checked_microseconds_win_epoch += kTimeTToMicrosecondsOffset;
329 if (!checked_microseconds_win_epoch.IsValid()) {
330 *time = base::Time(0);
331 return false;
332 }
333
334 *time = Time(checked_microseconds_win_epoch.ValueOrDie());
335 return true;
336 }
337
ToRoundedDownMillisecondsSinceUnixEpoch() const338 int64_t Time::ToRoundedDownMillisecondsSinceUnixEpoch() const {
339 // Adjust from Windows epoch (1601) to Unix epoch (1970).
340 int64_t microseconds = us_ - kTimeTToMicrosecondsOffset;
341
342 // Round the microseconds towards -infinity.
343 if (microseconds >= 0) {
344 // In this case, rounding towards -infinity means rounding towards 0.
345 return microseconds / kMicrosecondsPerMillisecond;
346 } else {
347 return (microseconds - kMicrosecondsPerMillisecond + 1) /
348 kMicrosecondsPerMillisecond;
349 }
350 }
351
operator <<(std::ostream & os,Time time)352 std::ostream& operator<<(std::ostream& os, Time time) {
353 Time::Exploded exploded;
354 time.UTCExplode(&exploded);
355 // Use StringPrintf because iostreams formatting is painful.
356 return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC",
357 exploded.year,
358 exploded.month,
359 exploded.day_of_month,
360 exploded.hour,
361 exploded.minute,
362 exploded.second,
363 exploded.millisecond);
364 }
365
366 // TimeTicks ------------------------------------------------------------------
367
368 // static
Now()369 TimeTicks TimeTicks::Now() {
370 return internal::g_time_ticks_now_function();
371 }
372
373 // static
UnixEpoch()374 TimeTicks TimeTicks::UnixEpoch() {
375 static const base::NoDestructor<base::TimeTicks> epoch([]() {
376 return subtle::TimeTicksNowIgnoringOverride() -
377 (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch());
378 }());
379 return *epoch;
380 }
381
SnappedToNextTick(TimeTicks tick_phase,TimeDelta tick_interval) const382 TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
383 TimeDelta tick_interval) const {
384 // |interval_offset| is the offset from |this| to the next multiple of
385 // |tick_interval| after |tick_phase|, possibly negative if in the past.
386 TimeDelta interval_offset = (tick_phase - *this) % tick_interval;
387 // If |this| is exactly on the interval (i.e. offset==0), don't adjust.
388 // Otherwise, if |tick_phase| was in the past, adjust forward to the next
389 // tick after |this|.
390 if (!interval_offset.is_zero() && tick_phase < *this)
391 interval_offset += tick_interval;
392 return *this + interval_offset;
393 }
394
operator <<(std::ostream & os,TimeTicks time_ticks)395 std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) {
396 // This function formats a TimeTicks object as "bogo-microseconds".
397 // The origin and granularity of the count are platform-specific, and may very
398 // from run to run. Although bogo-microseconds usually roughly correspond to
399 // real microseconds, the only real guarantee is that the number never goes
400 // down during a single run.
401 const TimeDelta as_time_delta = time_ticks - TimeTicks();
402 return os << as_time_delta.InMicroseconds() << " bogo-microseconds";
403 }
404
405 // ThreadTicks ----------------------------------------------------------------
406
407 // static
Now()408 ThreadTicks ThreadTicks::Now() {
409 return internal::g_thread_ticks_now_function();
410 }
411
operator <<(std::ostream & os,ThreadTicks thread_ticks)412 std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
413 const TimeDelta as_time_delta = thread_ticks - ThreadTicks();
414 return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
415 }
416
417 // Time::Exploded -------------------------------------------------------------
418
is_in_range(int value,int lo,int hi)419 inline bool is_in_range(int value, int lo, int hi) {
420 return lo <= value && value <= hi;
421 }
422
HasValidValues() const423 bool Time::Exploded::HasValidValues() const {
424 return is_in_range(month, 1, 12) &&
425 is_in_range(day_of_week, 0, 6) &&
426 is_in_range(day_of_month, 1, 31) &&
427 is_in_range(hour, 0, 23) &&
428 is_in_range(minute, 0, 59) &&
429 is_in_range(second, 0, 60) &&
430 is_in_range(millisecond, 0, 999);
431 }
432
433 } // namespace base
434