Home | History | Annotate | Download | only in time
      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