diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 1764000e5e..2ae0fc5b21 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.167 2004/05/22 23:14:37 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.168 2004/06/03 02:08:00 tgl Exp $ * * NOTES * Transaction aborts can now occur two ways: @@ -141,6 +141,7 @@ #include "postgres.h" +#include #include #include "access/gistscan.h" @@ -1858,7 +1859,7 @@ xact_desc(char *buf, uint8 xl_info, char *rec) if (info == XLOG_XACT_COMMIT) { xl_xact_commit *xlrec = (xl_xact_commit *) rec; - struct pg_tm *tm = pg_localtime(&xlrec->xtime); + struct tm *tm = localtime(&xlrec->xtime); sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, @@ -1868,7 +1869,7 @@ xact_desc(char *buf, uint8 xl_info, char *rec) else if (info == XLOG_XACT_ABORT) { xl_xact_abort *xlrec = (xl_xact_abort *) rec; - struct pg_tm *tm = pg_localtime(&xlrec->xtime); + struct tm *tm = localtime(&xlrec->xtime); sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index cfb864d094..f120564061 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.145 2004/05/29 22:48:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.146 2004/06/03 02:08:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -2761,9 +2762,9 @@ str_time(time_t tnow) { static char buf[128]; - pg_strftime(buf, sizeof(buf), + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", - pg_localtime(&tnow)); + localtime(&tnow)); return buf; } diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 4047958b1d..cbc8ff6e53 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.68 2004/05/26 04:41:05 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.69 2004/06/03 02:08:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -38,7 +38,6 @@ #include "nodes/parsenodes.h" #include "nodes/pg_list.h" #include "nodes/primnodes.h" -#include "pgtime.h" #include "rewrite/prs2lock.h" #include "storage/block.h" #include "storage/fd.h" diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l index 3f8777ea66..57b872231d 100644 --- a/src/backend/bootstrap/bootscanner.l +++ b/src/backend/bootstrap/bootscanner.l @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/bootstrap/bootscanner.l,v 1.34 2004/05/21 05:07:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/bootstrap/bootscanner.l,v 1.35 2004/06/03 02:08:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,7 +29,6 @@ #include "nodes/pg_list.h" #include "nodes/primnodes.h" #include "parser/scansup.h" -#include "pgtime.h" #include "rewrite/prs2lock.h" #include "storage/block.h" #include "storage/fd.h" diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index a19217a47b..02f67339b1 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.182 2004/05/29 22:48:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.183 2004/06/03 02:08:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,7 +34,6 @@ #include "libpq/pqsignal.h" #include "miscadmin.h" #include "postmaster/bgwriter.h" -#include "pgtime.h" #include "storage/freespace.h" #include "storage/ipc.h" #include "storage/pg_shmem.h" diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c index 902fcbcd26..fe73a42ea0 100644 --- a/src/backend/optimizer/geqo/geqo_main.c +++ b/src/backend/optimizer/geqo/geqo_main.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.44 2004/05/21 05:07:57 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.45 2004/06/03 02:08:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,7 +31,6 @@ #include "optimizer/geqo_mutation.h" #include "optimizer/geqo_pool.h" #include "optimizer/geqo_selection.h" -#include "pgtime.h" /* diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 6bb683386a..f0ecb13d27 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -37,13 +37,14 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.2 2004/05/31 03:47:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.3 2004/06/03 02:08:03 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include +#include #include "access/xlog.h" #include "libpq/pqsignal.h" diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index c90749ca12..1a904cc8db 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2003, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.73 2004/05/29 22:48:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.74 2004/06/03 02:08:03 tgl Exp $ * ---------- */ #include "postgres.h" @@ -29,6 +29,7 @@ #include #include #include +#include #include "pgstat.h" diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 6a0cfbf052..85ba8309d4 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.401 2004/05/30 03:50:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.402 2004/06/03 02:08:03 tgl Exp $ * * NOTES * @@ -62,6 +62,7 @@ #include #include +#include #include #include #include @@ -97,7 +98,6 @@ #include "miscadmin.h" #include "nodes/nodes.h" #include "postmaster/postmaster.h" -#include "pgtime.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/pg_shmem.h" diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index b59bfb9543..b4702e7ceb 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -12,12 +12,14 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/buffer/freelist.c,v 1.43 2004/04/21 18:06:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/buffer/freelist.c,v 1.44 2004/06/03 02:08:03 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include + #include "access/xact.h" #include "storage/buf_internals.h" #include "storage/bufmgr.h" diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 556528d6d2..29d457e94e 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.417 2004/05/29 22:48:20 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.418 2004/06/03 02:08:03 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -46,7 +46,6 @@ #include "optimizer/planner.h" #include "parser/analyze.h" #include "parser/parser.h" -#include "pgtime.h" #include "rewrite/rewriteHandler.h" #include "storage/freespace.h" #include "storage/ipc.h" diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 91ef127a94..1caa68d774 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.98 2004/05/31 18:53:17 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.99 2004/06/03 02:08:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,7 +23,6 @@ #include "libpq/pqformat.h" #include "miscadmin.h" #include "parser/scansup.h" -#include "pgtime.h" #include "utils/builtins.h" #include "utils/date.h" #include "utils/nabstime.h" @@ -295,35 +294,22 @@ date2timestamptz(DateADT dateVal) TimestampTz result; struct pg_tm tt, *tm = &tt; + int tz; j2date(dateVal + POSTGRES_EPOCH_JDATE, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); - if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) - { - int tz; - - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - tz = DetermineLocalTimeZone(tm); + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + tz = DetermineLocalTimeZone(tm); #ifdef HAVE_INT64_TIMESTAMP - result = (dateVal * INT64CONST(86400000000)) - + (tz * INT64CONST(1000000)); + result = (dateVal * INT64CONST(86400000000)) + + (tz * INT64CONST(1000000)); #else - result = dateVal * 86400.0 + tz; + result = dateVal * 86400.0 + tz; #endif - } - else - { - /* Outside of range for timezone support, so assume UTC */ -#ifdef HAVE_INT64_TIMESTAMP - result = (dateVal * INT64CONST(86400000000)); -#else - result = dateVal * 86400.0; -#endif - } return result; } diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 4284e4c5e3..6fdefc536e 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.129 2004/05/31 18:53:17 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.130 2004/06/03 02:08:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -40,9 +40,11 @@ static int DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm); static void TrimTrailingZeros(char *str); -int day_tab[2][13] = { +const int day_tab[2][13] = +{ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}, -{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}}; + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0} +}; char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; @@ -1572,115 +1574,126 @@ DecodeDateTime(char **field, int *ftype, int nf, * (ie, regular or daylight-savings time) at that time. Set the struct pg_tm's * tm_isdst field accordingly, and return the actual timezone offset. * - * Note: this subroutine exists because mktime() has such a spectacular - * variety of, ahem, odd behaviors on various platforms. We used to try to - * use mktime() here, but finally gave it up as a bad job. Avoid using - * mktime() anywhere else. + * Note: it might seem that we should use mktime() for this, but bitter + * experience teaches otherwise. In particular, mktime() is generally + * incapable of coping reasonably with "impossible" times within a + * spring-forward DST transition. Typical implementations of mktime() + * turn out to be loops around localtime() anyway, so they're not even + * any faster than this code. */ int -DetermineLocalTimeZone(struct pg_tm * tm) +DetermineLocalTimeZone(struct pg_tm *tm) { int tz; + int date, + sec; + pg_time_t day, + mysec, + locsec, + delta1, + delta2; + struct pg_tm *tx; if (HasCTZSet) { tm->tm_isdst = 0; /* for lack of a better idea */ - tz = CTimeZone; + return CTimeZone; } - else if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) + + /* + * First, generate the pg_time_t value corresponding to the given + * y/m/d/h/m/s taken as GMT time. If this overflows, punt and + * decide the timezone is GMT. (We only need to worry about overflow + * on machines where pg_time_t is 32 bits.) + */ + if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday)) + goto overflow; + date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE; + day = ((pg_time_t) date) * 86400; + if (day / 86400 != date) + goto overflow; + sec = tm->tm_sec + (tm->tm_min + tm->tm_hour * 60) * 60; + mysec = day + sec; + /* since sec >= 0, overflow could only be from +day to -mysec */ + if (mysec < 0 && day > 0) + goto overflow; + + /* + * Use pg_localtime to convert that pg_time_t to broken-down time, + * and reassemble to get a representation of local time. (We could get + * overflow of a few hours in the result, but the delta calculation + * should still work.) + */ + tx = pg_localtime(&mysec); + if (!tx) + goto overflow; /* probably can't happen */ + day = date2j(tx->tm_year + 1900, tx->tm_mon + 1, tx->tm_mday) - + UNIX_EPOCH_JDATE; + locsec = tx->tm_sec + (tx->tm_min + (day * 24 + tx->tm_hour) * 60) * 60; + + /* + * The local time offset corresponding to that GMT time is now + * computable as mysec - locsec. + */ + delta1 = mysec - locsec; + + /* + * However, if that GMT time and the local time we are + * actually interested in are on opposite sides of a + * daylight-savings-time transition, then this is not the time + * offset we want. So, adjust the pg_time_t to be what we think + * the GMT time corresponding to our target local time is, and + * repeat the pg_localtime() call and delta calculation. + * + * We have to watch out for overflow while adjusting the pg_time_t. + */ + if ((delta1 < 0) ? (mysec < 0 && (mysec + delta1) > 0) : + (mysec > 0 && (mysec + delta1) < 0)) + goto overflow; + mysec += delta1; + tx = pg_localtime(&mysec); + if (!tx) + goto overflow; /* probably can't happen */ + day = date2j(tx->tm_year + 1900, tx->tm_mon + 1, tx->tm_mday) - + UNIX_EPOCH_JDATE; + locsec = tx->tm_sec + (tx->tm_min + (day * 24 + tx->tm_hour) * 60) * 60; + delta2 = mysec - locsec; + + /* + * We may have to do it again to get the correct delta. + * + * It might seem we should just loop until we get the same delta + * twice in a row, but if we've been given an "impossible" local + * time (in the gap during a spring-forward transition) we'd never + * get out of the loop. The behavior we want is that "impossible" + * times are taken as standard time, and also that ambiguous times + * (during a fall-back transition) are taken as standard time. + * Therefore, we bias the code to prefer the standard-time solution. + */ + if (delta2 != delta1 && tx->tm_isdst != 0) { - /* - * First, generate the time_t value corresponding to the given - * y/m/d/h/m/s taken as GMT time. This will not overflow (at - * least not for time_t taken as signed) because of the range - * check we did above. - */ - long day, - mysec, - locsec, - delta1, - delta2; - time_t mytime; - struct pg_tm *tx; - - day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE; - mysec = tm->tm_sec + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60; - mytime = (time_t) mysec; - - /* - * Use localtime to convert that time_t to broken-down time, - * and reassemble to get a representation of local time. - */ - tx = pg_localtime(&mytime); + delta2 -= delta1; + if ((delta2 < 0) ? (mysec < 0 && (mysec + delta2) > 0) : + (mysec > 0 && (mysec + delta2) < 0)) + goto overflow; + mysec += delta2; + tx = pg_localtime(&mysec); if (!tx) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); - day = date2j(tx->tm_year + 1900, tx->tm_mon + 1, tx->tm_mday) - - UNIX_EPOCH_JDATE; - locsec = tx->tm_sec + (tx->tm_min + (day * 24 + tx->tm_hour) * 60) * 60; - - /* - * The local time offset corresponding to that GMT time is now - * computable as mysec - locsec. - */ - delta1 = mysec - locsec; - /* - * However, if that GMT time and the local time we are - * actually interested in are on opposite sides of a - * daylight-savings-time transition, then this is not the time - * offset we want. So, adjust the time_t to be what we think - * the GMT time corresponding to our target local time is, and - * repeat the localtime() call and delta calculation. - */ - mysec += delta1; - mytime = (time_t) mysec; - tx = pg_localtime(&mytime); - if (!tx) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); + goto overflow; /* probably can't happen */ day = date2j(tx->tm_year + 1900, tx->tm_mon + 1, tx->tm_mday) - UNIX_EPOCH_JDATE; locsec = tx->tm_sec + (tx->tm_min + (day * 24 + tx->tm_hour) * 60) * 60; delta2 = mysec - locsec; - - /* - * We may have to do it again to get the correct delta. - * - * It might seem we should just loop until we get the same delta - * twice in a row, but if we've been given an "impossible" local - * time (in the gap during a spring-forward transition) we'd never - * get out of the loop. The behavior we want is that "impossible" - * times are taken as standard time, and also that ambiguous times - * (during a fall-back transition) are taken as standard time. - * Therefore, we bias the code to prefer the standard-time solution. - */ - if (delta2 != delta1 && tx->tm_isdst != 0) - { - mysec += (delta2 - delta1); - mytime = (time_t) mysec; - tx = pg_localtime(&mytime); - if (!tx) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); - day = date2j(tx->tm_year + 1900, tx->tm_mon + 1, tx->tm_mday) - - UNIX_EPOCH_JDATE; - locsec = tx->tm_sec + (tx->tm_min + (day * 24 + tx->tm_hour) * 60) * 60; - delta2 = mysec - locsec; - } - tm->tm_isdst = tx->tm_isdst; - tz = (int) delta2; - } - else - { - /* Given date is out of range, so assume UTC */ - tm->tm_isdst = 0; - tz = 0; } + tm->tm_isdst = tx->tm_isdst; + tz = (int) delta2; return tz; + +overflow: + /* Given date is out of range, so assume UTC */ + tm->tm_isdst = 0; + return 0; } diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index 0443072e8e..8353fa2658 100644 --- a/src/backend/utils/adt/nabstime.c +++ b/src/backend/utils/adt/nabstime.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.122 2004/05/21 16:08:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.123 2004/06/03 02:08:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "access/xact.h" @@ -179,7 +180,7 @@ GetCurrentTimeUsec(struct pg_tm * tm, fsec_t *fsec, int *tzp) void abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn) { - time_t time = (time_t) _time; + pg_time_t time = (pg_time_t) _time; struct pg_tm *tx; /* @@ -1667,12 +1668,12 @@ timeofday(PG_FUNCTION_ARGS) char buf[128]; text *result; int len; - time_t tt; + pg_time_t tt; gettimeofday(&tp, &tpz); - tt = (time_t) tp.tv_sec; + tt = (pg_time_t) tp.tv_sec; pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z", - pg_localtime(&tt)); + pg_localtime(&tt)); snprintf(buf, sizeof(buf), templ, tp.tv_usec); len = VARHDRSZ + strlen(buf); diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index d40715b7e4..91a34ed538 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.107 2004/05/31 18:31:51 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.108 2004/06/03 02:08:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -921,16 +921,14 @@ dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec) } /* dt2time() */ -/* timestamp2tm() - * Convert timestamp data type to POSIX time structure. +/* + * timestamp2tm() - Convert timestamp data type to POSIX time structure. + * * Note that year is _not_ 1900-based, but is an explicit full value. * Also, month is one-based, _not_ zero-based. * Returns: * 0 on success * -1 on out of range - * - * For dates within the system-supported time_t range, convert to the - * local time zone. If out of this range, leave as GMT. - tgl 97/05/27 */ int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, char **tzn) @@ -942,8 +940,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, char **tzn) double date; double time; #endif - time_t utime; - struct pg_tm *tx; + pg_time_t utime; /* * If HasCTZSet is true then we have a brute force time zone @@ -988,70 +985,77 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, char **tzn) j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); - if (tzp != NULL) + /* Done if no TZ conversion wanted */ + if (tzp == NULL) { - /* - * We have a brute force time zone per SQL99? Then use it without - * change since we have already rotated to the time zone. - */ - if (HasCTZSet) - { - *tzp = CTimeZone; - tm->tm_isdst = 0; - tm->tm_gmtoff = CTimeZone; - tm->tm_zone = NULL; - if (tzn != NULL) - *tzn = NULL; - } + tm->tm_isdst = -1; + tm->tm_gmtoff = 0; + tm->tm_zone = NULL; + if (tzn != NULL) + *tzn = NULL; + return 0; + } - /* - * Does this fall within the capabilities of the localtime() - * interface? Then use this to rotate to the local time zone. - */ - else if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) - { - /* - * Convert to integer, avoiding platform-specific - * roundoff-in-wrong-direction errors, and adjust to - * Unix epoch. Note we have to do this in one step - * because the intermediate result before adjustment - * won't necessarily fit in an int32. - */ + /* + * We have a brute force time zone per SQL99? Then use it without + * change since we have already rotated to the time zone. + */ + if (HasCTZSet) + { + *tzp = CTimeZone; + tm->tm_isdst = 0; + tm->tm_gmtoff = CTimeZone; + tm->tm_zone = NULL; + if (tzn != NULL) + *tzn = NULL; + return 0; + } + + /* + * If the time falls within the range of pg_time_t, use pg_localtime() + * to rotate to the local time zone. + * + * First, convert to an integral timestamp, avoiding possibly + * platform-specific roundoff-in-wrong-direction errors, and adjust to + * Unix epoch. Then see if we can convert to pg_time_t without loss. + * This coding avoids hardwiring any assumptions about the width of + * pg_time_t, so it should behave sanely on machines without int64. + */ #ifdef HAVE_INT64_TIMESTAMP - utime = (dt - *fsec) / INT64CONST(1000000) + - (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400; + dt = (dt - *fsec) / INT64CONST(1000000) + + (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400; #else - utime = rint(dt - *fsec + - (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400); + dt = rint(dt - *fsec + + (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400); #endif + utime = (pg_time_t) dt; + if ((Timestamp) utime == dt) + { + struct pg_tm *tx = pg_localtime(&utime); - tx = pg_localtime(&utime); - tm->tm_year = tx->tm_year + 1900; - tm->tm_mon = tx->tm_mon + 1; - tm->tm_mday = tx->tm_mday; - tm->tm_hour = tx->tm_hour; - tm->tm_min = tx->tm_min; - tm->tm_sec = tx->tm_sec; - tm->tm_isdst = tx->tm_isdst; - tm->tm_gmtoff = tx->tm_gmtoff; - tm->tm_zone = tx->tm_zone; - - *tzp = -(tm->tm_gmtoff); - if (tzn != NULL) - *tzn = (char *) tm->tm_zone; - } - else - { - *tzp = 0; - /* Mark this as *no* time zone available */ - tm->tm_isdst = -1; - if (tzn != NULL) - *tzn = NULL; - } + tm->tm_year = tx->tm_year + 1900; + tm->tm_mon = tx->tm_mon + 1; + tm->tm_mday = tx->tm_mday; + tm->tm_hour = tx->tm_hour; + tm->tm_min = tx->tm_min; + tm->tm_sec = tx->tm_sec; + tm->tm_isdst = tx->tm_isdst; + tm->tm_gmtoff = tx->tm_gmtoff; + tm->tm_zone = tx->tm_zone; + *tzp = -(tm->tm_gmtoff); + if (tzn != NULL) + *tzn = (char *) tm->tm_zone; } else { + /* + * When out of range of pg_time_t, treat as GMT + */ + *tzp = 0; + /* Mark this as *no* time zone available */ tm->tm_isdst = -1; + tm->tm_gmtoff = 0; + tm->tm_zone = NULL; if (tzn != NULL) *tzn = NULL; } @@ -1224,7 +1228,7 @@ void GetEpochTime(struct pg_tm * tm) { struct pg_tm *t0; - time_t epoch = 0; + pg_time_t epoch = 0; t0 = pg_gmtime(&epoch); @@ -1235,12 +1239,9 @@ GetEpochTime(struct pg_tm * tm) tm->tm_min = t0->tm_min; tm->tm_sec = t0->tm_sec; - if (tm->tm_year < 1900) - tm->tm_year += 1900; + tm->tm_year += 1900; tm->tm_mon++; - - return; -} /* GetEpochTime() */ +} Timestamp SetEpochTimestamp(void) diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index e3adab8297..dc881a0067 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.139 2004/05/29 22:48:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.140 2004/06/03 02:08:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -56,7 +57,6 @@ #include "libpq/pqformat.h" #include "mb/pg_wchar.h" #include "miscadmin.h" -#include "pgtime.h" #include "postmaster/postmaster.h" #include "storage/ipc.h" #include "tcop/tcopprot.h" @@ -1217,8 +1217,9 @@ log_line_prefix(StringInfo buf) time_t stamp_time = time(NULL); char strfbuf[128]; - pg_strftime(strfbuf, sizeof(strfbuf), "%Y-%m-%d %H:%M:%S %Z", - pg_localtime(&stamp_time)); + strftime(strfbuf, sizeof(strfbuf), + "%Y-%m-%d %H:%M:%S %Z", + localtime(&stamp_time)); appendStringInfoString(buf, strfbuf); } break; @@ -1228,8 +1229,9 @@ log_line_prefix(StringInfo buf) time_t stamp_time = MyProcPort->session_start.tv_sec; char strfbuf[128]; - pg_strftime(strfbuf, sizeof(strfbuf), "%Y-%m-%d %H:%M:%S %Z", - pg_localtime(&stamp_time)); + strftime(strfbuf, sizeof(strfbuf), + "%Y-%m-%d %H:%M:%S %Z", + localtime(&stamp_time)); appendStringInfoString(buf, strfbuf); } break; diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index a4aba75985..2319da9b8e 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -8,15 +8,16 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.14 2004/05/21 05:08:04 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.15 2004/06/03 02:08:05 tgl Exp $ * *------------------------------------------------------------------------- */ #ifndef PG_CONTROL_H #define PG_CONTROL_H +#include + #include "access/xlogdefs.h" -#include "pgtime.h" #include "utils/pg_crc.h" diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 1a3f759840..8b1a15ee5a 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.53 2004/05/21 16:22:38 tgl Exp $ + * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.54 2004/06/03 02:08:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,7 +27,6 @@ #include "catalog/pg_statistic.h" #include "catalog/pg_type.h" #include "nodes/parsenodes.h" -#include "pgtime.h" #include "utils/rel.h" diff --git a/src/include/pgtime.h b/src/include/pgtime.h index 8493c8c6f7..e772d76bd7 100644 --- a/src/include/pgtime.h +++ b/src/include/pgtime.h @@ -6,50 +6,29 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/include/pgtime.h,v 1.1 2004/05/21 05:08:03 tgl Exp $ + * $PostgreSQL: pgsql/src/include/pgtime.h,v 1.2 2004/06/03 02:08:06 tgl Exp $ * *------------------------------------------------------------------------- */ #ifndef _PGTIME_H #define _PGTIME_H -#ifdef FRONTEND - -/* Don't mess with anything for the frontends */ -#include - -#else - -/* - * Redefine functions and defines we implement, so we cause an - * error if someone tries to use the "base functions" - */ -#ifndef NO_REDEFINE_TIMEFUNCS -#define localtime DONOTUSETHIS_localtime -#define gmtime DONOTUSETHIS_gmtime -#define asctime DONOTUSETHIS_asctime -#define ctime DONOTUSETHIS_ctime -#define tzset DONOTUSETHIS_tzset -#define mktime DONOTUSETHIS_mktime -#define tzname DONOTUSETHIS_tzname -#define daylight DONOTUSETHIS_daylight -#define strftime DONOTUSETHIS_strftime -#endif - -/* Then pull in default declarations, particularly time_t */ -#include /* - * Now define prototype for our own timezone implementation - * structs and functions. + * The API of this library is generally similar to the corresponding + * C library functions, except that we use pg_time_t which (we hope) is + * 64 bits wide, and which is most definitely signed not unsigned. */ + +typedef int64 pg_time_t; + struct pg_tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; - int tm_mon; - int tm_year; + int tm_mon; /* origin 0, not 1 */ + int tm_year; /* relative to 1900 */ int tm_wday; int tm_yday; int tm_isdst; @@ -57,9 +36,8 @@ struct pg_tm { const char *tm_zone; }; -extern struct pg_tm *pg_localtime(const time_t *); -extern struct pg_tm *pg_gmtime(const time_t *); -extern time_t pg_mktime(struct pg_tm *); +extern struct pg_tm *pg_localtime(const pg_time_t *); +extern struct pg_tm *pg_gmtime(const pg_time_t *); extern bool pg_tzset(const char *tzname); extern size_t pg_strftime(char *s, size_t max, const char *format, const struct pg_tm *tm); @@ -68,6 +46,4 @@ extern bool tz_acceptable(void); extern const char *select_default_timezone(void); extern const char *pg_get_current_timezone(void); -#endif /* FRONTEND */ - #endif /* _PGTIME_H */ diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index 35eec95eeb..1dd379fd21 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.48 2004/05/21 05:08:05 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.49 2004/06/03 02:08:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,7 +19,6 @@ #include #include -#include "pgtime.h" #include "utils/timestamp.h" @@ -232,10 +231,11 @@ do { \ * Include check for leap year. */ -extern int day_tab[2][13]; +extern const int day_tab[2][13]; #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + /* Julian date support for date2j() and j2date() * * IS_VALID_JULIAN checks the minimum date exactly, but is a bit sloppy @@ -257,24 +257,6 @@ extern int day_tab[2][13]; #define UNIX_EPOCH_JDATE 2440588 /* == date2j(1970, 1, 1) */ #define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */ -/* - * Info about limits of the Unix time_t data type. We assume that time_t - * is a signed int32 with origin 1970-01-01. Note this is only relevant - * when we use the C library's time routines for timezone processing. - */ -#define UTIME_MINYEAR (1901) -#define UTIME_MINMONTH (12) -#define UTIME_MINDAY (14) -#define UTIME_MAXYEAR (2038) -#define UTIME_MAXMONTH (01) -#define UTIME_MAXDAY (18) - -#define IS_VALID_UTIME(y,m,d) ((((y) > UTIME_MINYEAR) \ - || (((y) == UTIME_MINYEAR) && (((m) > UTIME_MINMONTH) \ - || (((m) == UTIME_MINMONTH) && ((d) >= UTIME_MINDAY))))) \ - && (((y) < UTIME_MAXYEAR) \ - || (((y) == UTIME_MAXYEAR) && (((m) < UTIME_MAXMONTH) \ - || (((m) == UTIME_MAXMONTH) && ((d) <= UTIME_MAXDAY)))))) /* * Datetime input parsing routines (ParseDateTime, DecodeDateTime, etc) diff --git a/src/include/utils/nabstime.h b/src/include/utils/nabstime.h index 704e7de583..914dd9ebd7 100644 --- a/src/include/utils/nabstime.h +++ b/src/include/utils/nabstime.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/nabstime.h,v 1.42 2004/05/21 05:08:05 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/nabstime.h,v 1.43 2004/06/03 02:08:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,7 +17,6 @@ #include #include "fmgr.h" -#include "pgtime.h" #include "utils/timestamp.h" #include "utils/datetime.h" @@ -28,9 +27,10 @@ * * ---------------------------------------------------------------- */ + /* * Although time_t generally is a long int on 64 bit systems, these two - * types must be 4 bytes, because that's what the system assumes. They + * types must be 4 bytes, because that's what pg_type.h assumes. They * should be yanked (long) before 2038 and be replaced by timestamp and * interval. */ diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out index b135eb5b91..4523947b56 100644 --- a/src/test/regress/expected/horology.out +++ b/src/test/regress/expected/horology.out @@ -672,15 +672,15 @@ SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL; | Sat Feb 14 17:32:01 1998 PST | Sun Feb 15 17:32:01 1998 PST | Mon Feb 16 17:32:01 1998 PST - | Thu Feb 16 17:32:01 0096 BC - | Sun Feb 16 17:32:01 0098 - | Fri Feb 16 17:32:01 0598 - | Wed Feb 16 17:32:01 1098 - | Sun Feb 16 17:32:01 1698 - | Fri Feb 16 17:32:01 1798 - | Wed Feb 16 17:32:01 1898 + | Thu Feb 16 17:32:01 0096 BC PST + | Sun Feb 16 17:32:01 0098 PST + | Fri Feb 16 17:32:01 0598 PST + | Wed Feb 16 17:32:01 1098 PST + | Sun Feb 16 17:32:01 1698 PST + | Fri Feb 16 17:32:01 1798 PST + | Wed Feb 16 17:32:01 1898 PST | Mon Feb 16 17:32:01 1998 PST - | Sun Feb 16 17:32:01 2098 + | Sun Feb 16 17:32:01 2098 PST | Fri Feb 28 17:32:01 1997 PST | Fri Feb 28 17:32:01 1997 PST | Sat Mar 01 17:32:01 1997 PST @@ -741,15 +741,15 @@ SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL; | Wed Feb 14 17:32:01 1996 PST | Thu Feb 15 17:32:01 1996 PST | Fri Feb 16 17:32:01 1996 PST - | Mon Feb 16 17:32:01 0098 BC - | Thu Feb 16 17:32:01 0096 - | Tue Feb 16 17:32:01 0596 - | Sun Feb 16 17:32:01 1096 - | Thu Feb 16 17:32:01 1696 - | Tue Feb 16 17:32:01 1796 - | Sun Feb 16 17:32:01 1896 + | Mon Feb 16 17:32:01 0098 BC PST + | Thu Feb 16 17:32:01 0096 PST + | Tue Feb 16 17:32:01 0596 PST + | Sun Feb 16 17:32:01 1096 PST + | Thu Feb 16 17:32:01 1696 PST + | Tue Feb 16 17:32:01 1796 PST + | Sun Feb 16 17:32:01 1896 PST | Fri Feb 16 17:32:01 1996 PST - | Thu Feb 16 17:32:01 2096 + | Thu Feb 16 17:32:01 2096 PST | Tue Feb 28 17:32:01 1995 PST | Tue Feb 28 17:32:01 1995 PST | Wed Mar 01 17:32:01 1995 PST diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out index 7557bf2900..d6f14ff6ef 100644 --- a/src/test/regress/expected/timestamp.out +++ b/src/test/regress/expected/timestamp.out @@ -1327,15 +1327,15 @@ SELECT '' AS to_char_9, to_char(d1, 'YYYY A.D. YYYY a.d. YYYY bc HH:MI:SS P.M. H -- TO_TIMESTAMP() SELECT '' AS to_timestamp_1, to_timestamp('0097/Feb/16 --> 08:14:30', 'YYYY/Mon/DD --> HH:MI:SS'); - to_timestamp_1 | to_timestamp -----------------+-------------------------- - | Sat Feb 16 08:14:30 0097 + to_timestamp_1 | to_timestamp +----------------+------------------------------ + | Sat Feb 16 08:14:30 0097 PST (1 row) SELECT '' AS to_timestamp_2, to_timestamp('97/2/16 8:14:30', 'FMYYYY/FMMM/FMDD FMHH:FMMI:FMSS'); - to_timestamp_2 | to_timestamp -----------------+-------------------------- - | Sat Feb 16 08:14:30 0097 + to_timestamp_2 | to_timestamp +----------------+------------------------------ + | Sat Feb 16 08:14:30 0097 PST (1 row) SELECT '' AS to_timestamp_3, to_timestamp('1985 January 12', 'YYYY FMMonth DD'); @@ -1352,9 +1352,9 @@ SELECT '' AS to_timestamp_4, to_timestamp('My birthday-> Year: 1976, Month: May, (1 row) SELECT '' AS to_timestamp_5, to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD'); - to_timestamp_5 | to_timestamp -----------------+-------------------------- - | Sat Aug 21 00:00:00 1582 + to_timestamp_5 | to_timestamp +----------------+------------------------------ + | Sat Aug 21 00:00:00 1582 PST (1 row) SELECT '' AS to_timestamp_6, to_timestamp('15 "text between quote marks" 98 54 45', @@ -1386,9 +1386,9 @@ SELECT '' AS to_timestamp_10, to_timestamp('19971116', 'YYYYMMDD'); (1 row) SELECT '' AS to_timestamp_11, to_timestamp('20000-1116', 'YYYY-MMDD'); - to_timestamp_11 | to_timestamp ------------------+--------------------------- - | Thu Nov 16 00:00:00 20000 + to_timestamp_11 | to_timestamp +-----------------+------------------------------- + | Thu Nov 16 00:00:00 20000 PST (1 row) SELECT '' AS to_timestamp_12, to_timestamp('9-1116', 'Y-MMDD'); diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out index 8a9bccf0a3..c07604ff72 100644 --- a/src/test/regress/expected/timestamptz.out +++ b/src/test/regress/expected/timestamptz.out @@ -180,15 +180,15 @@ SELECT '' AS "64", d1 FROM TIMESTAMPTZ_TBL; | Fri Feb 14 17:32:01 1997 PST | Sat Feb 15 17:32:01 1997 PST | Sun Feb 16 17:32:01 1997 PST - | Tue Feb 16 17:32:01 0097 BC - | Sat Feb 16 17:32:01 0097 - | Thu Feb 16 17:32:01 0597 - | Tue Feb 16 17:32:01 1097 - | Sat Feb 16 17:32:01 1697 - | Thu Feb 16 17:32:01 1797 - | Tue Feb 16 17:32:01 1897 + | Tue Feb 16 17:32:01 0097 BC PST + | Sat Feb 16 17:32:01 0097 PST + | Thu Feb 16 17:32:01 0597 PST + | Tue Feb 16 17:32:01 1097 PST + | Sat Feb 16 17:32:01 1697 PST + | Thu Feb 16 17:32:01 1797 PST + | Tue Feb 16 17:32:01 1897 PST | Sun Feb 16 17:32:01 1997 PST - | Sat Feb 16 17:32:01 2097 + | Sat Feb 16 17:32:01 2097 PST | Wed Feb 28 17:32:01 1996 PST | Thu Feb 29 17:32:01 1996 PST | Fri Mar 01 17:32:01 1996 PST @@ -249,7 +249,7 @@ SELECT '' AS "48", d1 FROM TIMESTAMPTZ_TBL | Sat Feb 15 17:32:01 1997 PST | Sun Feb 16 17:32:01 1997 PST | Sun Feb 16 17:32:01 1997 PST - | Sat Feb 16 17:32:01 2097 + | Sat Feb 16 17:32:01 2097 PST | Fri Feb 28 17:32:01 1997 PST | Sat Mar 01 17:32:01 1997 PST | Tue Dec 30 17:32:01 1997 PST @@ -262,17 +262,17 @@ SELECT '' AS "48", d1 FROM TIMESTAMPTZ_TBL SELECT '' AS "15", d1 FROM TIMESTAMPTZ_TBL WHERE d1 < timestamp with time zone '1997-01-02'; - 15 | d1 -----+------------------------------ + 15 | d1 +----+--------------------------------- | -infinity | Wed Dec 31 16:00:00 1969 PST - | Tue Feb 16 17:32:01 0097 BC - | Sat Feb 16 17:32:01 0097 - | Thu Feb 16 17:32:01 0597 - | Tue Feb 16 17:32:01 1097 - | Sat Feb 16 17:32:01 1697 - | Thu Feb 16 17:32:01 1797 - | Tue Feb 16 17:32:01 1897 + | Tue Feb 16 17:32:01 0097 BC PST + | Sat Feb 16 17:32:01 0097 PST + | Thu Feb 16 17:32:01 0597 PST + | Tue Feb 16 17:32:01 1097 PST + | Sat Feb 16 17:32:01 1697 PST + | Thu Feb 16 17:32:01 1797 PST + | Tue Feb 16 17:32:01 1897 PST | Wed Feb 28 17:32:01 1996 PST | Thu Feb 29 17:32:01 1996 PST | Fri Mar 01 17:32:01 1996 PST @@ -332,15 +332,15 @@ SELECT '' AS "63", d1 FROM TIMESTAMPTZ_TBL | Fri Feb 14 17:32:01 1997 PST | Sat Feb 15 17:32:01 1997 PST | Sun Feb 16 17:32:01 1997 PST - | Tue Feb 16 17:32:01 0097 BC - | Sat Feb 16 17:32:01 0097 - | Thu Feb 16 17:32:01 0597 - | Tue Feb 16 17:32:01 1097 - | Sat Feb 16 17:32:01 1697 - | Thu Feb 16 17:32:01 1797 - | Tue Feb 16 17:32:01 1897 + | Tue Feb 16 17:32:01 0097 BC PST + | Sat Feb 16 17:32:01 0097 PST + | Thu Feb 16 17:32:01 0597 PST + | Tue Feb 16 17:32:01 1097 PST + | Sat Feb 16 17:32:01 1697 PST + | Thu Feb 16 17:32:01 1797 PST + | Tue Feb 16 17:32:01 1897 PST | Sun Feb 16 17:32:01 1997 PST - | Sat Feb 16 17:32:01 2097 + | Sat Feb 16 17:32:01 2097 PST | Wed Feb 28 17:32:01 1996 PST | Thu Feb 29 17:32:01 1996 PST | Fri Mar 01 17:32:01 1996 PST @@ -359,18 +359,18 @@ SELECT '' AS "63", d1 FROM TIMESTAMPTZ_TBL SELECT '' AS "16", d1 FROM TIMESTAMPTZ_TBL WHERE d1 <= timestamp with time zone '1997-01-02'; - 16 | d1 -----+------------------------------ + 16 | d1 +----+--------------------------------- | -infinity | Wed Dec 31 16:00:00 1969 PST | Thu Jan 02 00:00:00 1997 PST - | Tue Feb 16 17:32:01 0097 BC - | Sat Feb 16 17:32:01 0097 - | Thu Feb 16 17:32:01 0597 - | Tue Feb 16 17:32:01 1097 - | Sat Feb 16 17:32:01 1697 - | Thu Feb 16 17:32:01 1797 - | Tue Feb 16 17:32:01 1897 + | Tue Feb 16 17:32:01 0097 BC PST + | Sat Feb 16 17:32:01 0097 PST + | Thu Feb 16 17:32:01 0597 PST + | Tue Feb 16 17:32:01 1097 PST + | Sat Feb 16 17:32:01 1697 PST + | Thu Feb 16 17:32:01 1797 PST + | Tue Feb 16 17:32:01 1897 PST | Wed Feb 28 17:32:01 1996 PST | Thu Feb 29 17:32:01 1996 PST | Fri Mar 01 17:32:01 1996 PST @@ -423,7 +423,7 @@ SELECT '' AS "49", d1 FROM TIMESTAMPTZ_TBL | Sat Feb 15 17:32:01 1997 PST | Sun Feb 16 17:32:01 1997 PST | Sun Feb 16 17:32:01 1997 PST - | Sat Feb 16 17:32:01 2097 + | Sat Feb 16 17:32:01 2097 PST | Fri Feb 28 17:32:01 1997 PST | Sat Mar 01 17:32:01 1997 PST | Tue Dec 30 17:32:01 1997 PST @@ -1395,16 +1395,16 @@ SELECT '' AS to_char_10, to_char(d1, 'YYYY WW IYYY IYY IY I IW') -- TO_TIMESTAMP() SELECT '' AS to_timestamp_1, to_timestamp('0097/Feb/16 --> 08:14:30', 'YYYY/Mon/DD --> HH:MI:SS'); - to_timestamp_1 | to_timestamp -----------------+-------------------------- - | Sat Feb 16 08:14:30 0097 + to_timestamp_1 | to_timestamp +----------------+------------------------------ + | Sat Feb 16 08:14:30 0097 PST (1 row) SELECT '' AS to_timestamp_2, to_timestamp('97/2/16 8:14:30', 'FMYYYY/FMMM/FMDD FMHH:FMMI:FMSS'); - to_timestamp_2 | to_timestamp -----------------+-------------------------- - | Sat Feb 16 08:14:30 0097 + to_timestamp_2 | to_timestamp +----------------+------------------------------ + | Sat Feb 16 08:14:30 0097 PST (1 row) SELECT '' AS to_timestamp_3, to_timestamp('1985 January 12', 'YYYY FMMonth DD'); @@ -1421,9 +1421,9 @@ SELECT '' AS to_timestamp_4, to_timestamp('My birthday-> Year: 1976, Month: May, (1 row) SELECT '' AS to_timestamp_5, to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD'); - to_timestamp_5 | to_timestamp -----------------+-------------------------- - | Sat Aug 21 00:00:00 1582 + to_timestamp_5 | to_timestamp +----------------+------------------------------ + | Sat Aug 21 00:00:00 1582 PST (1 row) SELECT '' AS to_timestamp_6, to_timestamp('15 "text between quote marks" 98 54 45', @@ -1455,9 +1455,9 @@ SELECT '' AS to_timestamp_10, to_timestamp('19971116', 'YYYYMMDD'); (1 row) SELECT '' AS to_timestamp_11, to_timestamp('20000-1116', 'YYYY-MMDD'); - to_timestamp_11 | to_timestamp ------------------+--------------------------- - | Thu Nov 16 00:00:00 20000 + to_timestamp_11 | to_timestamp +-----------------+------------------------------- + | Thu Nov 16 00:00:00 20000 PST (1 row) SELECT '' AS to_timestamp_12, to_timestamp('9-1116', 'Y-MMDD'); diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c index 5ce8664f27..61c58d05e7 100644 --- a/src/timezone/localtime.c +++ b/src/timezone/localtime.c @@ -3,7 +3,7 @@ * 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/localtime.c,v 1.6 2004/05/21 20:59:10 tgl Exp $ + * $PostgreSQL: pgsql/src/timezone/localtime.c,v 1.7 2004/06/03 02:08:07 tgl Exp $ */ /* @@ -69,7 +69,7 @@ struct ttinfo struct lsinfo { /* leap second information */ - time_t ls_trans; /* transition time */ + pg_time_t ls_trans; /* transition time */ long ls_corr; /* correction to apply */ }; @@ -81,7 +81,7 @@ struct state int timecnt; int typecnt; int charcnt; - time_t ats[TZ_MAX_TIMES]; + pg_time_t ats[TZ_MAX_TIMES]; unsigned char types[TZ_MAX_TIMES]; struct ttinfo ttis[TZ_MAX_TYPES]; char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), @@ -114,23 +114,11 @@ static const char *getsecs(const char *strp, long *secsp); static const char *getoffset(const char *strp, long *offsetp); static const char *getrule(const char *strp, struct rule * rulep); static void gmtload(struct state * sp); -static void gmtsub(const time_t *timep, long offset, struct pg_tm * tmp); -static void localsub(const time_t *timep, long offset, struct pg_tm * tmp); -static int increment_overflow(int *number, int delta); -static int normalize_overflow(int *tensptr, int *unitsptr, int base); -static time_t time1(struct pg_tm * tmp, - void (*funcp) (const time_t *, long, struct pg_tm *), - long offset); -static time_t time2(struct pg_tm * tmp, - void (*funcp) (const time_t *, long, struct pg_tm *), - long offset, int *okayp); -static time_t time2sub(struct pg_tm * tmp, - void (*funcp) (const time_t *, long, struct pg_tm *), - long offset, int *okayp, int do_norm_secs); -static void timesub(const time_t *timep, long offset, +static void gmtsub(const pg_time_t *timep, long offset, struct pg_tm * tmp); +static void localsub(const pg_time_t *timep, long offset, struct pg_tm * tmp); +static void timesub(const pg_time_t *timep, long offset, const struct state * sp, struct pg_tm * tmp); -static int tmcomp(const struct pg_tm * atmp, const struct pg_tm * btmp); -static time_t transtime(time_t janfirst, int year, +static pg_time_t transtime(pg_time_t janfirst, int year, const struct rule * rulep, long offset); static int tzload(const char *name, struct state * sp); static int tzparse(const char *name, struct state * sp, int lastditch); @@ -503,12 +491,12 @@ getrule(const char *strp, register struct rule * rulep) * year, a rule, and the offset from UTC at the time that rule takes effect, * calculate the Epoch-relative time that rule takes effect. */ -static time_t -transtime(const time_t janfirst, const int year, +static pg_time_t +transtime(const pg_time_t janfirst, const int year, register const struct rule * rulep, const long offset) { register int leapyear; - register time_t value = 0; + register pg_time_t value = 0; register int i; int d, m1, @@ -612,7 +600,7 @@ tzparse(const char *name, register struct state * sp, const int lastditch) size_t dstlen; long stdoffset; long dstoffset; - register time_t *atp; + register pg_time_t *atp; register unsigned char *typep; register char *cp; register int load_result; @@ -663,9 +651,9 @@ tzparse(const char *name, register struct state * sp, const int lastditch) struct rule start; struct rule end; register int year; - register time_t janfirst; - time_t starttime; - time_t endtime; + register pg_time_t janfirst; + pg_time_t starttime; + pg_time_t endtime; ++name; if ((name = getrule(name, &start)) == NULL) @@ -886,12 +874,12 @@ pg_tzset(const char *name) * The unused offset argument is for the benefit of mktime variants. */ static void -localsub(const time_t *timep, const long offset, struct pg_tm * tmp) +localsub(const pg_time_t *timep, const long offset, struct pg_tm * tmp) { register struct state *sp; register const struct ttinfo *ttisp; register int i; - const time_t t = *timep; + const pg_time_t t = *timep; sp = lclptr; if (sp->timecnt == 0 || t < sp->ats[0]) @@ -920,7 +908,7 @@ localsub(const time_t *timep, const long offset, struct pg_tm * tmp) struct pg_tm * -pg_localtime(const time_t *timep) +pg_localtime(const pg_time_t *timep) { localsub(timep, 0L, &tm); return &tm; @@ -931,7 +919,7 @@ pg_localtime(const time_t *timep) * gmtsub is to gmtime as localsub is to localtime. */ static void -gmtsub(const time_t *timep, const long offset, struct pg_tm * tmp) +gmtsub(const pg_time_t *timep, const long offset, struct pg_tm * tmp) { if (!gmt_is_set) { @@ -952,7 +940,7 @@ gmtsub(const time_t *timep, const long offset, struct pg_tm * tmp) } struct pg_tm * -pg_gmtime(const time_t *timep) +pg_gmtime(const pg_time_t *timep) { gmtsub(timep, 0L, &tm); return &tm; @@ -960,11 +948,13 @@ pg_gmtime(const time_t *timep) static void -timesub(const time_t *timep, const long offset, +timesub(const pg_time_t *timep, const long offset, register const struct state * sp, register struct pg_tm * tmp) { register const struct lsinfo *lp; - register long days; + /* expand days to 64 bits to support full Julian-day range */ + register int64 days; + register int idays; register long rem; register int y; register int yleap; @@ -1036,335 +1026,38 @@ timesub(const time_t *timep, const long offset, if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; y = EPOCH_YEAR; -#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) - while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) + /* + * Note: the point of adding 4800 is to ensure we make the same assumptions + * as Postgres' Julian-date routines about the placement of leap years + * in centuries BC, at least back to 4713BC which is as far as we'll go. + * This is effectively extending Gregorian timekeeping into pre-Gregorian + * centuries, which is a tad bogus but it conforms to the SQL spec... + */ +#define LEAPS_THRU_END_OF(y) (((y) + 4800) / 4 - ((y) + 4800) / 100 + ((y) + 4800) / 400) + while (days < 0 || days >= (int64) year_lengths[yleap = isleap(y)]) { register int newy; newy = y + days / DAYSPERNYEAR; if (days < 0) --newy; - days -= (newy - y) * DAYSPERNYEAR + + days -= ((int64) (newy - y)) * DAYSPERNYEAR + LEAPS_THRU_END_OF(newy - 1) - LEAPS_THRU_END_OF(y - 1); y = newy; } tmp->tm_year = y - TM_YEAR_BASE; - tmp->tm_yday = (int) days; + idays = (int) days; /* no longer have a range problem */ + tmp->tm_yday = idays; ip = mon_lengths[yleap]; - for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) - days = days - (long) ip[tmp->tm_mon]; - tmp->tm_mday = (int) (days + 1); + for (i = 0; idays >= ip[i]; ++i) + idays -= ip[i]; + tmp->tm_mon = i; + tmp->tm_mday = idays + 1; tmp->tm_isdst = 0; tmp->tm_gmtoff = offset; } -/* - * Adapted from code provided by Robert Elz, who writes: - * The "best" way to do mktime I think is based on an idea of Bob - * Kridle's (so its said...) from a long time ago. - * [kridle@xinet.com as of 1996-01-16.] - * It does a binary search of the time_t space. Since time_t's are - * just 32 bits, its a max of 32 iterations (even at 64 bits it - * would still be very reasonable). - */ - -#define WRONG (-1) - -/* - * Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). - */ - -static int -increment_overflow(int *number, int delta) -{ - int number0; - - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); -} - -static int -normalize_overflow(int *tensptr, int *unitsptr, const int base) -{ - register int tensdelta; - - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow(tensptr, tensdelta); -} - -static int -tmcomp(register const struct pg_tm * atmp, register const struct pg_tm * btmp) -{ - register int result; - - if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && - (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && - (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && - (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && - (result = (atmp->tm_min - btmp->tm_min)) == 0) - result = atmp->tm_sec - btmp->tm_sec; - return result; -} - -static time_t -time2sub(struct pg_tm * tmp, - void (*funcp) (const time_t *, long, struct pg_tm *), - const long offset, int *okayp, const int do_norm_secs) -{ - register const struct state *sp; - register int dir; - register int bits; - register int i, - j; - register int saved_seconds; - time_t newt; - time_t t; - struct pg_tm yourtm, - mytm; - - *okayp = FALSE; - yourtm = *tmp; - if (do_norm_secs) - { - if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, - SECSPERMIN)) - return WRONG; - } - if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) - return WRONG; - if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) - return WRONG; - if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) - return WRONG; - - /* - * Turn yourtm.tm_year into an actual year number for now. It is - * converted back to an offset from TM_YEAR_BASE later. - */ - if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) - return WRONG; - while (yourtm.tm_mday <= 0) - { - if (increment_overflow(&yourtm.tm_year, -1)) - return WRONG; - i = yourtm.tm_year + (1 < yourtm.tm_mon); - yourtm.tm_mday += year_lengths[isleap(i)]; - } - while (yourtm.tm_mday > DAYSPERLYEAR) - { - i = yourtm.tm_year + (1 < yourtm.tm_mon); - yourtm.tm_mday -= year_lengths[isleap(i)]; - if (increment_overflow(&yourtm.tm_year, 1)) - return WRONG; - } - for (;;) - { - i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; - if (yourtm.tm_mday <= i) - break; - yourtm.tm_mday -= i; - if (++yourtm.tm_mon >= MONSPERYEAR) - { - yourtm.tm_mon = 0; - if (increment_overflow(&yourtm.tm_year, 1)) - return WRONG; - } - } - if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) - return WRONG; - if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) - saved_seconds = 0; - else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) - { - /* - * We can't set tm_sec to 0, because that might push the time - * below the minimum representable time. Set tm_sec to 59 - * instead. This assumes that the minimum representable time is - * not in the same minute that a leap second was deleted from, - * which is a safer assumption than using 58 would be. - */ - if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) - return WRONG; - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = SECSPERMIN - 1; - } - else - { - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = 0; - } - - /* - * Divide the search space in half (this works whether time_t is - * signed or unsigned). - */ - bits = TYPE_BIT(time_t) -1; - - /* - * If time_t is signed, then 0 is just above the median, assuming - * two's complement arithmetic. If time_t is unsigned, then (1 << - * bits) is just above the median. - */ - t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); - for (;;) - { - (*funcp) (&t, offset, &mytm); - dir = tmcomp(&mytm, &yourtm); - if (dir != 0) - { - if (bits-- < 0) - return WRONG; - if (bits < 0) - --t; /* may be needed if new t is minimal */ - else if (dir > 0) - t -= ((time_t) 1) << bits; - else - t += ((time_t) 1) << bits; - continue; - } - if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) - break; - - /* - * Right time, wrong type. Hunt for right time, right type. - * It's okay to guess wrong since the guess gets checked. - */ - - /* - * The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. - */ - sp = (const struct state *) - (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); - for (i = sp->typecnt - 1; i >= 0; --i) - { - if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) - continue; - for (j = sp->typecnt - 1; j >= 0; --j) - { - if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) - continue; - newt = t + sp->ttis[j].tt_gmtoff - - sp->ttis[i].tt_gmtoff; - (*funcp) (&newt, offset, &mytm); - if (tmcomp(&mytm, &yourtm) != 0) - continue; - if (mytm.tm_isdst != yourtm.tm_isdst) - continue; - - /* - * We have a match. - */ - t = newt; - goto label; - } - } - return WRONG; - } -label: - newt = t + saved_seconds; - if ((newt < t) != (saved_seconds < 0)) - return WRONG; - t = newt; - (*funcp) (&t, offset, tmp); - *okayp = TRUE; - return t; -} - -static time_t -time2(struct pg_tm * tmp, - void (*funcp) (const time_t *, long, struct pg_tm *), - const long offset, int *okayp) -{ - time_t t; - - /* - * First try without normalization of seconds (in case tm_sec - * contains a value associated with a leap second). If that fails, - * try with normalization of seconds. - */ - t = time2sub(tmp, funcp, offset, okayp, FALSE); - return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); -} - -static time_t -time1(struct pg_tm * tmp, - void (*funcp) (const time_t *, long, struct pg_tm *), - const long offset) -{ - register time_t t; - register const struct state *sp; - register int samei, - otheri; - register int sameind, - otherind; - register int i; - register int nseen; - int seen[TZ_MAX_TYPES]; - int types[TZ_MAX_TYPES]; - int okay; - - if (tmp->tm_isdst > 1) - tmp->tm_isdst = 1; - t = time2(tmp, funcp, offset, &okay); - if (okay || tmp->tm_isdst < 0) - return t; - - /* - * We're supposed to assume that somebody took a time of one type - * and did some math on it that yielded a "struct pg_tm" that's bad. - * We try to divine the type they started from and adjust to the - * type they need. - */ - - /* - * The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. - */ - sp = (const struct state *) (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); - for (i = 0; i < sp->typecnt; ++i) - seen[i] = FALSE; - nseen = 0; - for (i = sp->timecnt - 1; i >= 0; --i) - if (!seen[sp->types[i]]) - { - seen[sp->types[i]] = TRUE; - types[nseen++] = sp->types[i]; - } - for (sameind = 0; sameind < nseen; ++sameind) - { - samei = types[sameind]; - if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) - continue; - for (otherind = 0; otherind < nseen; ++otherind) - { - otheri = types[otherind]; - if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) - continue; - tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - t = time2(tmp, funcp, offset, &okay); - if (okay) - return t; - tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - } - } - return WRONG; -} - -time_t -pg_mktime(struct pg_tm * tmp) -{ - return time1(tmp, localsub, 0L); -} /* * Return the name of the current timezone diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c index 9222cc143e..3da41363d5 100644 --- a/src/timezone/pgtz.c +++ b/src/timezone/pgtz.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.16 2004/05/25 19:46:21 tgl Exp $ + * $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.17 2004/06/03 02:08:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,12 +16,14 @@ #include #include +#include #include "miscadmin.h" #include "pgtime.h" #include "pgtz.h" #include "storage/fd.h" #include "tzfile.h" +#include "utils/datetime.h" #include "utils/elog.h" #include "utils/guc.h" @@ -107,7 +109,7 @@ win32_get_timezone_abbrev(const char *tz) #endif /* - * Convenience subroutine to convert y/m/d to time_t + * Convenience subroutine to convert y/m/d to time_t (NOT pg_time_t) */ static time_t build_time_t(int year, int month, int day) @@ -148,6 +150,7 @@ static bool try_timezone(const char *tzname, struct tztry *tt) { int i; + pg_time_t pgtt; struct tm *systm; struct pg_tm *pgtm; char cbuf[TZ_STRLEN_MAX + 1]; @@ -158,14 +161,15 @@ try_timezone(const char *tzname, struct tztry *tt) /* Check for match at all the test times */ for (i = 0; i < tt->n_test_times; i++) { - pgtm = pg_localtime(&(tt->test_times[i])); + pgtt = (pg_time_t) (tt->test_times[i]); + pgtm = pg_localtime(&pgtt); if (!pgtm) return false; /* probably shouldn't happen */ systm = localtime(&(tt->test_times[i])); if (!compare_tm(systm, pgtm)) { - elog(DEBUG4, "Reject TZ \"%s\": at %lu %04d-%02d-%02d %02d:%02d:%02d %s versus %04d-%02d-%02d %02d:%02d:%02d %s", - tzname, (unsigned long) tt->test_times[i], + elog(DEBUG4, "Reject TZ \"%s\": at %ld %04d-%02d-%02d %02d:%02d:%02d %s versus %04d-%02d-%02d %02d:%02d:%02d %s", + tzname, (long) pgtt, pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday, pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec, pgtm->tm_isdst ? "dst" : "std", @@ -183,8 +187,8 @@ try_timezone(const char *tzname, struct tztry *tt) strftime(cbuf, sizeof(cbuf) - 1, "%Z", systm); /* zone abbr */ if (strcmp(TZABBREV(cbuf), pgtm->tm_zone) != 0) { - elog(DEBUG4, "Reject TZ \"%s\": at %lu \"%s\" versus \"%s\"", - tzname, (unsigned long) tt->test_times[i], + elog(DEBUG4, "Reject TZ \"%s\": at %ld \"%s\" versus \"%s\"", + tzname, (long) pgtt, pgtm->tm_zone, cbuf); return false; } @@ -470,21 +474,17 @@ scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt) bool tz_acceptable(void) { - struct pg_tm tt; - time_t time2000; + struct pg_tm *tt; + pg_time_t time2000; /* - * To detect leap-second timekeeping, compute the time_t value for - * local midnight, 2000-01-01. Insist that this be a multiple of 60; - * any partial-minute offset has to be due to leap seconds. + * To detect leap-second timekeeping, run pg_localtime for what should + * be GMT midnight, 2000-01-01. Insist that the tm_sec value be zero; + * any other result has to be due to leap seconds. */ - MemSet(&tt, 0, sizeof(tt)); - tt.tm_year = 100; - tt.tm_mon = 0; - tt.tm_mday = 1; - tt.tm_isdst = -1; - time2000 = pg_mktime(&tt); - if ((time2000 % 60) != 0) + time2000 = (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400; + tt = pg_localtime(&time2000); + if (tt->tm_sec != 0) return false; return true; diff --git a/src/timezone/strftime.c b/src/timezone/strftime.c index 3b505364ef..791b076e8e 100644 --- a/src/timezone/strftime.c +++ b/src/timezone/strftime.c @@ -15,7 +15,7 @@ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/strftime.c,v 1.3 2004/05/21 20:59:10 tgl Exp $ + * $PostgreSQL: pgsql/src/timezone/strftime.c,v 1.4 2004/06/03 02:08:07 tgl Exp $ */ #include "postgres.h" @@ -265,21 +265,6 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim, case 'S': pt = _conv(t->tm_sec, "%02d", pt, ptlim); continue; - case 's': - { - struct pg_tm tm; - char buf[INT_STRLEN_MAXIMUM(time_t) +1]; - time_t mkt; - - tm = *t; - mkt = pg_mktime(&tm); - if (TYPE_SIGNED(time_t)) - (void) sprintf(buf, "%ld", (long) mkt); - else - (void) sprintf(buf, "%lu", (unsigned long) mkt); - pt = _add(buf, pt, ptlim); - } - continue; case 'T': pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp); continue; diff --git a/src/timezone/zic.c b/src/timezone/zic.c index a427e75686..90fe89ea08 100644 --- a/src/timezone/zic.c +++ b/src/timezone/zic.c @@ -3,12 +3,13 @@ * 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/zic.c,v 1.7 2004/05/21 20:59:10 tgl Exp $ + * $PostgreSQL: pgsql/src/timezone/zic.c,v 1.8 2004/06/03 02:08:07 tgl Exp $ */ #include "postgres.h" #include +#include #include "pgtz.h" #include "private.h" @@ -71,7 +72,7 @@ struct rule const char *r_abbrvar; /* variable part of abbreviation */ int r_todo; /* a rule to do (used in outzone) */ - time_t r_temp; /* used in outzone */ + pg_time_t r_temp; /* used in outzone */ }; /* @@ -98,14 +99,14 @@ struct zone int z_nrules; struct rule z_untilrule; - time_t z_untiltime; + pg_time_t z_untiltime; }; extern int link(const char *fromname, const char *toname); -static void addtt(time_t starttime, int type); +static void addtt(pg_time_t starttime, int type); static int addtype(long gmtoff, const char *abbr, int isdst, int ttisstd, int ttisgmt); -static void leapadd(time_t t, int positive, int rolling, int count); +static void leapadd(pg_time_t t, int positive, int rolling, int count); static void adjleap(void); static void associate(void); static int ciequal(const char *ap, const char *bp); @@ -138,13 +139,13 @@ static long oadd(long t1, long t2); static void outzone(const struct zone * zp, int ntzones); static void puttzcode(long code, FILE *fp); static int rcomp(const void *leftp, const void *rightp); -static time_t rpytime(const struct rule * rp, int wantedy); +static pg_time_t rpytime(const struct rule * rp, int wantedy); static void rulesub(struct rule * rp, const char *loyearp, const char *hiyearp, const char *typep, const char *monthp, const char *dayp, const char *timep); static void setboundaries(void); -static time_t tadd(time_t t1, long t2); +static pg_time_t tadd(pg_time_t t1, long t2); static void usage(void); static void writezone(const char *name); static int yearistype(int year, const char *type); @@ -158,10 +159,10 @@ static int errors; static const char *filename; static int leapcnt; static int linenum; -static time_t max_time; +static pg_time_t max_time; static int max_year; static int max_year_representable; -static time_t min_time; +static pg_time_t min_time; static int min_year; static int min_year_representable; static int noise; @@ -354,7 +355,7 @@ static const int len_years[2] = { static struct attype { - time_t at; + pg_time_t at; unsigned char type; } attypes[TZ_MAX_TIMES]; static long gmtoffs[TZ_MAX_TYPES]; @@ -363,7 +364,7 @@ static unsigned char abbrinds[TZ_MAX_TYPES]; static char ttisstds[TZ_MAX_TYPES]; static char ttisgmts[TZ_MAX_TYPES]; static char chars[TZ_MAX_CHARS]; -static time_t trans[TZ_MAX_LEAPS]; +static pg_time_t trans[TZ_MAX_LEAPS]; static long corr[TZ_MAX_LEAPS]; static char roll[TZ_MAX_LEAPS]; @@ -684,27 +685,26 @@ dolink(const char *fromfile, const char *tofile) * change to the tz file format. */ -#define MAX_BITS_IN_FILE 32 -#define TIME_T_BITS_IN_FILE ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE) +#define TIME_T_BITS_IN_FILE 32 static void setboundaries(void) { - if (TYPE_SIGNED(time_t)) - { - min_time = ~(time_t) 0; - min_time <<= TIME_T_BITS_IN_FILE - 1; - max_time = ~(time_t) 0 - min_time; - if (sflag) - min_time = 0; - } - else - { - min_time = 0; - max_time = 2 - sflag; - max_time <<= TIME_T_BITS_IN_FILE - 1; - --max_time; - } + /* + * pg_time_t is always signed, but might be only 32 bits ... + */ + min_time = ~(pg_time_t) 0; + min_time <<= TYPE_BIT(pg_time_t) - 1; + max_time = ~(pg_time_t) 0 - min_time; + + /* + * For the moment, hard-wire the range as 1901 to 2038. We cannot + * go wider without adopting an incompatible zone file format, which + * is a step I'd just as soon not take just yet. + */ + min_time = Max(min_time, (pg_time_t) INT_MIN); + max_time = Min(max_time, (pg_time_t) INT_MAX); + min_year = TM_YEAR_BASE + pg_gmtime(&min_time)->tm_year; max_year = TM_YEAR_BASE + pg_gmtime(&max_time)->tm_year; min_year_representable = min_year; @@ -1170,7 +1170,7 @@ inleap(register char **fields, const int nfields) day; long dayoff, tod; - time_t t; + pg_time_t t; if (nfields != LEAP_FIELDS) { @@ -1223,11 +1223,6 @@ inleap(register char **fields, const int nfields) return; } dayoff = oadd(dayoff, eitol(day - 1)); - if (dayoff < 0 && !TYPE_SIGNED(time_t)) - { - error(_("time before zero")); - return; - } if (dayoff < min_time / SECSPERDAY) { error(_("time too small")); @@ -1238,7 +1233,7 @@ inleap(register char **fields, const int nfields) error(_("time too large")); return; } - t = (time_t) dayoff *SECSPERDAY; + t = (pg_time_t) dayoff *SECSPERDAY; tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE); cp = fields[LP_CORR]; @@ -1525,7 +1520,7 @@ writezone(const char *name) j; static char *fullname; static struct tzhead tzh; - time_t ats[TZ_MAX_TIMES]; + pg_time_t ats[TZ_MAX_TIMES]; unsigned char types[TZ_MAX_TIMES]; /* @@ -1711,8 +1706,8 @@ outzone(const struct zone * zpfirst, const int zonecount) j; register int usestart, useuntil; - register time_t starttime = 0; - register time_t untiltime = 0; + register pg_time_t starttime = 0; + register pg_time_t untiltime = 0; register long gmtoff; register long stdoff; register int year; @@ -1790,7 +1785,7 @@ outzone(const struct zone * zpfirst, const int zonecount) for (;;) { register int k; - register time_t jtime, + register pg_time_t jtime, ktime = 0; register long offset; char buf[BUFSIZ]; @@ -1911,7 +1906,7 @@ outzone(const struct zone * zpfirst, const int zonecount) } static void -addtt(const time_t starttime, int type) +addtt(const pg_time_t starttime, int type) { if (starttime <= min_time || (timecnt == 1 && attypes[0].at < min_time)) @@ -1999,7 +1994,7 @@ addtype(const long gmtoff, const char *abbr, const int isdst, } static void -leapadd(const time_t t, const int positive, const int rolling, int count) +leapadd(const pg_time_t t, const int positive, const int rolling, int count) { register int i, j; @@ -2191,10 +2186,10 @@ oadd(const long t1, const long t2) return t; } -static time_t -tadd(const time_t t1, const long t2) +static pg_time_t +tadd(const pg_time_t t1, const long t2) { - register time_t t; + register pg_time_t t; if (t1 == max_time && t2 > 0) return max_time; @@ -2214,14 +2209,14 @@ tadd(const time_t t1, const long t2) * 1970, 00:00 LOCAL time - in that year that the rule refers to. */ -static time_t +static pg_time_t rpytime(register const struct rule * rp, register const int wantedy) { register int y, m, i; register long dayoff; /* with a nod to Margaret O. */ - register time_t t; + register pg_time_t t; if (wantedy == INT_MIN) return min_time; @@ -2302,13 +2297,11 @@ rpytime(register const struct rule * rp, register const int wantedy) (void) exit(EXIT_FAILURE); } } - if (dayoff < 0 && !TYPE_SIGNED(time_t)) - return min_time; if (dayoff < min_time / SECSPERDAY) return min_time; if (dayoff > max_time / SECSPERDAY) return max_time; - t = (time_t) dayoff *SECSPERDAY; + t = (pg_time_t) dayoff *SECSPERDAY; return tadd(t, rp->r_tod); }