• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2006-2008 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.h"
6 
7 #include <sys/time.h>
8 #include <time.h>
9 
10 #include <limits>
11 
12 #include "base/basictypes.h"
13 #include "base/logging.h"
14 
15 namespace base {
16 
17 #if !defined(OS_MACOSX)
18 // The Time routines in this file use standard POSIX routines, or almost-
19 // standard routines in the case of timegm.  We need to use a Mach-specific
20 // function for TimeTicks::Now() on Mac OS X.
21 
22 // Time -----------------------------------------------------------------------
23 
24 // Windows uses a Gregorian epoch of 1601.  We need to match this internally
25 // so that our time representations match across all platforms.  See bug 14734.
26 //   irb(main):010:0> Time.at(0).getutc()
27 //   => Thu Jan 01 00:00:00 UTC 1970
28 //   irb(main):011:0> Time.at(-11644473600).getutc()
29 //   => Mon Jan 01 00:00:00 UTC 1601
30 static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
31 static const int64 kWindowsEpochDeltaMilliseconds =
32     kWindowsEpochDeltaSeconds * Time::kMillisecondsPerSecond;
33 
34 // static
35 const int64 Time::kWindowsEpochDeltaMicroseconds =
36     kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
37 
38 // Some functions in time.cc use time_t directly, so we provide an offset
39 // to convert from time_t (Unix epoch) and internal (Windows epoch).
40 // static
41 const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
42 
43 // static
Now()44 Time Time::Now() {
45   struct timeval tv;
46   struct timezone tz = { 0, 0 };  // UTC
47   if (gettimeofday(&tv, &tz) != 0) {
48     DCHECK(0) << "Could not determine time of day";
49   }
50   // Combine seconds and microseconds in a 64-bit field containing microseconds
51   // since the epoch.  That's enough for nearly 600 centuries.  Adjust from
52   // Unix (1970) to Windows (1601) epoch.
53   return Time((tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec) +
54       kWindowsEpochDeltaMicroseconds);
55 }
56 
57 // static
NowFromSystemTime()58 Time Time::NowFromSystemTime() {
59   // Just use Now() because Now() returns the system time.
60   return Now();
61 }
62 
63 // static
FromExploded(bool is_local,const Exploded & exploded)64 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
65   struct tm timestruct;
66   timestruct.tm_sec    = exploded.second;
67   timestruct.tm_min    = exploded.minute;
68   timestruct.tm_hour   = exploded.hour;
69   timestruct.tm_mday   = exploded.day_of_month;
70   timestruct.tm_mon    = exploded.month - 1;
71   timestruct.tm_year   = exploded.year - 1900;
72   timestruct.tm_wday   = exploded.day_of_week;  // mktime/timegm ignore this
73   timestruct.tm_yday   = 0;     // mktime/timegm ignore this
74   timestruct.tm_isdst  = -1;    // attempt to figure it out
75   timestruct.tm_gmtoff = 0;     // not a POSIX field, so mktime/timegm ignore
76   timestruct.tm_zone   = NULL;  // not a POSIX field, so mktime/timegm ignore
77 
78   time_t seconds;
79   if (is_local)
80     seconds = mktime(&timestruct);
81   else
82     seconds = timegm(&timestruct);
83 
84   int64 milliseconds;
85   // Handle overflow.  Clamping the range to what mktime and timegm might
86   // return is the best that can be done here.  It's not ideal, but it's better
87   // than failing here or ignoring the overflow case and treating each time
88   // overflow as one second prior to the epoch.
89   if (seconds == -1 &&
90       (exploded.year < 1969 || exploded.year > 1970)) {
91     // If exploded.year is 1969 or 1970, take -1 as correct, with the
92     // time indicating 1 second prior to the epoch.  (1970 is allowed to handle
93     // time zone and DST offsets.)  Otherwise, return the most future or past
94     // time representable.  Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
95     //
96     // The minimum and maximum representible times that mktime and timegm could
97     // return are used here instead of values outside that range to allow for
98     // proper round-tripping between exploded and counter-type time
99     // representations in the presence of possible truncation to time_t by
100     // division and use with other functions that accept time_t.
101     //
102     // When representing the most distant time in the future, add in an extra
103     // 999ms to avoid the time being less than any other possible value that
104     // this function can return.
105     if (exploded.year < 1969) {
106       milliseconds = std::numeric_limits<time_t>::min() *
107                      kMillisecondsPerSecond;
108     } else {
109       milliseconds = (std::numeric_limits<time_t>::max() *
110                       kMillisecondsPerSecond) +
111                      kMillisecondsPerSecond - 1;
112     }
113   } else {
114     milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond;
115   }
116 
117   // Adjust from Unix (1970) to Windows (1601) epoch.
118   return Time((milliseconds * kMicrosecondsPerMillisecond) +
119       kWindowsEpochDeltaMicroseconds);
120 }
121 
Explode(bool is_local,Exploded * exploded) const122 void Time::Explode(bool is_local, Exploded* exploded) const {
123   // Time stores times with microsecond resolution, but Exploded only carries
124   // millisecond resolution, so begin by being lossy.  Adjust from Windows
125   // epoch (1601) to Unix epoch (1970);
126   int64 milliseconds = (us_ - kWindowsEpochDeltaMicroseconds) /
127       kMicrosecondsPerMillisecond;
128   time_t seconds = milliseconds / kMillisecondsPerSecond;
129 
130   struct tm timestruct;
131   if (is_local)
132     localtime_r(&seconds, &timestruct);
133   else
134     gmtime_r(&seconds, &timestruct);
135 
136   exploded->year         = timestruct.tm_year + 1900;
137   exploded->month        = timestruct.tm_mon + 1;
138   exploded->day_of_week  = timestruct.tm_wday;
139   exploded->day_of_month = timestruct.tm_mday;
140   exploded->hour         = timestruct.tm_hour;
141   exploded->minute       = timestruct.tm_min;
142   exploded->second       = timestruct.tm_sec;
143   exploded->millisecond  = milliseconds % kMillisecondsPerSecond;
144 }
145 
146 // TimeTicks ------------------------------------------------------------------
147 // FreeBSD 6 has CLOCK_MONOLITHIC but defines _POSIX_MONOTONIC_CLOCK to -1.
148 #if (defined(OS_POSIX) &&                                               \
149      defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
150     defined(OS_FREEBSD)
151 
152 // static
Now()153 TimeTicks TimeTicks::Now() {
154   uint64_t absolute_micro;
155 
156   struct timespec ts;
157   if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
158     NOTREACHED() << "clock_gettime(CLOCK_MONOTONIC) failed.";
159     return TimeTicks();
160   }
161 
162   absolute_micro =
163       (static_cast<int64>(ts.tv_sec) * Time::kMicrosecondsPerSecond) +
164       (static_cast<int64>(ts.tv_nsec) / Time::kNanosecondsPerMicrosecond);
165 
166   return TimeTicks(absolute_micro);
167 }
168 
169 #else  // _POSIX_MONOTONIC_CLOCK
170 #error No usable tick clock function on this platform.
171 #endif  // _POSIX_MONOTONIC_CLOCK
172 
173 // static
HighResNow()174 TimeTicks TimeTicks::HighResNow() {
175   return Now();
176 }
177 
178 #endif  // !OS_MACOSX
179 
ToTimeSpec() const180 struct timespec TimeDelta::ToTimeSpec() const {
181   int64 microseconds = InMicroseconds();
182   time_t seconds = 0;
183   if (microseconds >= Time::kMicrosecondsPerSecond) {
184     seconds = InSeconds();
185     microseconds -= seconds * Time::kMicrosecondsPerSecond;
186   }
187   struct timespec result =
188       {seconds,
189        microseconds * Time::kNanosecondsPerMicrosecond};
190   return result;
191 }
192 
193 }  // namespace base
194