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