1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 <cmath> 8 #include <ios> 9 #include <limits> 10 #include <ostream> 11 #include <sstream> 12 13 #include "base/logging.h" 14 #include "base/macros.h" 15 #include "base/no_destructor.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 21 namespace base { 22 23 namespace internal { 24 25 TimeNowFunction g_time_now_function = &subtle::TimeNowIgnoringOverride; 26 27 TimeNowFunction g_time_now_from_system_time_function = 28 &subtle::TimeNowFromSystemTimeIgnoringOverride; 29 30 TimeTicksNowFunction g_time_ticks_now_function = 31 &subtle::TimeTicksNowIgnoringOverride; 32 33 ThreadTicksNowFunction g_thread_ticks_now_function = 34 &subtle::ThreadTicksNowIgnoringOverride; 35 36 } // namespace internal 37 38 // TimeDelta ------------------------------------------------------------------ 39 40 int TimeDelta::InDays() const { 41 if (is_max()) { 42 // Preserve max to prevent overflow. 43 return std::numeric_limits<int>::max(); 44 } 45 return static_cast<int>(delta_ / Time::kMicrosecondsPerDay); 46 } 47 48 int TimeDelta::InDaysFloored() const { 49 if (is_max()) { 50 // Preserve max to prevent overflow. 51 return std::numeric_limits<int>::max(); 52 } 53 int result = delta_ / Time::kMicrosecondsPerDay; 54 int64_t remainder = delta_ - (result * Time::kMicrosecondsPerDay); 55 if (remainder < 0) { 56 --result; // Use floor(), not trunc() rounding behavior. 57 } 58 return result; 59 } 60 61 int TimeDelta::InHours() const { 62 if (is_max()) { 63 // Preserve max to prevent overflow. 64 return std::numeric_limits<int>::max(); 65 } 66 return static_cast<int>(delta_ / Time::kMicrosecondsPerHour); 67 } 68 69 int TimeDelta::InMinutes() const { 70 if (is_max()) { 71 // Preserve max to prevent overflow. 72 return std::numeric_limits<int>::max(); 73 } 74 return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute); 75 } 76 77 double TimeDelta::InSecondsF() const { 78 if (is_max()) { 79 // Preserve max to prevent overflow. 80 return std::numeric_limits<double>::infinity(); 81 } 82 return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond; 83 } 84 85 int64_t TimeDelta::InSeconds() const { 86 if (is_max()) { 87 // Preserve max to prevent overflow. 88 return std::numeric_limits<int64_t>::max(); 89 } 90 return delta_ / Time::kMicrosecondsPerSecond; 91 } 92 93 double TimeDelta::InMillisecondsF() const { 94 if (is_max()) { 95 // Preserve max to prevent overflow. 96 return std::numeric_limits<double>::infinity(); 97 } 98 return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond; 99 } 100 101 int64_t TimeDelta::InMilliseconds() const { 102 if (is_max()) { 103 // Preserve max to prevent overflow. 104 return std::numeric_limits<int64_t>::max(); 105 } 106 return delta_ / Time::kMicrosecondsPerMillisecond; 107 } 108 109 int64_t TimeDelta::InMillisecondsRoundedUp() const { 110 if (is_max()) { 111 // Preserve max to prevent overflow. 112 return std::numeric_limits<int64_t>::max(); 113 } 114 int64_t result = delta_ / Time::kMicrosecondsPerMillisecond; 115 int64_t remainder = delta_ - (result * Time::kMicrosecondsPerMillisecond); 116 if (remainder > 0) { 117 ++result; // Use ceil(), not trunc() rounding behavior. 118 } 119 return result; 120 } 121 122 int64_t TimeDelta::InMicroseconds() const { 123 if (is_max()) { 124 // Preserve max to prevent overflow. 125 return std::numeric_limits<int64_t>::max(); 126 } 127 return delta_; 128 } 129 130 double TimeDelta::InMicrosecondsF() const { 131 if (is_max()) { 132 // Preserve max to prevent overflow. 133 return std::numeric_limits<double>::infinity(); 134 } 135 return static_cast<double>(delta_); 136 } 137 138 int64_t TimeDelta::InNanoseconds() const { 139 if (is_max()) { 140 // Preserve max to prevent overflow. 141 return std::numeric_limits<int64_t>::max(); 142 } 143 return delta_ * Time::kNanosecondsPerMicrosecond; 144 } 145 146 namespace time_internal { 147 148 int64_t SaturatedAdd(TimeDelta delta, int64_t value) { 149 CheckedNumeric<int64_t> rv(delta.delta_); 150 rv += value; 151 if (rv.IsValid()) 152 return rv.ValueOrDie(); 153 // Positive RHS overflows. Negative RHS underflows. 154 if (value < 0) 155 return std::numeric_limits<int64_t>::min(); 156 return std::numeric_limits<int64_t>::max(); 157 } 158 159 int64_t SaturatedSub(TimeDelta delta, int64_t value) { 160 CheckedNumeric<int64_t> rv(delta.delta_); 161 rv -= value; 162 if (rv.IsValid()) 163 return rv.ValueOrDie(); 164 // Negative RHS overflows. Positive RHS underflows. 165 if (value < 0) 166 return std::numeric_limits<int64_t>::max(); 167 return std::numeric_limits<int64_t>::min(); 168 } 169 170 } // namespace time_internal 171 172 std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) { 173 return os << time_delta.InSecondsF() << " s"; 174 } 175 176 // Time ----------------------------------------------------------------------- 177 178 // static 179 Time Time::Now() { 180 return internal::g_time_now_function(); 181 } 182 183 // static 184 Time Time::NowFromSystemTime() { 185 // Just use g_time_now_function because it returns the system time. 186 return internal::g_time_now_from_system_time_function(); 187 } 188 189 // static 190 Time Time::FromDeltaSinceWindowsEpoch(TimeDelta delta) { 191 return Time(delta.InMicroseconds()); 192 } 193 194 TimeDelta Time::ToDeltaSinceWindowsEpoch() const { 195 return TimeDelta::FromMicroseconds(us_); 196 } 197 198 // static 199 Time Time::FromTimeT(time_t tt) { 200 if (tt == 0) 201 return Time(); // Preserve 0 so we can tell it doesn't exist. 202 if (tt == std::numeric_limits<time_t>::max()) 203 return Max(); 204 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt); 205 } 206 207 time_t Time::ToTimeT() const { 208 if (is_null()) 209 return 0; // Preserve 0 so we can tell it doesn't exist. 210 if (is_max()) { 211 // Preserve max without offset to prevent overflow. 212 return std::numeric_limits<time_t>::max(); 213 } 214 if (std::numeric_limits<int64_t>::max() - kTimeTToMicrosecondsOffset <= us_) { 215 DLOG(WARNING) << "Overflow when converting base::Time with internal " << 216 "value " << us_ << " to time_t."; 217 return std::numeric_limits<time_t>::max(); 218 } 219 return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond; 220 } 221 222 // static 223 Time Time::FromDoubleT(double dt) { 224 if (dt == 0 || std::isnan(dt)) 225 return Time(); // Preserve 0 so we can tell it doesn't exist. 226 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt); 227 } 228 229 double Time::ToDoubleT() const { 230 if (is_null()) 231 return 0; // Preserve 0 so we can tell it doesn't exist. 232 if (is_max()) { 233 // Preserve max without offset to prevent overflow. 234 return std::numeric_limits<double>::infinity(); 235 } 236 return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) / 237 static_cast<double>(kMicrosecondsPerSecond)); 238 } 239 240 #if defined(OS_POSIX) 241 // static 242 Time Time::FromTimeSpec(const timespec& ts) { 243 return FromDoubleT(ts.tv_sec + 244 static_cast<double>(ts.tv_nsec) / 245 base::Time::kNanosecondsPerSecond); 246 } 247 #endif 248 249 // static 250 Time Time::FromJsTime(double ms_since_epoch) { 251 // The epoch is a valid time, so this constructor doesn't interpret 252 // 0 as the null time. 253 return Time(kTimeTToMicrosecondsOffset) + 254 TimeDelta::FromMillisecondsD(ms_since_epoch); 255 } 256 257 double Time::ToJsTime() const { 258 if (is_null()) { 259 // Preserve 0 so the invalid result doesn't depend on the platform. 260 return 0; 261 } 262 if (is_max()) { 263 // Preserve max without offset to prevent overflow. 264 return std::numeric_limits<double>::infinity(); 265 } 266 return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) / 267 kMicrosecondsPerMillisecond); 268 } 269 270 Time Time::FromJavaTime(int64_t ms_since_epoch) { 271 return base::Time::UnixEpoch() + 272 base::TimeDelta::FromMilliseconds(ms_since_epoch); 273 } 274 275 int64_t Time::ToJavaTime() const { 276 if (is_null()) { 277 // Preserve 0 so the invalid result doesn't depend on the platform. 278 return 0; 279 } 280 if (is_max()) { 281 // Preserve max without offset to prevent overflow. 282 return std::numeric_limits<int64_t>::max(); 283 } 284 return ((us_ - kTimeTToMicrosecondsOffset) / 285 kMicrosecondsPerMillisecond); 286 } 287 288 // static 289 Time Time::UnixEpoch() { 290 Time time; 291 time.us_ = kTimeTToMicrosecondsOffset; 292 return time; 293 } 294 295 Time Time::LocalMidnight() const { 296 Exploded exploded; 297 LocalExplode(&exploded); 298 exploded.hour = 0; 299 exploded.minute = 0; 300 exploded.second = 0; 301 exploded.millisecond = 0; 302 Time out_time; 303 if (FromLocalExploded(exploded, &out_time)) 304 return out_time; 305 // This function must not fail. 306 NOTREACHED(); 307 return Time(); 308 } 309 310 // static 311 bool Time::FromStringInternal(const char* time_string, 312 bool is_local, 313 Time* parsed_time) { 314 DCHECK((time_string != nullptr) && (parsed_time != nullptr)); 315 316 if (time_string[0] == '\0') 317 return false; 318 319 PRTime result_time = 0; 320 PRStatus result = PR_ParseTimeString(time_string, 321 is_local ? PR_FALSE : PR_TRUE, 322 &result_time); 323 if (PR_SUCCESS != result) 324 return false; 325 326 result_time += kTimeTToMicrosecondsOffset; 327 *parsed_time = Time(result_time); 328 return true; 329 } 330 331 // static 332 bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) { 333 return lhs.year == rhs.year && lhs.month == rhs.month && 334 lhs.day_of_month == rhs.day_of_month && lhs.hour == rhs.hour && 335 lhs.minute == rhs.minute && lhs.second == rhs.second && 336 lhs.millisecond == rhs.millisecond; 337 } 338 339 std::ostream& operator<<(std::ostream& os, Time time) { 340 Time::Exploded exploded; 341 time.UTCExplode(&exploded); 342 // Use StringPrintf because iostreams formatting is painful. 343 return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC", 344 exploded.year, 345 exploded.month, 346 exploded.day_of_month, 347 exploded.hour, 348 exploded.minute, 349 exploded.second, 350 exploded.millisecond); 351 } 352 353 // TimeTicks ------------------------------------------------------------------ 354 355 // static 356 TimeTicks TimeTicks::Now() { 357 return internal::g_time_ticks_now_function(); 358 } 359 360 // static 361 TimeTicks TimeTicks::UnixEpoch() { 362 static const base::NoDestructor<base::TimeTicks> epoch([]() { 363 return subtle::TimeTicksNowIgnoringOverride() - 364 (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch()); 365 }()); 366 return *epoch; 367 } 368 369 TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase, 370 TimeDelta tick_interval) const { 371 // |interval_offset| is the offset from |this| to the next multiple of 372 // |tick_interval| after |tick_phase|, possibly negative if in the past. 373 TimeDelta interval_offset = (tick_phase - *this) % tick_interval; 374 // If |this| is exactly on the interval (i.e. offset==0), don't adjust. 375 // Otherwise, if |tick_phase| was in the past, adjust forward to the next 376 // tick after |this|. 377 if (!interval_offset.is_zero() && tick_phase < *this) 378 interval_offset += tick_interval; 379 return *this + interval_offset; 380 } 381 382 std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) { 383 // This function formats a TimeTicks object as "bogo-microseconds". 384 // The origin and granularity of the count are platform-specific, and may very 385 // from run to run. Although bogo-microseconds usually roughly correspond to 386 // real microseconds, the only real guarantee is that the number never goes 387 // down during a single run. 388 const TimeDelta as_time_delta = time_ticks - TimeTicks(); 389 return os << as_time_delta.InMicroseconds() << " bogo-microseconds"; 390 } 391 392 // ThreadTicks ---------------------------------------------------------------- 393 394 // static 395 ThreadTicks ThreadTicks::Now() { 396 return internal::g_thread_ticks_now_function(); 397 } 398 399 std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) { 400 const TimeDelta as_time_delta = thread_ticks - ThreadTicks(); 401 return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds"; 402 } 403 404 // Time::Exploded ------------------------------------------------------------- 405 406 inline bool is_in_range(int value, int lo, int hi) { 407 return lo <= value && value <= hi; 408 } 409 410 bool Time::Exploded::HasValidValues() const { 411 return is_in_range(month, 1, 12) && 412 is_in_range(day_of_week, 0, 6) && 413 is_in_range(day_of_month, 1, 31) && 414 is_in_range(hour, 0, 23) && 415 is_in_range(minute, 0, 59) && 416 is_in_range(second, 0, 60) && 417 is_in_range(millisecond, 0, 999); 418 } 419 420 } // namespace base 421