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/lazy_instance.h" 14 #include "base/logging.h" 15 #include "base/macros.h" 16 #include "base/strings/stringprintf.h" 17 #include "base/third_party/nspr/prtime.h" 18 #include "build/build_config.h" 19 20 namespace base { 21 22 // TimeDelta ------------------------------------------------------------------ 23 24 int TimeDelta::InDays() const { 25 if (is_max()) { 26 // Preserve max to prevent overflow. 27 return std::numeric_limits<int>::max(); 28 } 29 return static_cast<int>(delta_ / Time::kMicrosecondsPerDay); 30 } 31 32 int TimeDelta::InHours() const { 33 if (is_max()) { 34 // Preserve max to prevent overflow. 35 return std::numeric_limits<int>::max(); 36 } 37 return static_cast<int>(delta_ / Time::kMicrosecondsPerHour); 38 } 39 40 int TimeDelta::InMinutes() 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::kMicrosecondsPerMinute); 46 } 47 48 double TimeDelta::InSecondsF() const { 49 if (is_max()) { 50 // Preserve max to prevent overflow. 51 return std::numeric_limits<double>::infinity(); 52 } 53 return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond; 54 } 55 56 int64_t TimeDelta::InSeconds() const { 57 if (is_max()) { 58 // Preserve max to prevent overflow. 59 return std::numeric_limits<int64_t>::max(); 60 } 61 return delta_ / Time::kMicrosecondsPerSecond; 62 } 63 64 double TimeDelta::InMillisecondsF() const { 65 if (is_max()) { 66 // Preserve max to prevent overflow. 67 return std::numeric_limits<double>::infinity(); 68 } 69 return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond; 70 } 71 72 int64_t TimeDelta::InMilliseconds() const { 73 if (is_max()) { 74 // Preserve max to prevent overflow. 75 return std::numeric_limits<int64_t>::max(); 76 } 77 return delta_ / Time::kMicrosecondsPerMillisecond; 78 } 79 80 int64_t TimeDelta::InMillisecondsRoundedUp() const { 81 if (is_max()) { 82 // Preserve max to prevent overflow. 83 return std::numeric_limits<int64_t>::max(); 84 } 85 return (delta_ + Time::kMicrosecondsPerMillisecond - 1) / 86 Time::kMicrosecondsPerMillisecond; 87 } 88 89 int64_t TimeDelta::InMicroseconds() const { 90 if (is_max()) { 91 // Preserve max to prevent overflow. 92 return std::numeric_limits<int64_t>::max(); 93 } 94 return delta_; 95 } 96 97 namespace time_internal { 98 99 int64_t SaturatedAdd(TimeDelta delta, int64_t value) { 100 CheckedNumeric<int64_t> rv(delta.delta_); 101 rv += value; 102 if (rv.IsValid()) 103 return rv.ValueOrDie(); 104 // Positive RHS overflows. Negative RHS underflows. 105 if (value < 0) 106 return -std::numeric_limits<int64_t>::max(); 107 return std::numeric_limits<int64_t>::max(); 108 } 109 110 int64_t SaturatedSub(TimeDelta delta, int64_t value) { 111 CheckedNumeric<int64_t> rv(delta.delta_); 112 rv -= value; 113 if (rv.IsValid()) 114 return rv.ValueOrDie(); 115 // Negative RHS overflows. Positive RHS underflows. 116 if (value < 0) 117 return std::numeric_limits<int64_t>::max(); 118 return -std::numeric_limits<int64_t>::max(); 119 } 120 121 } // namespace time_internal 122 123 std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) { 124 return os << time_delta.InSecondsF() << " s"; 125 } 126 127 // Time ----------------------------------------------------------------------- 128 129 // static 130 Time Time::FromTimeT(time_t tt) { 131 if (tt == 0) 132 return Time(); // Preserve 0 so we can tell it doesn't exist. 133 if (tt == std::numeric_limits<time_t>::max()) 134 return Max(); 135 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt); 136 } 137 138 time_t Time::ToTimeT() const { 139 if (is_null()) 140 return 0; // Preserve 0 so we can tell it doesn't exist. 141 if (is_max()) { 142 // Preserve max without offset to prevent overflow. 143 return std::numeric_limits<time_t>::max(); 144 } 145 if (std::numeric_limits<int64_t>::max() - kTimeTToMicrosecondsOffset <= us_) { 146 DLOG(WARNING) << "Overflow when converting base::Time with internal " << 147 "value " << us_ << " to time_t."; 148 return std::numeric_limits<time_t>::max(); 149 } 150 return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond; 151 } 152 153 // static 154 Time Time::FromDoubleT(double dt) { 155 if (dt == 0 || std::isnan(dt)) 156 return Time(); // Preserve 0 so we can tell it doesn't exist. 157 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt); 158 } 159 160 double Time::ToDoubleT() const { 161 if (is_null()) 162 return 0; // Preserve 0 so we can tell it doesn't exist. 163 if (is_max()) { 164 // Preserve max without offset to prevent overflow. 165 return std::numeric_limits<double>::infinity(); 166 } 167 return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) / 168 static_cast<double>(kMicrosecondsPerSecond)); 169 } 170 171 #if defined(OS_POSIX) 172 // static 173 Time Time::FromTimeSpec(const timespec& ts) { 174 return FromDoubleT(ts.tv_sec + 175 static_cast<double>(ts.tv_nsec) / 176 base::Time::kNanosecondsPerSecond); 177 } 178 #endif 179 180 // static 181 Time Time::FromJsTime(double ms_since_epoch) { 182 // The epoch is a valid time, so this constructor doesn't interpret 183 // 0 as the null time. 184 return Time(kTimeTToMicrosecondsOffset) + 185 TimeDelta::FromMillisecondsD(ms_since_epoch); 186 } 187 188 double Time::ToJsTime() const { 189 if (is_null()) { 190 // Preserve 0 so the invalid result doesn't depend on the platform. 191 return 0; 192 } 193 if (is_max()) { 194 // Preserve max without offset to prevent overflow. 195 return std::numeric_limits<double>::infinity(); 196 } 197 return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) / 198 kMicrosecondsPerMillisecond); 199 } 200 201 Time Time::FromJavaTime(int64_t ms_since_epoch) { 202 return base::Time::UnixEpoch() + 203 base::TimeDelta::FromMilliseconds(ms_since_epoch); 204 } 205 206 int64_t Time::ToJavaTime() const { 207 if (is_null()) { 208 // Preserve 0 so the invalid result doesn't depend on the platform. 209 return 0; 210 } 211 if (is_max()) { 212 // Preserve max without offset to prevent overflow. 213 return std::numeric_limits<int64_t>::max(); 214 } 215 return ((us_ - kTimeTToMicrosecondsOffset) / 216 kMicrosecondsPerMillisecond); 217 } 218 219 // static 220 Time Time::UnixEpoch() { 221 Time time; 222 time.us_ = kTimeTToMicrosecondsOffset; 223 return time; 224 } 225 226 Time Time::LocalMidnight() const { 227 Exploded exploded; 228 LocalExplode(&exploded); 229 exploded.hour = 0; 230 exploded.minute = 0; 231 exploded.second = 0; 232 exploded.millisecond = 0; 233 Time out_time; 234 if (FromLocalExploded(exploded, &out_time)) 235 return out_time; 236 // This function must not fail. 237 NOTREACHED(); 238 return Time(); 239 } 240 241 // static 242 bool Time::FromStringInternal(const char* time_string, 243 bool is_local, 244 Time* parsed_time) { 245 DCHECK((time_string != NULL) && (parsed_time != NULL)); 246 247 if (time_string[0] == '\0') 248 return false; 249 250 PRTime result_time = 0; 251 PRStatus result = PR_ParseTimeString(time_string, 252 is_local ? PR_FALSE : PR_TRUE, 253 &result_time); 254 if (PR_SUCCESS != result) 255 return false; 256 257 result_time += kTimeTToMicrosecondsOffset; 258 *parsed_time = Time(result_time); 259 return true; 260 } 261 262 // static 263 bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) { 264 return lhs.year == rhs.year && lhs.month == rhs.month && 265 lhs.day_of_month == rhs.day_of_month && lhs.hour == rhs.hour && 266 lhs.minute == rhs.minute && lhs.second == rhs.second && 267 lhs.millisecond == rhs.millisecond; 268 } 269 270 std::ostream& operator<<(std::ostream& os, Time time) { 271 Time::Exploded exploded; 272 time.UTCExplode(&exploded); 273 // Use StringPrintf because iostreams formatting is painful. 274 return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC", 275 exploded.year, 276 exploded.month, 277 exploded.day_of_month, 278 exploded.hour, 279 exploded.minute, 280 exploded.second, 281 exploded.millisecond); 282 } 283 284 // Local helper class to hold the conversion from Time to TickTime at the 285 // time of the Unix epoch. 286 class UnixEpochSingleton { 287 public: 288 UnixEpochSingleton() 289 : unix_epoch_(TimeTicks::Now() - (Time::Now() - Time::UnixEpoch())) {} 290 291 TimeTicks unix_epoch() const { return unix_epoch_; } 292 293 private: 294 const TimeTicks unix_epoch_; 295 296 DISALLOW_COPY_AND_ASSIGN(UnixEpochSingleton); 297 }; 298 299 static LazyInstance<UnixEpochSingleton>::Leaky 300 leaky_unix_epoch_singleton_instance = LAZY_INSTANCE_INITIALIZER; 301 302 // Static 303 TimeTicks TimeTicks::UnixEpoch() { 304 return leaky_unix_epoch_singleton_instance.Get().unix_epoch(); 305 } 306 307 TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase, 308 TimeDelta tick_interval) const { 309 // |interval_offset| is the offset from |this| to the next multiple of 310 // |tick_interval| after |tick_phase|, possibly negative if in the past. 311 TimeDelta interval_offset = (tick_phase - *this) % tick_interval; 312 // If |this| is exactly on the interval (i.e. offset==0), don't adjust. 313 // Otherwise, if |tick_phase| was in the past, adjust forward to the next 314 // tick after |this|. 315 if (!interval_offset.is_zero() && tick_phase < *this) 316 interval_offset += tick_interval; 317 return *this + interval_offset; 318 } 319 320 std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) { 321 // This function formats a TimeTicks object as "bogo-microseconds". 322 // The origin and granularity of the count are platform-specific, and may very 323 // from run to run. Although bogo-microseconds usually roughly correspond to 324 // real microseconds, the only real guarantee is that the number never goes 325 // down during a single run. 326 const TimeDelta as_time_delta = time_ticks - TimeTicks(); 327 return os << as_time_delta.InMicroseconds() << " bogo-microseconds"; 328 } 329 330 std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) { 331 const TimeDelta as_time_delta = thread_ticks - ThreadTicks(); 332 return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds"; 333 } 334 335 // Time::Exploded ------------------------------------------------------------- 336 337 inline bool is_in_range(int value, int lo, int hi) { 338 return lo <= value && value <= hi; 339 } 340 341 bool Time::Exploded::HasValidValues() const { 342 return is_in_range(month, 1, 12) && 343 is_in_range(day_of_week, 0, 6) && 344 is_in_range(day_of_month, 1, 31) && 345 is_in_range(hour, 0, 23) && 346 is_in_range(minute, 0, 59) && 347 is_in_range(second, 0, 60) && 348 is_in_range(millisecond, 0, 999); 349 } 350 351 } // namespace base 352