blob: 0dc892a835f611e3d75a6cd065f2d054971c8350 [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"
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080014#include "base/macros.h"
Vitaly Bukacbed2062015-08-17 12:54:05 -070015#include "base/strings/stringprintf.h"
Vitaly Bukacbed2062015-08-17 12:54:05 -070016
17namespace base {
18
19// TimeDelta ------------------------------------------------------------------
20
21// static
22TimeDelta TimeDelta::Max() {
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080023 return TimeDelta(std::numeric_limits<int64_t>::max());
Vitaly Bukacbed2062015-08-17 12:54:05 -070024}
25
26int 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
34int 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
42int 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
50double 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
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080058int64_t TimeDelta::InSeconds() const {
Vitaly Bukacbed2062015-08-17 12:54:05 -070059 if (is_max()) {
60 // Preserve max to prevent overflow.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080061 return std::numeric_limits<int64_t>::max();
Vitaly Bukacbed2062015-08-17 12:54:05 -070062 }
63 return delta_ / Time::kMicrosecondsPerSecond;
64}
65
66double 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
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080074int64_t TimeDelta::InMilliseconds() const {
Vitaly Bukacbed2062015-08-17 12:54:05 -070075 if (is_max()) {
76 // Preserve max to prevent overflow.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080077 return std::numeric_limits<int64_t>::max();
Vitaly Bukacbed2062015-08-17 12:54:05 -070078 }
79 return delta_ / Time::kMicrosecondsPerMillisecond;
80}
81
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080082int64_t TimeDelta::InMillisecondsRoundedUp() const {
Vitaly Bukacbed2062015-08-17 12:54:05 -070083 if (is_max()) {
84 // Preserve max to prevent overflow.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080085 return std::numeric_limits<int64_t>::max();
Vitaly Bukacbed2062015-08-17 12:54:05 -070086 }
87 return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /
88 Time::kMicrosecondsPerMillisecond;
89}
90
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080091int64_t TimeDelta::InMicroseconds() const {
Vitaly Bukacbed2062015-08-17 12:54:05 -070092 if (is_max()) {
93 // Preserve max to prevent overflow.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080094 return std::numeric_limits<int64_t>::max();
Vitaly Bukacbed2062015-08-17 12:54:05 -070095 }
96 return delta_;
97}
98
99namespace time_internal {
100
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800101int64_t SaturatedAdd(TimeDelta delta, int64_t value) {
102 CheckedNumeric<int64_t> rv(delta.delta_);
Vitaly Bukacbed2062015-08-17 12:54:05 -0700103 rv += value;
104 return FromCheckedNumeric(rv);
105}
106
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800107int64_t SaturatedSub(TimeDelta delta, int64_t value) {
108 CheckedNumeric<int64_t> rv(delta.delta_);
Vitaly Bukacbed2062015-08-17 12:54:05 -0700109 rv -= value;
110 return FromCheckedNumeric(rv);
111}
112
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800113int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> value) {
Vitaly Bukacbed2062015-08-17 12:54:05 -0700114 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.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800121 int64_t limit = std::numeric_limits<int64_t>::max();
Vitaly Bukacbed2062015-08-17 12:54:05 -0700122 if (value.validity() == internal::RANGE_UNDERFLOW)
123 limit = -limit;
124 return value.ValueOrDefault(limit);
125}
126
127} // namespace time_internal
128
129std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
130 return os << time_delta.InSecondsF() << "s";
131}
132
133// Time -----------------------------------------------------------------------
134
135// static
136Time Time::Max() {
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800137 return Time(std::numeric_limits<int64_t>::max());
Vitaly Bukacbed2062015-08-17 12:54:05 -0700138}
139
140// static
141Time 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();
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800146 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt);
Vitaly Bukacbed2062015-08-17 12:54:05 -0700147}
148
149time_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 }
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800156 if (std::numeric_limits<int64_t>::max() - kTimeTToMicrosecondsOffset <= us_) {
Vitaly Bukacbed2062015-08-17 12:54:05 -0700157 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
165Time Time::FromDoubleT(double dt) {
166 if (dt == 0 || std::isnan(dt))
167 return Time(); // Preserve 0 so we can tell it doesn't exist.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800168 return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt);
Vitaly Bukacbed2062015-08-17 12:54:05 -0700169}
170
171double 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
184Time 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
192Time 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.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800195 return Time(kTimeTToMicrosecondsOffset) +
196 TimeDelta::FromMillisecondsD(ms_since_epoch);
Vitaly Bukacbed2062015-08-17 12:54:05 -0700197}
198
199double 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
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800212int64_t Time::ToJavaTime() const {
Vitaly Bukacbed2062015-08-17 12:54:05 -0700213 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.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800219 return std::numeric_limits<int64_t>::max();
Vitaly Bukacbed2062015-08-17 12:54:05 -0700220 }
221 return ((us_ - kTimeTToMicrosecondsOffset) /
222 kMicrosecondsPerMillisecond);
223}
224
225// static
226Time Time::UnixEpoch() {
227 Time time;
228 time.us_ = kTimeTToMicrosecondsOffset;
229 return time;
230}
231
232Time 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
Vitaly Bukacbed2062015-08-17 12:54:05 -0700242std::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.
258class UnixEpochSingleton {
259 public:
260 UnixEpochSingleton()
261 : unix_epoch_(TimeTicks::Now() - (Time::Now() - Time::UnixEpoch())) {}
262
263 TimeTicks unix_epoch() const { return unix_epoch_; }
264
265 private:
266 const TimeTicks unix_epoch_;
267
268 DISALLOW_COPY_AND_ASSIGN(UnixEpochSingleton);
269};
270
Vitaly Bukacbed2062015-08-17 12:54:05 -0700271TimeTicks 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
284std::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
294std::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
Vitaly Bukacbed2062015-08-17 12:54:05 -0700299// Time::Exploded -------------------------------------------------------------
300
301inline bool is_in_range(int value, int lo, int hi) {
302 return lo <= value && value <= hi;
303}
304
305bool 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