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