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. 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 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 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. 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 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 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 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 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 128 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, ×truct, 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 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(×truct, 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(×truct, is_local); 211 212 timestruct = timestruct0; 213 timestruct.tm_isdst = 1; 214 int64_t seconds_isdst1 = SysTimeFromTimeStruct(×truct, 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