Commit 3c4b4c8c authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Check in a working cross-platform timegm


svn:r779
parent 3dddcf43
Loading
Loading
Loading
Loading
+28 −11
Original line number Diff line number Diff line
@@ -112,19 +112,36 @@ void tv_addms(struct timeval *a, long ms) {
  a->tv_usec %= 1000000;
}


#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400)))
static int n_leapdays(int y1, int y2) {
  --y1;
  --y2;
  return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400);
}
static const int days_per_month[] = 
  { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

time_t tor_timegm (struct tm *tm) {
  /* This is a pretty ironclad timegm implementation, snarfed from Python2.2. 
   * It's way more brute-force than fiddling with tzset().
   */
  time_t ret;
  char *tz;

  tz = getenv("TZ");
  setenv("TZ", "", 1);
  tzset();
  ret = mktime(tm);
  if (tz)
      setenv("TZ", tz, 1);
  else
      unsetenv("TZ");
  tzset();
  unsigned long year, days, hours, minutes;
  int i;
  year = tm->tm_year + 1900;
  assert(year >= 1970);
  assert(tm->tm_mon >= 0 && tm->tm_mon <= 11);
  days = 365 * (year-1970) + n_leapdays(1970,year);
  for (i = 0; i < tm->tm_mon; ++i)
    days += days_per_month[i];
  if (tm->tm_mon > 1 && IS_LEAPYEAR(year))
    ++days;
  days += tm->tm_mday - 1;
  hours = days*24 + tm->tm_hour;
  
  minutes = hours*60 + tm->tm_min;
  ret = minutes*60 + tm->tm_sec;
  return ret;
}

+15 −0
Original line number Diff line number Diff line
@@ -422,6 +422,7 @@ test_crypto()
void 
test_util() {
  struct timeval start, end;
  struct tm a_time;

  start.tv_sec = 5;
  start.tv_usec = 5000;
@@ -447,6 +448,20 @@ test_util() {

  test_eq(0L, tv_udiff(&start, &end));

  /* The test values here are confirmed to be correct on a platform
   * with a working timgm. */
  a_time.tm_year = 2003-1900;
  a_time.tm_mon = 7;
  a_time.tm_mday = 30;
  a_time.tm_hour = 6;
  a_time.tm_min = 14;
  a_time.tm_sec = 55;
  test_eq((time_t) 1062224095UL, tor_timegm(&a_time));
  a_time.tm_year = 2004-1900; /* Try a leap year, after feb. */
  test_eq((time_t) 1093846495UL, tor_timegm(&a_time));
  a_time.tm_mon = 1;          /* Try a leap year, in feb. */
  a_time.tm_mday = 10;
  test_eq((time_t) 1076393695UL, tor_timegm(&a_time));
}

void