• 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/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 
InDays() const24 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 
InHours() const32 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 
InMinutes() const40 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 
InSecondsF() const48 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 
InSeconds() const56 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 
InMillisecondsF() const64 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 
InMilliseconds() const72 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 
InMillisecondsRoundedUp() const80 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 
InMicroseconds() const89 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 
SaturatedAdd(TimeDelta delta,int64_t value)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 
SaturatedSub(TimeDelta delta,int64_t value)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 
operator <<(std::ostream & os,TimeDelta time_delta)123 std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
124   return os << time_delta.InSecondsF() << " s";
125 }
126 
127 // Time -----------------------------------------------------------------------
128 
129 // static
FromTimeT(time_t tt)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 
ToTimeT() const138 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
FromDoubleT(double dt)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 
ToDoubleT() const160 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
FromTimeSpec(const timespec & ts)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
FromJsTime(double ms_since_epoch)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 
ToJsTime() const188 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 
FromJavaTime(int64_t ms_since_epoch)201 Time Time::FromJavaTime(int64_t ms_since_epoch) {
202   return base::Time::UnixEpoch() +
203          base::TimeDelta::FromMilliseconds(ms_since_epoch);
204 }
205 
ToJavaTime() const206 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
UnixEpoch()220 Time Time::UnixEpoch() {
221   Time time;
222   time.us_ = kTimeTToMicrosecondsOffset;
223   return time;
224 }
225 
LocalMidnight() const226 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
FromStringInternal(const char * time_string,bool is_local,Time * parsed_time)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
ExplodedMostlyEquals(const Exploded & lhs,const Exploded & rhs)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 
operator <<(std::ostream & os,Time time)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:
UnixEpochSingleton()288   UnixEpochSingleton()
289       : unix_epoch_(TimeTicks::Now() - (Time::Now() - Time::UnixEpoch())) {}
290 
unix_epoch() const291   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
UnixEpoch()303 TimeTicks TimeTicks::UnixEpoch() {
304   return leaky_unix_epoch_singleton_instance.Get().unix_epoch();
305 }
306 
SnappedToNextTick(TimeTicks tick_phase,TimeDelta tick_interval) const307 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 
operator <<(std::ostream & os,TimeTicks time_ticks)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 
operator <<(std::ostream & os,ThreadTicks thread_ticks)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 
is_in_range(int value,int lo,int hi)337 inline bool is_in_range(int value, int lo, int hi) {
338   return lo <= value && value <= hi;
339 }
340 
HasValidValues() const341 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