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