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