• 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 <optional>
11 #include <ostream>
12 #include <tuple>
13 #include <utility>
14 
15 #include "base/check.h"
16 #include "base/format_macros.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/third_party/nspr/prtime.h"
19 #include "base/time/time_override.h"
20 #include "build/build_config.h"
21 
22 namespace base {
23 
24 namespace {
25 
26 TimeTicks g_shared_time_ticks_at_unix_epoch;
27 
28 }  // namespace
29 
30 namespace internal {
31 
32 std::atomic<TimeNowFunction> g_time_now_function{
33     &subtle::TimeNowIgnoringOverride};
34 
35 std::atomic<TimeNowFunction> g_time_now_from_system_time_function{
36     &subtle::TimeNowFromSystemTimeIgnoringOverride};
37 
38 std::atomic<TimeTicksNowFunction> g_time_ticks_now_function{
39     &subtle::TimeTicksNowIgnoringOverride};
40 
41 std::atomic<TimeTicksLowResolutionNowFunction>
42     g_time_ticks_low_resolution_now_function{
43         &subtle::TimeTicksLowResolutionNowIgnoringOverride};
44 
45 std::atomic<LiveTicksNowFunction> g_live_ticks_now_function{
46     &subtle::LiveTicksNowIgnoringOverride};
47 
48 std::atomic<ThreadTicksNowFunction> g_thread_ticks_now_function{
49     &subtle::ThreadTicksNowIgnoringOverride};
50 
51 }  // namespace internal
52 
53 // TimeDelta ------------------------------------------------------------------
54 
CeilToMultiple(TimeDelta interval) const55 TimeDelta TimeDelta::CeilToMultiple(TimeDelta interval) const {
56   if (is_inf() || interval.is_zero())
57     return *this;
58   const TimeDelta remainder = *this % interval;
59   if (delta_ < 0)
60     return *this - remainder;
61   return remainder.is_zero() ? *this
62                              : (*this - remainder + interval.magnitude());
63 }
64 
FloorToMultiple(TimeDelta interval) const65 TimeDelta TimeDelta::FloorToMultiple(TimeDelta interval) const {
66   if (is_inf() || interval.is_zero())
67     return *this;
68   const TimeDelta remainder = *this % interval;
69   if (delta_ < 0) {
70     return remainder.is_zero() ? *this
71                                : (*this - remainder - interval.magnitude());
72   }
73   return *this - remainder;
74 }
75 
RoundToMultiple(TimeDelta interval) const76 TimeDelta TimeDelta::RoundToMultiple(TimeDelta interval) const {
77   if (is_inf() || interval.is_zero())
78     return *this;
79   if (interval.is_inf())
80     return TimeDelta();
81   const TimeDelta half = interval.magnitude() / 2;
82   return (delta_ < 0) ? (*this - half).CeilToMultiple(interval)
83                       : (*this + half).FloorToMultiple(interval);
84 }
85 
operator <<(std::ostream & os,TimeDelta time_delta)86 std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
87   return os << time_delta.InSecondsF() << " s";
88 }
89 
90 // Time -----------------------------------------------------------------------
91 
92 // static
Now()93 Time Time::Now() {
94   return internal::g_time_now_function.load(std::memory_order_relaxed)();
95 }
96 
97 // static
NowFromSystemTime()98 Time Time::NowFromSystemTime() {
99   // Just use g_time_now_function because it returns the system time.
100   return internal::g_time_now_from_system_time_function.load(
101       std::memory_order_relaxed)();
102 }
103 
Midnight(bool is_local) const104 Time Time::Midnight(bool is_local) const {
105   Exploded exploded;
106   Explode(is_local, &exploded);
107   exploded.hour = 0;
108   exploded.minute = 0;
109   exploded.second = 0;
110   exploded.millisecond = 0;
111   Time out_time;
112   if (FromExploded(is_local, exploded, &out_time))
113     return out_time;
114 
115   // Reaching here means 00:00:00am of the current day does not exist (due to
116   // Daylight Saving Time in some countries where clocks are shifted at
117   // midnight). In this case, midnight should be defined as 01:00:00am.
118   DCHECK(is_local);
119   exploded.hour = 1;
120   [[maybe_unused]] const bool result =
121       FromExploded(is_local, exploded, &out_time);
122 #if BUILDFLAG(IS_CHROMEOS_ASH) && defined(ARCH_CPU_ARM_FAMILY)
123   // TODO(crbug.com/40800460): DCHECKs have limited coverage during automated
124   // testing on CrOS and this check failed when tested on an experimental
125   // builder. Testing for ARCH_CPU_ARM_FAMILY prevents regressing coverage on
126   // x86_64, which is already enabled. See go/chrome-dcheck-on-cros or
127   // http://crbug.com/1113456 for more details.
128 #else
129   DCHECK(result);  // This function must not fail.
130 #endif
131   return out_time;
132 }
133 
134 // static
FromStringInternal(const char * time_string,bool is_local,Time * parsed_time)135 bool Time::FromStringInternal(const char* time_string,
136                               bool is_local,
137                               Time* parsed_time) {
138   DCHECK(time_string);
139   DCHECK(parsed_time);
140 
141   if (time_string[0] == '\0')
142     return false;
143 
144   PRTime result_time = 0;
145   PRStatus result = PR_ParseTimeString(time_string,
146                                        is_local ? PR_FALSE : PR_TRUE,
147                                        &result_time);
148   if (result != PR_SUCCESS)
149     return false;
150 
151   *parsed_time = UnixEpoch() + Microseconds(result_time);
152   return true;
153 }
154 
155 // static
ExplodedMostlyEquals(const Exploded & lhs,const Exploded & rhs)156 bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) {
157   return std::tie(lhs.year, lhs.month, lhs.day_of_month, lhs.hour, lhs.minute,
158                   lhs.second, lhs.millisecond) ==
159          std::tie(rhs.year, rhs.month, rhs.day_of_month, rhs.hour, rhs.minute,
160                   rhs.second, rhs.millisecond);
161 }
162 
163 // static
FromMillisecondsSinceUnixEpoch(int64_t unix_milliseconds,Time * time)164 bool Time::FromMillisecondsSinceUnixEpoch(int64_t unix_milliseconds,
165                                           Time* time) {
166   // Adjust the provided time from milliseconds since the Unix epoch (1970) to
167   // microseconds since the Windows epoch (1601), avoiding overflows.
168   CheckedNumeric<int64_t> checked_microseconds_win_epoch = unix_milliseconds;
169   checked_microseconds_win_epoch *= kMicrosecondsPerMillisecond;
170   checked_microseconds_win_epoch += kTimeTToMicrosecondsOffset;
171   *time = Time(checked_microseconds_win_epoch.ValueOrDefault(0));
172   return checked_microseconds_win_epoch.IsValid();
173 }
174 
ToRoundedDownMillisecondsSinceUnixEpoch() const175 int64_t Time::ToRoundedDownMillisecondsSinceUnixEpoch() const {
176   constexpr int64_t kEpochOffsetMillis =
177       kTimeTToMicrosecondsOffset / kMicrosecondsPerMillisecond;
178   static_assert(kTimeTToMicrosecondsOffset % kMicrosecondsPerMillisecond == 0,
179                 "assumption: no epoch offset sub-milliseconds");
180 
181   // Compute the milliseconds since UNIX epoch without the possibility of
182   // under/overflow. Round the result towards -infinity.
183   //
184   // If |us_| is negative and includes fractions of a millisecond, subtract one
185   // more to effect the round towards -infinity. C-style integer truncation
186   // takes care of all other cases.
187   const int64_t millis = us_ / kMicrosecondsPerMillisecond;
188   const int64_t submillis = us_ % kMicrosecondsPerMillisecond;
189   return millis - kEpochOffsetMillis - (submillis < 0);
190 }
191 
operator <<(std::ostream & os,Time time)192 std::ostream& operator<<(std::ostream& os, Time time) {
193   Time::Exploded exploded;
194   time.UTCExplode(&exploded);
195   // Can't call `UnlocalizedTimeFormatWithPattern()`/`TimeFormatAsIso8601()`
196   // since `//base` can't depend on `//base:i18n`.
197   //
198   // TODO(pkasting): Consider whether `operator<<()` should move to
199   // `base/i18n/time_formatting.h` -- would let us implement in terms of
200   // existing time formatting, but might be confusing.
201   return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%06" PRId64 " UTC",
202                             exploded.year, exploded.month,
203                             exploded.day_of_month, exploded.hour,
204                             exploded.minute, exploded.second,
205                             time.ToDeltaSinceWindowsEpoch().InMicroseconds() %
206                                 Time::kMicrosecondsPerSecond);
207 }
208 
209 // TimeTicks ------------------------------------------------------------------
210 
211 // static
Now()212 TimeTicks TimeTicks::Now() {
213   return internal::g_time_ticks_now_function.load(std::memory_order_relaxed)();
214 }
215 
216 // static
LowResolutionNow()217 TimeTicks TimeTicks::LowResolutionNow() {
218   return internal::g_time_ticks_low_resolution_now_function.load(
219       std::memory_order_relaxed)();
220 }
221 
222 // static
223 // This method should be called once at process start and before
224 // TimeTicks::UnixEpoch is accessed. It is intended to make the offset between
225 // unix time and monotonic time consistent across processes.
SetSharedUnixEpoch(TimeTicks ticks_at_epoch)226 void TimeTicks::SetSharedUnixEpoch(TimeTicks ticks_at_epoch) {
227   DCHECK(g_shared_time_ticks_at_unix_epoch.is_null());
228   g_shared_time_ticks_at_unix_epoch = ticks_at_epoch;
229 }
230 
231 // static
UnixEpoch()232 TimeTicks TimeTicks::UnixEpoch() {
233   struct StaticUnixEpoch {
234     StaticUnixEpoch()
235         : epoch(
236               g_shared_time_ticks_at_unix_epoch.is_null()
237                   ? subtle::TimeTicksNowIgnoringOverride() -
238                         (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch())
239                   : g_shared_time_ticks_at_unix_epoch) {
240       // Prevent future usage of `g_shared_time_ticks_at_unix_epoch`.
241       g_shared_time_ticks_at_unix_epoch = TimeTicks::Max();
242     }
243 
244     const TimeTicks epoch;
245   };
246 
247   static StaticUnixEpoch static_epoch;
248   return static_epoch.epoch;
249 }
250 
SnappedToNextTick(TimeTicks tick_phase,TimeDelta tick_interval) const251 TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
252                                        TimeDelta tick_interval) const {
253   // |interval_offset| is the offset from |this| to the next multiple of
254   // |tick_interval| after |tick_phase|, possibly negative if in the past.
255   TimeDelta interval_offset = (tick_phase - *this) % tick_interval;
256   // If |this| is exactly on the interval (i.e. offset==0), don't adjust.
257   // Otherwise, if |tick_phase| was in the past, adjust forward to the next
258   // tick after |this|.
259   if (!interval_offset.is_zero() && tick_phase < *this)
260     interval_offset += tick_interval;
261   return *this + interval_offset;
262 }
263 
operator <<(std::ostream & os,TimeTicks time_ticks)264 std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) {
265   // This function formats a TimeTicks object as "bogo-microseconds".
266   // The origin and granularity of the count are platform-specific, and may very
267   // from run to run. Although bogo-microseconds usually roughly correspond to
268   // real microseconds, the only real guarantee is that the number never goes
269   // down during a single run.
270   const TimeDelta as_time_delta = time_ticks - TimeTicks();
271   return os << as_time_delta.InMicroseconds() << " bogo-microseconds";
272 }
273 
274 // LiveTicks ------------------------------------------------------------------
275 
276 // static
Now()277 LiveTicks LiveTicks::Now() {
278   return internal::g_live_ticks_now_function.load(std::memory_order_relaxed)();
279 }
280 
281 #if !BUILDFLAG(IS_WIN)
282 namespace subtle {
LiveTicksNowIgnoringOverride()283 LiveTicks LiveTicksNowIgnoringOverride() {
284   // On non-windows platforms LiveTicks is equivalent to TimeTicks already.
285   // Subtract the empty `TimeTicks` from `TimeTicks::Now()` to get a `TimeDelta`
286   // that can be added to the empty `LiveTicks`.
287   return LiveTicks() + (TimeTicks::Now() - TimeTicks());
288 }
289 }  // namespace subtle
290 
291 #endif
292 
operator <<(std::ostream & os,LiveTicks live_ticks)293 std::ostream& operator<<(std::ostream& os, LiveTicks live_ticks) {
294   const TimeDelta as_time_delta = live_ticks - LiveTicks();
295   return os << as_time_delta.InMicroseconds() << " bogo-live-microseconds";
296 }
297 
298 // ThreadTicks ----------------------------------------------------------------
299 
300 // static
Now()301 ThreadTicks ThreadTicks::Now() {
302   return internal::g_thread_ticks_now_function.load(
303       std::memory_order_relaxed)();
304 }
305 
operator <<(std::ostream & os,ThreadTicks thread_ticks)306 std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
307   const TimeDelta as_time_delta = thread_ticks - ThreadTicks();
308   return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
309 }
310 
311 // Time::Exploded -------------------------------------------------------------
312 
HasValidValues() const313 bool Time::Exploded::HasValidValues() const {
314   // clang-format off
315   return (1 <= month) && (month <= 12) &&
316          (0 <= day_of_week) && (day_of_week <= 6) &&
317          (1 <= day_of_month) && (day_of_month <= 31) &&
318          (0 <= hour) && (hour <= 23) &&
319          (0 <= minute) && (minute <= 59) &&
320          (0 <= second) && (second <= 60) &&
321          (0 <= millisecond) && (millisecond <= 999);
322   // clang-format on
323 }
324 
325 }  // namespace base
326