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