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