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
138 namespace time_internal {
139
SaturatedAdd(int64_t value,TimeDelta delta)140 int64_t SaturatedAdd(int64_t value, TimeDelta delta) {
141 // Treat Min/Max() as +/- infinity (additions involving two infinities are
142 // only valid if signs match).
143 if (delta.is_max()) {
144 CHECK_GT(value, std::numeric_limits<int64_t>::min());
145 return std::numeric_limits<int64_t>::max();
146 } else if (delta.is_min()) {
147 CHECK_LT(value, std::numeric_limits<int64_t>::max());
148 return std::numeric_limits<int64_t>::min();
149 }
150
151 CheckedNumeric<int64_t> rv(value);
152 rv += delta.delta_;
153 if (rv.IsValid())
154 return rv.ValueOrDie();
155 // Positive RHS overflows. Negative RHS underflows.
156 if (delta.delta_ < 0)
157 return std::numeric_limits<int64_t>::min();
158 return std::numeric_limits<int64_t>::max();
159 }
160
SaturatedSub(int64_t value,TimeDelta delta)161 int64_t SaturatedSub(int64_t value, TimeDelta delta) {
162 // Treat Min/Max() as +/- infinity (subtractions involving two infinities are
163 // only valid if signs are opposite).
164 if (delta.is_max()) {
165 CHECK_LT(value, std::numeric_limits<int64_t>::max());
166 return std::numeric_limits<int64_t>::min();
167 } else if (delta.is_min()) {
168 CHECK_GT(value, std::numeric_limits<int64_t>::min());
169 return std::numeric_limits<int64_t>::max();
170 }
171
172 CheckedNumeric<int64_t> rv(value);
173 rv -= delta.delta_;
174 if (rv.IsValid())
175 return rv.ValueOrDie();
176 // Negative RHS overflows. Positive RHS underflows.
177 if (delta.delta_ < 0)
178 return std::numeric_limits<int64_t>::max();
179 return std::numeric_limits<int64_t>::min();
180 }
181
182 } // namespace time_internal
183
operator <<(std::ostream & os,TimeDelta time_delta)184 std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
185 return os << time_delta.InSecondsF() << " s";
186 }
187
188 // Time -----------------------------------------------------------------------
189
190 // static
Now()191 Time Time::Now() {
192 return internal::g_time_now_function();
193 }
194
195 // static
NowFromSystemTime()196 Time Time::NowFromSystemTime() {
197 // Just use g_time_now_function because it returns the system time.
198 return internal::g_time_now_from_system_time_function();
199 }
200
201 // static
FromDeltaSinceWindowsEpoch(TimeDelta delta)202 Time Time::FromDeltaSinceWindowsEpoch(TimeDelta delta) {
203 return Time(delta.InMicroseconds());
204 }
205
ToDeltaSinceWindowsEpoch() const206 TimeDelta Time::ToDeltaSinceWindowsEpoch() const {
207 return TimeDelta::FromMicroseconds(us_);
208 }
209
210 // static
FromTimeT(time_t tt)211 Time Time::FromTimeT(time_t tt) {
212 if (tt == 0)
213 return Time(); // Preserve 0 so we can tell it doesn't exist.
214 if (tt == std::numeric_limits<time_t>::max())
215 return Max();
216 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt);
217 }
218
ToTimeT() const219 time_t Time::ToTimeT() const {
220 if (is_null())
221 return 0; // Preserve 0 so we can tell it doesn't exist.
222 if (is_max()) {
223 // Preserve max without offset to prevent overflow.
224 return std::numeric_limits<time_t>::max();
225 }
226 if (std::numeric_limits<int64_t>::max() - kTimeTToMicrosecondsOffset <= us_) {
227 DLOG(WARNING) << "Overflow when converting base::Time with internal " <<
228 "value " << us_ << " to time_t.";
229 return std::numeric_limits<time_t>::max();
230 }
231 return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond;
232 }
233
234 // static
FromDoubleT(double dt)235 Time Time::FromDoubleT(double dt) {
236 if (dt == 0 || std::isnan(dt))
237 return Time(); // Preserve 0 so we can tell it doesn't exist.
238 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt);
239 }
240
ToDoubleT() const241 double Time::ToDoubleT() const {
242 if (is_null())
243 return 0; // Preserve 0 so we can tell it doesn't exist.
244 if (is_max()) {
245 // Preserve max without offset to prevent overflow.
246 return std::numeric_limits<double>::infinity();
247 }
248 return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
249 static_cast<double>(kMicrosecondsPerSecond));
250 }
251
252 #if defined(OS_POSIX)
253 // static
FromTimeSpec(const timespec & ts)254 Time Time::FromTimeSpec(const timespec& ts) {
255 return FromDoubleT(ts.tv_sec +
256 static_cast<double>(ts.tv_nsec) /
257 base::Time::kNanosecondsPerSecond);
258 }
259 #endif
260
261 // static
FromJsTime(double ms_since_epoch)262 Time Time::FromJsTime(double ms_since_epoch) {
263 // The epoch is a valid time, so this constructor doesn't interpret
264 // 0 as the null time.
265 return Time(kTimeTToMicrosecondsOffset) +
266 TimeDelta::FromMillisecondsD(ms_since_epoch);
267 }
268
ToJsTime() const269 double Time::ToJsTime() const {
270 if (is_null()) {
271 // Preserve 0 so the invalid result doesn't depend on the platform.
272 return 0;
273 }
274 if (is_max()) {
275 // Preserve max without offset to prevent overflow.
276 return std::numeric_limits<double>::infinity();
277 }
278 return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
279 kMicrosecondsPerMillisecond);
280 }
281
FromJavaTime(int64_t ms_since_epoch)282 Time Time::FromJavaTime(int64_t ms_since_epoch) {
283 return base::Time::UnixEpoch() +
284 base::TimeDelta::FromMilliseconds(ms_since_epoch);
285 }
286
ToJavaTime() const287 int64_t Time::ToJavaTime() const {
288 if (is_null()) {
289 // Preserve 0 so the invalid result doesn't depend on the platform.
290 return 0;
291 }
292 if (is_max()) {
293 // Preserve max without offset to prevent overflow.
294 return std::numeric_limits<int64_t>::max();
295 }
296 return ((us_ - kTimeTToMicrosecondsOffset) /
297 kMicrosecondsPerMillisecond);
298 }
299
300 // static
UnixEpoch()301 Time Time::UnixEpoch() {
302 Time time;
303 time.us_ = kTimeTToMicrosecondsOffset;
304 return time;
305 }
306
Midnight(bool is_local) const307 Time Time::Midnight(bool is_local) const {
308 Exploded exploded;
309 Explode(is_local, &exploded);
310 exploded.hour = 0;
311 exploded.minute = 0;
312 exploded.second = 0;
313 exploded.millisecond = 0;
314 Time out_time;
315 if (FromExploded(is_local, exploded, &out_time))
316 return out_time;
317 // This function must not fail.
318 NOTREACHED();
319 return Time();
320 }
321
322 #if !defined(MOZ_SANDBOX)
323 // static
FromStringInternal(const char * time_string,bool is_local,Time * parsed_time)324 bool Time::FromStringInternal(const char* time_string,
325 bool is_local,
326 Time* parsed_time) {
327 DCHECK((time_string != nullptr) && (parsed_time != nullptr));
328
329 if (time_string[0] == '\0')
330 return false;
331
332 PRTime result_time = 0;
333 PRStatus result = PR_ParseTimeString(time_string,
334 is_local ? PR_FALSE : PR_TRUE,
335 &result_time);
336 if (PR_SUCCESS != result)
337 return false;
338
339 result_time += kTimeTToMicrosecondsOffset;
340 *parsed_time = Time(result_time);
341 return true;
342 }
343 #endif
344
345 // static
ExplodedMostlyEquals(const Exploded & lhs,const Exploded & rhs)346 bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) {
347 return lhs.year == rhs.year && lhs.month == rhs.month &&
348 lhs.day_of_month == rhs.day_of_month && lhs.hour == rhs.hour &&
349 lhs.minute == rhs.minute && lhs.second == rhs.second &&
350 lhs.millisecond == rhs.millisecond;
351 }
352
operator <<(std::ostream & os,Time time)353 std::ostream& operator<<(std::ostream& os, Time time) {
354 Time::Exploded exploded;
355 time.UTCExplode(&exploded);
356 // Use StringPrintf because iostreams formatting is painful.
357 return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC",
358 exploded.year,
359 exploded.month,
360 exploded.day_of_month,
361 exploded.hour,
362 exploded.minute,
363 exploded.second,
364 exploded.millisecond);
365 }
366
367 // TimeTicks ------------------------------------------------------------------
368
369 // static
Now()370 TimeTicks TimeTicks::Now() {
371 return internal::g_time_ticks_now_function();
372 }
373
374 // static
UnixEpoch()375 TimeTicks TimeTicks::UnixEpoch() {
376 static const base::NoDestructor<base::TimeTicks> epoch([]() {
377 return subtle::TimeTicksNowIgnoringOverride() -
378 (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch());
379 }());
380 return *epoch;
381 }
382
SnappedToNextTick(TimeTicks tick_phase,TimeDelta tick_interval) const383 TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
384 TimeDelta tick_interval) const {
385 // |interval_offset| is the offset from |this| to the next multiple of
386 // |tick_interval| after |tick_phase|, possibly negative if in the past.
387 TimeDelta interval_offset = (tick_phase - *this) % tick_interval;
388 // If |this| is exactly on the interval (i.e. offset==0), don't adjust.
389 // Otherwise, if |tick_phase| was in the past, adjust forward to the next
390 // tick after |this|.
391 if (!interval_offset.is_zero() && tick_phase < *this)
392 interval_offset += tick_interval;
393 return *this + interval_offset;
394 }
395
operator <<(std::ostream & os,TimeTicks time_ticks)396 std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) {
397 // This function formats a TimeTicks object as "bogo-microseconds".
398 // The origin and granularity of the count are platform-specific, and may very
399 // from run to run. Although bogo-microseconds usually roughly correspond to
400 // real microseconds, the only real guarantee is that the number never goes
401 // down during a single run.
402 const TimeDelta as_time_delta = time_ticks - TimeTicks();
403 return os << as_time_delta.InMicroseconds() << " bogo-microseconds";
404 }
405
406 // ThreadTicks ----------------------------------------------------------------
407
408 // static
Now()409 ThreadTicks ThreadTicks::Now() {
410 return internal::g_thread_ticks_now_function();
411 }
412
operator <<(std::ostream & os,ThreadTicks thread_ticks)413 std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
414 const TimeDelta as_time_delta = thread_ticks - ThreadTicks();
415 return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
416 }
417
418 // Time::Exploded -------------------------------------------------------------
419
is_in_range(int value,int lo,int hi)420 inline bool is_in_range(int value, int lo, int hi) {
421 return lo <= value && value <= hi;
422 }
423
HasValidValues() const424 bool Time::Exploded::HasValidValues() const {
425 return is_in_range(month, 1, 12) &&
426 is_in_range(day_of_week, 0, 6) &&
427 is_in_range(day_of_month, 1, 31) &&
428 is_in_range(hour, 0, 23) &&
429 is_in_range(minute, 0, 59) &&
430 is_in_range(second, 0, 60) &&
431 is_in_range(millisecond, 0, 999);
432 }
433
434 } // namespace base
435