• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 <atomic>
8 #include <cmath>
9 #include <limits>
10 #include <ostream>
11 #include <tuple>
12 #include <utility>
13 
14 #include "base/check.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/third_party/nspr/prtime.h"
17 #include "base/time/time_override.h"
18 #include "build/build_config.h"
19 #include "third_party/abseil-cpp/absl/types/optional.h"
20 
21 namespace base {
22 
23 namespace {
24 
25 const char kWeekdayName[7][4] = {"Sun", "Mon", "Tue", "Wed",
26                                  "Thu", "Fri", "Sat"};
27 
28 const char kMonthName[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
29                                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
30 
31 TimeTicks g_shared_time_ticks_at_unix_epoch;
32 
33 }  // namespace
34 
35 namespace internal {
36 
37 std::atomic<TimeNowFunction> g_time_now_function{
38     &subtle::TimeNowIgnoringOverride};
39 
40 std::atomic<TimeNowFunction> g_time_now_from_system_time_function{
41     &subtle::TimeNowFromSystemTimeIgnoringOverride};
42 
43 std::atomic<TimeTicksNowFunction> g_time_ticks_now_function{
44     &subtle::TimeTicksNowIgnoringOverride};
45 
46 std::atomic<ThreadTicksNowFunction> g_thread_ticks_now_function{
47     &subtle::ThreadTicksNowIgnoringOverride};
48 
49 }  // namespace internal
50 
51 // TimeDelta ------------------------------------------------------------------
52 
InDays() const53 int TimeDelta::InDays() const {
54   if (!is_inf())
55     return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
56   return (delta_ < 0) ? std::numeric_limits<int>::min()
57                       : std::numeric_limits<int>::max();
58 }
59 
InDaysFloored() const60 int TimeDelta::InDaysFloored() const {
61   if (!is_inf()) {
62     const int result = delta_ / Time::kMicrosecondsPerDay;
63     // Convert |result| from truncating to flooring.
64     return (result * Time::kMicrosecondsPerDay > delta_) ? (result - 1)
65                                                          : result;
66   }
67   return (delta_ < 0) ? std::numeric_limits<int>::min()
68                       : std::numeric_limits<int>::max();
69 }
70 
InMillisecondsF() const71 double TimeDelta::InMillisecondsF() const {
72   if (!is_inf())
73     return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
74   return (delta_ < 0) ? -std::numeric_limits<double>::infinity()
75                       : std::numeric_limits<double>::infinity();
76 }
77 
InMilliseconds() const78 int64_t TimeDelta::InMilliseconds() const {
79   if (!is_inf())
80     return delta_ / Time::kMicrosecondsPerMillisecond;
81   return (delta_ < 0) ? std::numeric_limits<int64_t>::min()
82                       : std::numeric_limits<int64_t>::max();
83 }
84 
InMillisecondsRoundedUp() const85 int64_t TimeDelta::InMillisecondsRoundedUp() const {
86   if (!is_inf()) {
87     const int64_t result = delta_ / Time::kMicrosecondsPerMillisecond;
88     // Convert |result| from truncating to ceiling.
89     return (delta_ > result * Time::kMicrosecondsPerMillisecond) ? (result + 1)
90                                                                  : result;
91   }
92   return delta_;
93 }
94 
InMicrosecondsF() const95 double TimeDelta::InMicrosecondsF() const {
96   if (!is_inf())
97     return static_cast<double>(delta_);
98   return (delta_ < 0) ? -std::numeric_limits<double>::infinity()
99                       : std::numeric_limits<double>::infinity();
100 }
101 
CeilToMultiple(TimeDelta interval) const102 TimeDelta TimeDelta::CeilToMultiple(TimeDelta interval) const {
103   if (is_inf() || interval.is_zero())
104     return *this;
105   const TimeDelta remainder = *this % interval;
106   if (delta_ < 0)
107     return *this - remainder;
108   return remainder.is_zero() ? *this
109                              : (*this - remainder + interval.magnitude());
110 }
111 
FloorToMultiple(TimeDelta interval) const112 TimeDelta TimeDelta::FloorToMultiple(TimeDelta interval) const {
113   if (is_inf() || interval.is_zero())
114     return *this;
115   const TimeDelta remainder = *this % interval;
116   if (delta_ < 0) {
117     return remainder.is_zero() ? *this
118                                : (*this - remainder - interval.magnitude());
119   }
120   return *this - remainder;
121 }
122 
RoundToMultiple(TimeDelta interval) const123 TimeDelta TimeDelta::RoundToMultiple(TimeDelta interval) const {
124   if (is_inf() || interval.is_zero())
125     return *this;
126   if (interval.is_inf())
127     return TimeDelta();
128   const TimeDelta half = interval.magnitude() / 2;
129   return (delta_ < 0) ? (*this - half).CeilToMultiple(interval)
130                       : (*this + half).FloorToMultiple(interval);
131 }
132 
operator <<(std::ostream & os,TimeDelta time_delta)133 std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
134   return os << time_delta.InSecondsF() << " s";
135 }
136 
137 // Time -----------------------------------------------------------------------
138 
139 // static
Now()140 Time Time::Now() {
141   return internal::g_time_now_function.load(std::memory_order_relaxed)();
142 }
143 
144 // static
NowFromSystemTime()145 Time Time::NowFromSystemTime() {
146   // Just use g_time_now_function because it returns the system time.
147   return internal::g_time_now_from_system_time_function.load(
148       std::memory_order_relaxed)();
149 }
150 
ToTimeT() const151 time_t Time::ToTimeT() const {
152   if (is_null())
153     return 0;  // Preserve 0 so we can tell it doesn't exist.
154   if (!is_inf() && ((std::numeric_limits<int64_t>::max() -
155                      kTimeTToMicrosecondsOffset) > us_)) {
156     return static_cast<time_t>((*this - UnixEpoch()).InSeconds());
157   }
158   return (us_ < 0) ? std::numeric_limits<time_t>::min()
159                    : std::numeric_limits<time_t>::max();
160 }
161 
162 // static
FromDoubleT(double dt)163 Time Time::FromDoubleT(double dt) {
164   // Preserve 0 so we can tell it doesn't exist.
165   return (dt == 0 || std::isnan(dt)) ? Time() : (UnixEpoch() + Seconds(dt));
166 }
167 
ToDoubleT() const168 double Time::ToDoubleT() const {
169   if (is_null())
170     return 0;  // Preserve 0 so we can tell it doesn't exist.
171   if (!is_inf())
172     return (*this - UnixEpoch()).InSecondsF();
173   return (us_ < 0) ? -std::numeric_limits<double>::infinity()
174                    : std::numeric_limits<double>::infinity();
175 }
176 
177 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
178 // static
FromTimeSpec(const timespec & ts)179 Time Time::FromTimeSpec(const timespec& ts) {
180   return FromDoubleT(ts.tv_sec +
181                      static_cast<double>(ts.tv_nsec) / kNanosecondsPerSecond);
182 }
183 #endif
184 
185 // static
FromJsTime(double ms_since_epoch)186 Time Time::FromJsTime(double ms_since_epoch) {
187   // The epoch is a valid time, so this constructor doesn't interpret 0 as the
188   // null time.
189   return UnixEpoch() + Milliseconds(ms_since_epoch);
190 }
191 
ToJsTime() const192 double Time::ToJsTime() const {
193   // Preserve 0 so the invalid result doesn't depend on the platform.
194   return is_null() ? 0 : ToJsTimeIgnoringNull();
195 }
196 
ToJsTimeIgnoringNull() const197 double Time::ToJsTimeIgnoringNull() const {
198   // Preserve max and min without offset to prevent over/underflow.
199   if (!is_inf())
200     return (*this - UnixEpoch()).InMillisecondsF();
201   return (us_ < 0) ? -std::numeric_limits<double>::infinity()
202                    : std::numeric_limits<double>::infinity();
203 }
204 
FromJavaTime(int64_t ms_since_epoch)205 Time Time::FromJavaTime(int64_t ms_since_epoch) {
206   return UnixEpoch() + Milliseconds(ms_since_epoch);
207 }
208 
ToJavaTime() const209 int64_t Time::ToJavaTime() const {
210   // Preserve 0 so the invalid result doesn't depend on the platform.
211   if (is_null())
212     return 0;
213   if (!is_inf())
214     return (*this - UnixEpoch()).InMilliseconds();
215   return (us_ < 0) ? std::numeric_limits<int64_t>::min()
216                    : std::numeric_limits<int64_t>::max();
217 }
218 
Midnight(bool is_local) const219 Time Time::Midnight(bool is_local) const {
220   Exploded exploded;
221   Explode(is_local, &exploded);
222   exploded.hour = 0;
223   exploded.minute = 0;
224   exploded.second = 0;
225   exploded.millisecond = 0;
226   Time out_time;
227   if (FromExploded(is_local, exploded, &out_time))
228     return out_time;
229 
230   // Reaching here means 00:00:00am of the current day does not exist (due to
231   // Daylight Saving Time in some countries where clocks are shifted at
232   // midnight). In this case, midnight should be defined as 01:00:00am.
233   DCHECK(is_local);
234   exploded.hour = 1;
235   [[maybe_unused]] const bool result =
236       FromExploded(is_local, exploded, &out_time);
237 #if BUILDFLAG(IS_CHROMEOS_ASH) && defined(ARCH_CPU_ARM_FAMILY)
238   // TODO(crbug.com/1263873): DCHECKs have limited coverage during automated
239   // testing on CrOS and this check failed when tested on an experimental
240   // builder. Testing for ARCH_CPU_ARM_FAMILY prevents regressing coverage on
241   // x86_64, which is already enabled. See go/chrome-dcheck-on-cros or
242   // http://crbug.com/1113456 for more details.
243 #else
244   DCHECK(result);  // This function must not fail.
245 #endif
246   return out_time;
247 }
248 
249 // static
FromStringInternal(const char * time_string,bool is_local,Time * parsed_time)250 bool Time::FromStringInternal(const char* time_string,
251                               bool is_local,
252                               Time* parsed_time) {
253   DCHECK(time_string);
254   DCHECK(parsed_time);
255 
256   if (time_string[0] == '\0')
257     return false;
258 
259   PRTime result_time = 0;
260   PRStatus result = PR_ParseTimeString(time_string,
261                                        is_local ? PR_FALSE : PR_TRUE,
262                                        &result_time);
263   if (result != PR_SUCCESS)
264     return false;
265 
266   *parsed_time = UnixEpoch() + Microseconds(result_time);
267   return true;
268 }
269 
270 // static
ExplodedMostlyEquals(const Exploded & lhs,const Exploded & rhs)271 bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) {
272   return std::tie(lhs.year, lhs.month, lhs.day_of_month, lhs.hour, lhs.minute,
273                   lhs.second, lhs.millisecond) ==
274          std::tie(rhs.year, rhs.month, rhs.day_of_month, rhs.hour, rhs.minute,
275                   rhs.second, rhs.millisecond);
276 }
277 
278 // static
FromMillisecondsSinceUnixEpoch(int64_t unix_milliseconds,Time * time)279 bool Time::FromMillisecondsSinceUnixEpoch(int64_t unix_milliseconds,
280                                           Time* time) {
281   // Adjust the provided time from milliseconds since the Unix epoch (1970) to
282   // microseconds since the Windows epoch (1601), avoiding overflows.
283   CheckedNumeric<int64_t> checked_microseconds_win_epoch = unix_milliseconds;
284   checked_microseconds_win_epoch *= kMicrosecondsPerMillisecond;
285   checked_microseconds_win_epoch += kTimeTToMicrosecondsOffset;
286   *time = Time(checked_microseconds_win_epoch.ValueOrDefault(0));
287   return checked_microseconds_win_epoch.IsValid();
288 }
289 
ToRoundedDownMillisecondsSinceUnixEpoch() const290 int64_t Time::ToRoundedDownMillisecondsSinceUnixEpoch() const {
291   constexpr int64_t kEpochOffsetMillis =
292       kTimeTToMicrosecondsOffset / kMicrosecondsPerMillisecond;
293   static_assert(kTimeTToMicrosecondsOffset % kMicrosecondsPerMillisecond == 0,
294                 "assumption: no epoch offset sub-milliseconds");
295 
296   // Compute the milliseconds since UNIX epoch without the possibility of
297   // under/overflow. Round the result towards -infinity.
298   //
299   // If |us_| is negative and includes fractions of a millisecond, subtract one
300   // more to effect the round towards -infinity. C-style integer truncation
301   // takes care of all other cases.
302   const int64_t millis = us_ / kMicrosecondsPerMillisecond;
303   const int64_t submillis = us_ % kMicrosecondsPerMillisecond;
304   return millis - kEpochOffsetMillis - (submillis < 0);
305 }
306 
operator <<(std::ostream & os,Time time)307 std::ostream& operator<<(std::ostream& os, Time time) {
308   Time::Exploded exploded;
309   time.UTCExplode(&exploded);
310   // Use StringPrintf because iostreams formatting is painful.
311   return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC",
312                             exploded.year,
313                             exploded.month,
314                             exploded.day_of_month,
315                             exploded.hour,
316                             exploded.minute,
317                             exploded.second,
318                             exploded.millisecond);
319 }
320 
321 // TimeTicks ------------------------------------------------------------------
322 
323 // static
Now()324 TimeTicks TimeTicks::Now() {
325   return internal::g_time_ticks_now_function.load(std::memory_order_relaxed)();
326 }
327 
328 // static
329 // This method should be called once at process start and before
330 // TimeTicks::UnixEpoch is accessed. It is intended to make the offset between
331 // unix time and monotonic time consistent across processes.
SetSharedUnixEpoch(TimeTicks ticks_at_epoch)332 void TimeTicks::SetSharedUnixEpoch(TimeTicks ticks_at_epoch) {
333   DCHECK(g_shared_time_ticks_at_unix_epoch.is_null());
334   g_shared_time_ticks_at_unix_epoch = ticks_at_epoch;
335 }
336 
337 // static
UnixEpoch()338 TimeTicks TimeTicks::UnixEpoch() {
339   struct StaticUnixEpoch {
340     StaticUnixEpoch()
341         : epoch(
342               g_shared_time_ticks_at_unix_epoch.is_null()
343                   ? subtle::TimeTicksNowIgnoringOverride() -
344                         (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch())
345                   : g_shared_time_ticks_at_unix_epoch) {
346       // Prevent future usage of `g_shared_time_ticks_at_unix_epoch`.
347       g_shared_time_ticks_at_unix_epoch = TimeTicks::Max();
348     }
349 
350     const TimeTicks epoch;
351   };
352 
353   static StaticUnixEpoch static_epoch;
354   return static_epoch.epoch;
355 }
356 
SnappedToNextTick(TimeTicks tick_phase,TimeDelta tick_interval) const357 TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
358                                        TimeDelta tick_interval) const {
359   // |interval_offset| is the offset from |this| to the next multiple of
360   // |tick_interval| after |tick_phase|, possibly negative if in the past.
361   TimeDelta interval_offset = (tick_phase - *this) % tick_interval;
362   // If |this| is exactly on the interval (i.e. offset==0), don't adjust.
363   // Otherwise, if |tick_phase| was in the past, adjust forward to the next
364   // tick after |this|.
365   if (!interval_offset.is_zero() && tick_phase < *this)
366     interval_offset += tick_interval;
367   return *this + interval_offset;
368 }
369 
operator <<(std::ostream & os,TimeTicks time_ticks)370 std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) {
371   // This function formats a TimeTicks object as "bogo-microseconds".
372   // The origin and granularity of the count are platform-specific, and may very
373   // from run to run. Although bogo-microseconds usually roughly correspond to
374   // real microseconds, the only real guarantee is that the number never goes
375   // down during a single run.
376   const TimeDelta as_time_delta = time_ticks - TimeTicks();
377   return os << as_time_delta.InMicroseconds() << " bogo-microseconds";
378 }
379 
380 // ThreadTicks ----------------------------------------------------------------
381 
382 // static
Now()383 ThreadTicks ThreadTicks::Now() {
384   return internal::g_thread_ticks_now_function.load(
385       std::memory_order_relaxed)();
386 }
387 
operator <<(std::ostream & os,ThreadTicks thread_ticks)388 std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
389   const TimeDelta as_time_delta = thread_ticks - ThreadTicks();
390   return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
391 }
392 
393 // Time::Exploded -------------------------------------------------------------
394 
HasValidValues() const395 bool Time::Exploded::HasValidValues() const {
396   // clang-format off
397   return (1 <= month) && (month <= 12) &&
398          (0 <= day_of_week) && (day_of_week <= 6) &&
399          (1 <= day_of_month) && (day_of_month <= 31) &&
400          (0 <= hour) && (hour <= 23) &&
401          (0 <= minute) && (minute <= 59) &&
402          (0 <= second) && (second <= 60) &&
403          (0 <= millisecond) && (millisecond <= 999);
404   // clang-format on
405 }
406 
TimeFormatHTTP(base::Time time)407 std::string TimeFormatHTTP(base::Time time) {
408   base::Time::Exploded exploded;
409   time.UTCExplode(&exploded);
410   return base::StringPrintf(
411       "%s, %02d %s %04d %02d:%02d:%02d GMT", kWeekdayName[exploded.day_of_week],
412       exploded.day_of_month, kMonthName[exploded.month - 1], exploded.year,
413       exploded.hour, exploded.minute, exploded.second);
414 }
415 
416 }  // namespace base
417