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