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.