Exemplo n.º 1
0
Time64_T mktime64(struct TM *input_date) {
  struct tm safe_date;
  struct TM date;
  Time64_T  time;
  Year      year = input_date->tm_year + 1900;

  if( date_in_safe_range(input_date, &SYSTEM_MKTIME_MIN, &SYSTEM_MKTIME_MAX) )
  {
    copy_TM64_to_tm(input_date, &safe_date);
    time = (Time64_T)mktime(&safe_date);

    /* Correct the possibly out of bound input date */
    copy_tm_to_TM64(&safe_date, input_date);
    TIME64_TRACE2("mktime64: safe year %ld, %"PRId64" seconds\n", (long)year, time);
    return time;
  }

  /* Have to make the year safe in date else it won't fit in safe_date */
  date = *input_date;
  date.tm_year = safe_year(year) - 1900;

  copy_TM64_to_tm(&date, &safe_date);
  time = (Time64_T)mktime(&safe_date);
  TIME64_TRACE1("mktime64: %"PRId64" seconds\n", time);

  /* Correct the user's possibly out of bound input date */
  copy_tm_to_TM64(&safe_date, input_date);

  time += seconds_between_years(year, (Year)(safe_date.tm_year + 1900));
  TIME64_TRACE1("mktime64 => %"PRId64" seconds\n", time);

  return time;
}
Exemplo n.º 2
0
static Time64_T seconds_between_years(Year left_year, Year right_year) {
  int increment = (left_year > right_year) ? 1 : -1;
  Time64_T seconds = 0;
  Year cycles;

  if( left_year > 2400 ) {
    TIME64_TRACE1("year %"PRId64" > 2400\n", left_year);
    cycles = (left_year - 2400) / 400;
    left_year -= cycles * 400;
    seconds   += cycles * seconds_in_gregorian_cycle;
  }
  else if( left_year < 1600 ) {
    TIME64_TRACE1("year %"PRId64" < 1600\n", left_year);
    cycles = (left_year - 1600) / 400;
    left_year += cycles * 400;
    seconds   += cycles * seconds_in_gregorian_cycle;
  }

  if (increment > 0) {
    TIME64_TRACE2("year %"PRId64" > safe_year %"PRId64"\n", left_year, right_year);
    while( left_year != right_year ) {
      seconds += length_of_year[IS_LEAP_ABS(right_year)] * 60 * 60 * 24;
      right_year++;
    }
    TIME64_TRACE1("adjust by %"PRId64" days\n", seconds / (60 * 60 * 24));
    return seconds;
  } else {
    TIME64_TRACE2("year %"PRId64" < safe_year %"PRId64"\n", left_year, right_year);
    while( left_year != right_year ) {
      seconds -= length_of_year[IS_LEAP_ABS(right_year)] * 60 * 60 * 24;
      right_year--;
    }
    TIME64_TRACE1("adjust by %"PRId64" days\n", seconds / (60 * 60 * 24));
    return seconds;
  }
}
Exemplo n.º 3
0
struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm)
{
    time_t safe_time;
    struct tm safe_date;
    struct TM gm_tm;
    Year orig_year;
    int month_diff;

    assert(local_tm != NULL);

    /* Use the system localtime() if time_t is small enough */
    if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
        safe_time = (time_t)*time;

        TIME64_TRACE1("Using system localtime for %lld\n", *time);

        LOCALTIME_R(&safe_time, &safe_date);

        copy_tm_to_TM64(&safe_date, local_tm);
        assert(check_tm(local_tm));

        return local_tm;
    }

    if( gmtime64_r(time, &gm_tm) == NULL ) {
        TIME64_TRACE1("gmtime64_r returned null for %lld\n", *time);
        return NULL;
    }

    orig_year = gm_tm.tm_year;

    if (gm_tm.tm_year > (2037 - 1900) ||
        gm_tm.tm_year < (1970 - 1900)
       )
    {
        TIME64_TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year);
        gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900;
    }

    safe_time = (time_t)timegm64(&gm_tm);
    if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) {
        TIME64_TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time);
        return NULL;
    }

    copy_tm_to_TM64(&safe_date, local_tm);

    local_tm->tm_year = orig_year;
    if( local_tm->tm_year != orig_year ) {
        TIME64_TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n",
              (Year)local_tm->tm_year, (Year)orig_year);

#ifdef EOVERFLOW
        errno = EOVERFLOW;
#endif
        return NULL;
    }


    month_diff = local_tm->tm_mon - gm_tm.tm_mon;

    /*  When localtime is Dec 31st previous year and
        gmtime is Jan 1st next year.
    */
    if( month_diff == 11 ) {
        local_tm->tm_year--;
    }

    /*  When localtime is Jan 1st, next year and
        gmtime is Dec 31st, previous year.
    */
    if( month_diff == -11 ) {
        local_tm->tm_year++;
    }

    /* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st 
       in a non-leap xx00.  There is one point in the cycle
       we can't account for which the safe xx00 year is a leap
       year.  So we need to correct for Dec 31st comming out as
       the 366th day of the year.
    */
    if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )
        local_tm->tm_yday--;

    assert(check_tm(local_tm));
    
    return local_tm;
}