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