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