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 20namespace base { 21 22// TimeDelta ------------------------------------------------------------------ 23 24// static 25TimeDelta TimeDelta::Max() { 26 return TimeDelta(std::numeric_limits<int64_t>::max()); 27} 28 29int 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 37int 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 45int 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 53double 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 61int64_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 69double 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 77int64_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 85int64_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 94int64_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 102namespace time_internal { 103 104int64_t SaturatedAdd(TimeDelta delta, int64_t value) { 105 CheckedNumeric<int64_t> rv(delta.delta_); 106 rv += value; 107 return FromCheckedNumeric(rv); 108} 109 110int64_t SaturatedSub(TimeDelta delta, int64_t value) { 111 CheckedNumeric<int64_t> rv(delta.delta_); 112 rv -= value; 113 return FromCheckedNumeric(rv); 114} 115 116int64_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 132std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) { 133 return os << time_delta.InSecondsF() << "s"; 134} 135 136// Time ----------------------------------------------------------------------- 137 138// static 139Time 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 147time_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 163Time 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 169double 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 182Time 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 190Time 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 197double 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 210int64_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 224Time Time::UnixEpoch() { 225 Time time; 226 time.us_ = kTimeTToMicrosecondsOffset; 227 return time; 228} 229 230Time 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 241bool 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 262bool 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 269std::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. 285class 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 298static LazyInstance<UnixEpochSingleton>::Leaky 299 leaky_unix_epoch_singleton_instance = LAZY_INSTANCE_INITIALIZER; 300 301// Static 302TimeTicks TimeTicks::UnixEpoch() { 303 return leaky_unix_epoch_singleton_instance.Get().unix_epoch(); 304} 305 306TimeTicks 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 319std::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 329std::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 336inline bool is_in_range(int value, int lo, int hi) { 337 return lo <= value && value <= hi; 338} 339 340bool 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