blob: a2ea5ae2d5209dbefe7a7bcaea870d337939bbe3 [file] [log] [blame]
tzik@chromium.org0a1ccf42011-06-18 20:53:14 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
mmentovai@google.com7ba78d72008-08-12 03:15:10 +09004
5#include "base/time.h"
6
mmentovai@google.com7ba78d72008-08-12 03:15:10 +09007#include <sys/time.h>
8#include <time.h>
tzik@chromium.org0a1ccf42011-06-18 20:53:14 +09009#include <unistd.h>
mmentovai@google.com7ba78d72008-08-12 03:15:10 +090010
mark@chromium.org430a6472008-11-05 04:45:51 +090011#include <limits>
12
mmentovai@google.com7ba78d72008-08-12 03:15:10 +090013#include "base/basictypes.h"
14#include "base/logging.h"
15
dsh@google.com0f8dd262008-10-28 05:43:33 +090016namespace base {
17
erg@google.com37c078e2011-01-11 09:50:59 +090018struct timespec TimeDelta::ToTimeSpec() const {
19 int64 microseconds = InMicroseconds();
20 time_t seconds = 0;
21 if (microseconds >= Time::kMicrosecondsPerSecond) {
22 seconds = InSeconds();
23 microseconds -= seconds * Time::kMicrosecondsPerSecond;
24 }
25 struct timespec result =
26 {seconds,
27 microseconds * Time::kNanosecondsPerMicrosecond};
28 return result;
29}
30
jeremy@chromium.org5dd6a512009-12-15 20:55:08 +090031#if !defined(OS_MACOSX)
mmentovai@google.com7ba78d72008-08-12 03:15:10 +090032// The Time routines in this file use standard POSIX routines, or almost-
33// standard routines in the case of timegm. We need to use a Mach-specific
34// function for TimeTicks::Now() on Mac OS X.
35
36// Time -----------------------------------------------------------------------
37
brettw@chromium.orgd2f97822009-08-26 11:53:36 +090038// Windows uses a Gregorian epoch of 1601. We need to match this internally
39// so that our time representations match across all platforms. See bug 14734.
40// irb(main):010:0> Time.at(0).getutc()
41// => Thu Jan 01 00:00:00 UTC 1970
42// irb(main):011:0> Time.at(-11644473600).getutc()
43// => Mon Jan 01 00:00:00 UTC 1601
44static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
45static const int64 kWindowsEpochDeltaMilliseconds =
46 kWindowsEpochDeltaSeconds * Time::kMillisecondsPerSecond;
47
mmentovai@google.com7ba78d72008-08-12 03:15:10 +090048// static
brettw@chromium.orgd2f97822009-08-26 11:53:36 +090049const int64 Time::kWindowsEpochDeltaMicroseconds =
50 kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
51
52// Some functions in time.cc use time_t directly, so we provide an offset
53// to convert from time_t (Unix epoch) and internal (Windows epoch).
54// static
55const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
mmentovai@google.com7ba78d72008-08-12 03:15:10 +090056
57// static
deanm@chromium.orga9d0d482008-09-11 23:06:48 +090058Time Time::Now() {
mmentovai@google.com7ba78d72008-08-12 03:15:10 +090059 struct timeval tv;
60 struct timezone tz = { 0, 0 }; // UTC
61 if (gettimeofday(&tv, &tz) != 0) {
62 DCHECK(0) << "Could not determine time of day";
63 }
64 // Combine seconds and microseconds in a 64-bit field containing microseconds
brettw@chromium.orgd2f97822009-08-26 11:53:36 +090065 // since the epoch. That's enough for nearly 600 centuries. Adjust from
66 // Unix (1970) to Windows (1601) epoch.
67 return Time((tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec) +
68 kWindowsEpochDeltaMicroseconds);
mmentovai@google.com7ba78d72008-08-12 03:15:10 +090069}
70
71// static
erikkay@google.com9ac26762009-04-18 09:42:48 +090072Time Time::NowFromSystemTime() {
73 // Just use Now() because Now() returns the system time.
74 return Now();
75}
76
erg@google.com37c078e2011-01-11 09:50:59 +090077void Time::Explode(bool is_local, Exploded* exploded) const {
78 // Time stores times with microsecond resolution, but Exploded only carries
79 // millisecond resolution, so begin by being lossy. Adjust from Windows
80 // epoch (1601) to Unix epoch (1970);
81 int64 milliseconds = (us_ - kWindowsEpochDeltaMicroseconds) /
82 kMicrosecondsPerMillisecond;
83 time_t seconds = milliseconds / kMillisecondsPerSecond;
84
85 struct tm timestruct;
86 if (is_local)
87 localtime_r(&seconds, &timestruct);
88 else
89 gmtime_r(&seconds, &timestruct);
90
91 exploded->year = timestruct.tm_year + 1900;
92 exploded->month = timestruct.tm_mon + 1;
93 exploded->day_of_week = timestruct.tm_wday;
94 exploded->day_of_month = timestruct.tm_mday;
95 exploded->hour = timestruct.tm_hour;
96 exploded->minute = timestruct.tm_min;
97 exploded->second = timestruct.tm_sec;
98 exploded->millisecond = milliseconds % kMillisecondsPerSecond;
99}
100
erikkay@google.com9ac26762009-04-18 09:42:48 +0900101// static
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900102Time Time::FromExploded(bool is_local, const Exploded& exploded) {
103 struct tm timestruct;
104 timestruct.tm_sec = exploded.second;
105 timestruct.tm_min = exploded.minute;
106 timestruct.tm_hour = exploded.hour;
107 timestruct.tm_mday = exploded.day_of_month;
108 timestruct.tm_mon = exploded.month - 1;
109 timestruct.tm_year = exploded.year - 1900;
110 timestruct.tm_wday = exploded.day_of_week; // mktime/timegm ignore this
111 timestruct.tm_yday = 0; // mktime/timegm ignore this
112 timestruct.tm_isdst = -1; // attempt to figure it out
chromium@hybridsource.org8f85a6a2011-06-25 13:54:41 +0900113#if !defined(OS_NACL) && !defined(OS_SOLARIS)
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900114 timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore
115 timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore
abarth@chromium.orgce796862011-03-14 04:01:16 +0900116#endif
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900117
118 time_t seconds;
119 if (is_local)
120 seconds = mktime(&timestruct);
121 else
122 seconds = timegm(&timestruct);
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900123
mark@chromium.org430a6472008-11-05 04:45:51 +0900124 int64 milliseconds;
125 // Handle overflow. Clamping the range to what mktime and timegm might
126 // return is the best that can be done here. It's not ideal, but it's better
127 // than failing here or ignoring the overflow case and treating each time
128 // overflow as one second prior to the epoch.
129 if (seconds == -1 &&
130 (exploded.year < 1969 || exploded.year > 1970)) {
131 // If exploded.year is 1969 or 1970, take -1 as correct, with the
132 // time indicating 1 second prior to the epoch. (1970 is allowed to handle
133 // time zone and DST offsets.) Otherwise, return the most future or past
134 // time representable. Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
135 //
136 // The minimum and maximum representible times that mktime and timegm could
137 // return are used here instead of values outside that range to allow for
138 // proper round-tripping between exploded and counter-type time
139 // representations in the presence of possible truncation to time_t by
140 // division and use with other functions that accept time_t.
141 //
142 // When representing the most distant time in the future, add in an extra
143 // 999ms to avoid the time being less than any other possible value that
144 // this function can return.
145 if (exploded.year < 1969) {
146 milliseconds = std::numeric_limits<time_t>::min() *
147 kMillisecondsPerSecond;
148 } else {
149 milliseconds = (std::numeric_limits<time_t>::max() *
150 kMillisecondsPerSecond) +
151 kMillisecondsPerSecond - 1;
152 }
153 } else {
154 milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond;
155 }
156
brettw@chromium.orgd2f97822009-08-26 11:53:36 +0900157 // Adjust from Unix (1970) to Windows (1601) epoch.
158 return Time((milliseconds * kMicrosecondsPerMillisecond) +
159 kWindowsEpochDeltaMicroseconds);
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900160}
161
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900162// TimeTicks ------------------------------------------------------------------
wtc@chromium.org9b07a8f2009-09-01 07:25:00 +0900163// FreeBSD 6 has CLOCK_MONOLITHIC but defines _POSIX_MONOTONIC_CLOCK to -1.
164#if (defined(OS_POSIX) && \
165 defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
pvalchev@google.com1d919db2010-03-10 16:46:43 +0900166 defined(OS_FREEBSD) || defined(OS_OPENBSD)
brettw@chromium.orgd2f97822009-08-26 11:53:36 +0900167
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900168// static
169TimeTicks TimeTicks::Now() {
170 uint64_t absolute_micro;
171
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900172 struct timespec ts;
173 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
174 NOTREACHED() << "clock_gettime(CLOCK_MONOTONIC) failed.";
175 return TimeTicks();
176 }
177
178 absolute_micro =
179 (static_cast<int64>(ts.tv_sec) * Time::kMicrosecondsPerSecond) +
180 (static_cast<int64>(ts.tv_nsec) / Time::kNanosecondsPerMicrosecond);
181
brettw@chromium.orgd2f97822009-08-26 11:53:36 +0900182 return TimeTicks(absolute_micro);
183}
184
abarth@chromium.orgce796862011-03-14 04:01:16 +0900185#elif defined(OS_NACL)
186
187TimeTicks TimeTicks::Now() {
188 // Sadly, Native Client does not have _POSIX_TIMERS enabled in sys/features.h
189 // Apparently NaCl only has CLOCK_REALTIME:
190 // http://code.google.com/p/nativeclient/issues/detail?id=1159
191 return TimeTicks(clock());
192}
193
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900194#else // _POSIX_MONOTONIC_CLOCK
195#error No usable tick clock function on this platform.
196#endif // _POSIX_MONOTONIC_CLOCK
197
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900198// static
mbelshe@google.com556bc842008-09-26 12:00:00 +0900199TimeTicks TimeTicks::HighResNow() {
mmentovai@google.com7ba78d72008-08-12 03:15:10 +0900200 return Now();
201}
dsh@google.com0f8dd262008-10-28 05:43:33 +0900202
jeremy@chromium.org5dd6a512009-12-15 20:55:08 +0900203#endif // !OS_MACOSX
204
jochen@chromium.orga6879772010-02-18 19:02:26 +0900205struct timeval Time::ToTimeVal() const {
206 struct timeval result;
207 int64 us = us_ - kTimeTToMicrosecondsOffset;
208 result.tv_sec = us / Time::kMicrosecondsPerSecond;
209 result.tv_usec = us % Time::kMicrosecondsPerSecond;
210 return result;
211}
212
dsh@google.com0f8dd262008-10-28 05:43:33 +0900213} // namespace base