Thomas Lockhart writes:
 > I haven't yet actually fixed the code, but will post patches when
 > I've done so (assuming that a fix is possible).

The normalization in this example program which subtracts 34 years
seems to work OK.  I've run it on AIX, IRIX, Linux and Solaris.  Some
examples follow.

AIX:
$ TZ=PST8PDT ago34 851995921
Local Mon Dec 30 17:32:01 1996 PST PST
      1996-12-30T17:32:01, wday=1, yday=364, isdst = 0
  UTC Tue Dec 31 01:32:01 1996 PST PST
      1996-12-31T01:32:01, wday=2, yday=365, isdst = 0
Local Sun Dec 30 17:32:01 1962 PST PST
      1962-12-30T17:32:01, wday=0, yday=363, isdst = 0
  UTC Mon Dec 31 01:32:01 1962 PST PST
      1962-12-31T01:32:01, wday=1, yday=364, isdst = 0

Linux:
$ TZ=America/Los_Angeles ago34 426475921
Local Thu Jul 07 18:32:01 1983 PDT -0700
      1983-07-07T18:32:01, wday=4, yday=187, isdst = 1
  UTC Fri Jul 08 01:32:01 1983 GMT +0000
      1983-07-08T01:32:01, wday=5, yday=188, isdst = 0
Local Thu Jul 07 18:32:01 1949 PST -0800
      1949-07-07T18:32:01, wday=4, yday=187, isdst = 0
  UTC Fri Jul 08 02:32:01 1949 GMT +0000
      1949-07-08T02:32:01, wday=5, yday=188, isdst = 0

Here is the program.  The call to localtime(&t_ago) is redundant and
hence the adjustment of t_ago can be skipped.  It is in this program
as a sanity check.

As it stands, this program assumes that the input and resulting date
are in the usual UNIX range of [1901, 2038].  I presume that there is
code in place that checks the range of dates.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void print_date(const char *label, const struct tm *tm);
int date_equals(const struct tm *a, const struct tm *b);

int main(int argc, char **argv)
{
    time_t t_in = 0, t_ago;
    struct tm local, utc, local2;

    if (argc == 2) {
        t_in = (time_t) strtol(argv[1], NULL, 0);
    }
    local = *localtime(&t_in);
    print_date("Local", &local);
    utc = *gmtime(&t_in);
    print_date("UTC", &utc);

    /* subtract an interval of 34 years */
    local.tm_year -= 34;

    /* Normalize */
    local.tm_isdst = -1;
    t_ago = mktime(&local);
    if (t_ago == -1 && local.tm_isdst == -1) {
        int n = (70 - local.tm_year + 27) / 28;
        local.tm_year += n * 28;
        t_ago = mktime(&local);
        if (t_ago == -1 && local.tm_isdst == -1) {
            printf("Warning, time may be wrong\n"); /* or call elog() */
        }
        local.tm_year -= n * 28;
        t_ago -= (365*4+1)*7*24*60*60*n; /* assumes 1901 <= year <= 2099 */
    }

    print_date("Local", &local);
    local2 = *localtime(&t_ago);  /* this should be redundant */
    if (!date_equals(&local, &local2)) {
        print_date("ERROR", &local2);
    }
    utc = *gmtime(&t_ago);
    print_date("UTC", &utc);

    return EXIT_SUCCESS;
}

void print_date(const char *label, const struct tm *tm)
{
    char buffer[80];

    strftime(buffer, sizeof buffer, "%a %b %d %H:%M:%S %Y %Z %z", tm);
    printf("%5s %s\n", label, buffer);
    printf("      %4d-%02d-%02dT%02d:%02d:%02d, wday=%d, yday=%d, isdst = %d\n",
           1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday,
           tm->tm_hour, tm->tm_min, tm->tm_sec,
           tm->tm_wday, tm->tm_yday, tm->tm_isdst);
}

/* return 1 if all fields of a are equal to those of b, otherwise 0 */
int date_equals(const struct tm *a, const struct tm *b)
{
    return a->tm_year  == b->tm_year
        && a->tm_mon   == b->tm_mon
        && a->tm_mday  == b->tm_mday
        && a->tm_hour  == b->tm_hour
        && a->tm_min   == b->tm_min
        && a->tm_sec   == b->tm_sec
        && a->tm_wday  == b->tm_wday
        && a->tm_yday  == b->tm_yday
        && a->tm_isdst == b->tm_isdst;
}




-- 
Pete Forman                 -./\.- Disclaimer: This post is originated
WesternGeco                   -./\.-  by myself and does not represent
[EMAIL PROTECTED]     -./\.-  opinion of Schlumberger, Baker
http://www.crosswinds.net/~petef  -./\.-  Hughes or their divisions.

Reply via email to