• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdint.h>
8 #include <sys/time.h>
9 #include <time.h>
10 #if defined(OS_ANDROID) && !defined(__LP64__)
11 #include <time64.h>
12 #endif
13 #include <unistd.h>
14 
15 #include <limits>
16 
17 #include "base/numerics/safe_math.h"
18 #include "base/synchronization/lock.h"
19 #include "build/build_config.h"
20 
21 #if defined(OS_ANDROID)
22 #include "base/os_compat_android.h"
23 #elif defined(OS_NACL)
24 #include "base/os_compat_nacl.h"
25 #endif
26 
27 #if defined(OS_MACOSX)
28 static_assert(sizeof(time_t) >= 8, "Y2038 problem!");
29 #endif
30 
31 namespace {
32 
33 // This prevents a crash on traversing the environment global and looking up
34 // the 'TZ' variable in libc. See: crbug.com/390567.
GetSysTimeToTimeStructLock()35 base::Lock* GetSysTimeToTimeStructLock() {
36   static auto* lock = new base::Lock();
37   return lock;
38 }
39 
40 // Define a system-specific SysTime that wraps either to a time_t or
41 // a time64_t depending on the host system, and associated convertion.
42 // See crbug.com/162007
43 #if defined(OS_ANDROID) && !defined(__LP64__)
44 typedef time64_t SysTime;
45 
SysTimeFromTimeStruct(struct tm * timestruct,bool is_local)46 SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
47   base::AutoLock locked(*GetSysTimeToTimeStructLock());
48   if (is_local)
49     return mktime64(timestruct);
50   else
51     return timegm64(timestruct);
52 }
53 
SysTimeToTimeStruct(SysTime t,struct tm * timestruct,bool is_local)54 void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
55   base::AutoLock locked(*GetSysTimeToTimeStructLock());
56   if (is_local)
57     localtime64_r(&t, timestruct);
58   else
59     gmtime64_r(&t, timestruct);
60 }
61 
62 #elif defined(OS_AIX)
63 
64 // The function timegm is not available on AIX.
aix_timegm(struct tm * tm)65 time_t aix_timegm(struct tm* tm) {
66   time_t ret;
67   char* tz;
68 
69   tz = getenv("TZ");
70   if (tz) {
71     tz = strdup(tz);
72   }
73   setenv("TZ", "GMT0", 1);
74   tzset();
75   ret = mktime(tm);
76   if (tz) {
77     setenv("TZ", tz, 1);
78     free(tz);
79   } else {
80     unsetenv("TZ");
81   }
82   tzset();
83   return ret;
84 }
85 
86 typedef time_t SysTime;
87 
SysTimeFromTimeStruct(struct tm * timestruct,bool is_local)88 SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
89   base::AutoLock locked(*GetSysTimeToTimeStructLock());
90   if (is_local)
91     return mktime(timestruct);
92   else
93     return aix_timegm(timestruct);
94 }
95 
SysTimeToTimeStruct(SysTime t,struct tm * timestruct,bool is_local)96 void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
97   base::AutoLock locked(*GetSysTimeToTimeStructLock());
98   if (is_local)
99     localtime_r(&t, timestruct);
100   else
101     gmtime_r(&t, timestruct);
102 }
103 
104 #else   // OS_ANDROID && !__LP64__
105 typedef time_t SysTime;
106 
SysTimeFromTimeStruct(struct tm * timestruct,bool is_local)107 SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
108   base::AutoLock locked(*GetSysTimeToTimeStructLock());
109   if (is_local)
110     return mktime(timestruct);
111   else
112     return timegm(timestruct);
113 }
114 
SysTimeToTimeStruct(SysTime t,struct tm * timestruct,bool is_local)115 void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
116   base::AutoLock locked(*GetSysTimeToTimeStructLock());
117   if (is_local)
118     localtime_r(&t, timestruct);
119   else
120     gmtime_r(&t, timestruct);
121 }
122 #endif  // OS_ANDROID
123 
124 }  // namespace
125 
126 namespace base {
127 
Explode(bool is_local,Exploded * exploded) const128 void Time::Explode(bool is_local, Exploded* exploded) const {
129   // Time stores times with microsecond resolution, but Exploded only carries
130   // millisecond resolution, so begin by being lossy.  Adjust from Windows
131   // epoch (1601) to Unix epoch (1970);
132   int64_t microseconds = us_ - kTimeTToMicrosecondsOffset;
133   // The following values are all rounded towards -infinity.
134   int64_t milliseconds;  // Milliseconds since epoch.
135   SysTime seconds;       // Seconds since epoch.
136   int millisecond;       // Exploded millisecond value (0-999).
137   if (microseconds >= 0) {
138     // Rounding towards -infinity <=> rounding towards 0, in this case.
139     milliseconds = microseconds / kMicrosecondsPerMillisecond;
140     seconds = milliseconds / kMillisecondsPerSecond;
141     millisecond = milliseconds % kMillisecondsPerSecond;
142   } else {
143     // Round these *down* (towards -infinity).
144     milliseconds = (microseconds - kMicrosecondsPerMillisecond + 1) /
145                    kMicrosecondsPerMillisecond;
146     seconds =
147         (milliseconds - kMillisecondsPerSecond + 1) / kMillisecondsPerSecond;
148     // Make this nonnegative (and between 0 and 999 inclusive).
149     millisecond = milliseconds % kMillisecondsPerSecond;
150     if (millisecond < 0)
151       millisecond += kMillisecondsPerSecond;
152   }
153 
154   struct tm timestruct;
155   SysTimeToTimeStruct(seconds, &timestruct, is_local);
156 
157   exploded->year = timestruct.tm_year + 1900;
158   exploded->month = timestruct.tm_mon + 1;
159   exploded->day_of_week = timestruct.tm_wday;
160   exploded->day_of_month = timestruct.tm_mday;
161   exploded->hour = timestruct.tm_hour;
162   exploded->minute = timestruct.tm_min;
163   exploded->second = timestruct.tm_sec;
164   exploded->millisecond = millisecond;
165 }
166 
167 // static
FromExploded(bool is_local,const Exploded & exploded,Time * time)168 bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) {
169   CheckedNumeric<int> month = exploded.month;
170   month--;
171   CheckedNumeric<int> year = exploded.year;
172   year -= 1900;
173   if (!month.IsValid() || !year.IsValid()) {
174     *time = Time(0);
175     return false;
176   }
177 
178   struct tm timestruct;
179   timestruct.tm_sec = exploded.second;
180   timestruct.tm_min = exploded.minute;
181   timestruct.tm_hour = exploded.hour;
182   timestruct.tm_mday = exploded.day_of_month;
183   timestruct.tm_mon = month.ValueOrDie();
184   timestruct.tm_year = year.ValueOrDie();
185   timestruct.tm_wday = exploded.day_of_week;  // mktime/timegm ignore this
186   timestruct.tm_yday = 0;                     // mktime/timegm ignore this
187   timestruct.tm_isdst = -1;                   // attempt to figure it out
188 #if !defined(OS_NACL) && !defined(OS_SOLARIS) && !defined(OS_AIX)
189   timestruct.tm_gmtoff = 0;   // not a POSIX field, so mktime/timegm ignore
190   timestruct.tm_zone = nullptr;  // not a POSIX field, so mktime/timegm ignore
191 #endif
192 
193   SysTime seconds;
194 
195   // Certain exploded dates do not really exist due to daylight saving times,
196   // and this causes mktime() to return implementation-defined values when
197   // tm_isdst is set to -1. On Android, the function will return -1, while the
198   // C libraries of other platforms typically return a liberally-chosen value.
199   // Handling this requires the special code below.
200 
201   // SysTimeFromTimeStruct() modifies the input structure, save current value.
202   struct tm timestruct0 = timestruct;
203 
204   seconds = SysTimeFromTimeStruct(&timestruct, is_local);
205   if (seconds == -1) {
206     // Get the time values with tm_isdst == 0 and 1, then select the closest one
207     // to UTC 00:00:00 that isn't -1.
208     timestruct = timestruct0;
209     timestruct.tm_isdst = 0;
210     int64_t seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
211 
212     timestruct = timestruct0;
213     timestruct.tm_isdst = 1;
214     int64_t seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
215 
216     // seconds_isdst0 or seconds_isdst1 can be -1 for some timezones.
217     // E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'.
218     if (seconds_isdst0 < 0)
219       seconds = seconds_isdst1;
220     else if (seconds_isdst1 < 0)
221       seconds = seconds_isdst0;
222     else
223       seconds = std::min(seconds_isdst0, seconds_isdst1);
224   }
225 
226   // Handle overflow.  Clamping the range to what mktime and timegm might
227   // return is the best that can be done here.  It's not ideal, but it's better
228   // than failing here or ignoring the overflow case and treating each time
229   // overflow as one second prior to the epoch.
230   int64_t milliseconds = 0;
231   if (seconds == -1 && (exploded.year < 1969 || exploded.year > 1970)) {
232     // If exploded.year is 1969 or 1970, take -1 as correct, with the
233     // time indicating 1 second prior to the epoch.  (1970 is allowed to handle
234     // time zone and DST offsets.)  Otherwise, return the most future or past
235     // time representable.  Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
236     //
237     // The minimum and maximum representible times that mktime and timegm could
238     // return are used here instead of values outside that range to allow for
239     // proper round-tripping between exploded and counter-type time
240     // representations in the presence of possible truncation to time_t by
241     // division and use with other functions that accept time_t.
242     //
243     // When representing the most distant time in the future, add in an extra
244     // 999ms to avoid the time being less than any other possible value that
245     // this function can return.
246 
247     // On Android, SysTime is int64_t, special care must be taken to avoid
248     // overflows.
249     const int64_t min_seconds = (sizeof(SysTime) < sizeof(int64_t))
250                                     ? std::numeric_limits<SysTime>::min()
251                                     : std::numeric_limits<int32_t>::min();
252     const int64_t max_seconds = (sizeof(SysTime) < sizeof(int64_t))
253                                     ? std::numeric_limits<SysTime>::max()
254                                     : std::numeric_limits<int32_t>::max();
255     if (exploded.year < 1969) {
256       milliseconds = min_seconds * kMillisecondsPerSecond;
257     } else {
258       milliseconds = max_seconds * kMillisecondsPerSecond;
259       milliseconds += (kMillisecondsPerSecond - 1);
260     }
261   } else {
262     base::CheckedNumeric<int64_t> checked_millis = seconds;
263     checked_millis *= kMillisecondsPerSecond;
264     checked_millis += exploded.millisecond;
265     if (!checked_millis.IsValid()) {
266       *time = base::Time(0);
267       return false;
268     }
269     milliseconds = checked_millis.ValueOrDie();
270   }
271 
272   // Adjust from Unix (1970) to Windows (1601) epoch avoiding overflows.
273   base::CheckedNumeric<int64_t> checked_microseconds_win_epoch = milliseconds;
274   checked_microseconds_win_epoch *= kMicrosecondsPerMillisecond;
275   checked_microseconds_win_epoch += kTimeTToMicrosecondsOffset;
276   if (!checked_microseconds_win_epoch.IsValid()) {
277     *time = base::Time(0);
278     return false;
279   }
280   base::Time converted_time(checked_microseconds_win_epoch.ValueOrDie());
281 
282   // If |exploded.day_of_month| is set to 31 on a 28-30 day month, it will
283   // return the first day of the next month. Thus round-trip the time and
284   // compare the initial |exploded| with |utc_to_exploded| time.
285   base::Time::Exploded to_exploded;
286   if (!is_local)
287     converted_time.UTCExplode(&to_exploded);
288   else
289     converted_time.LocalExplode(&to_exploded);
290 
291   if (ExplodedMostlyEquals(to_exploded, exploded)) {
292     *time = converted_time;
293     return true;
294   }
295 
296   *time = Time(0);
297   return false;
298 }
299 
300 }  // namespace base
301