Home | History | Annotate | Download | only in time
      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, &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
    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