Adjust our timezone library to use pg_time_t (typedef'd as int64) in

place of time_t, as per prior discussion.  The behavior does not change
on machines without a 64-bit-int type, but on machines with one, which
is most, we are rid of the bizarre boundary behavior at the edges of
the 32-bit-time_t range (1901 and 2038).  The system will now treat
times over the full supported timestamp range as being in your local
time zone.  It may seem a little bizarre to consider that times in
4000 BC are PST or EST, but this is surely at least as reasonable as
propagating Gregorian calendar rules back that far.

I did not modify the format of the zic timezone database files, which
means that for the moment the system will not know about daylight-savings
periods outside the range 1901-2038.  Given the way the files are set up,
it's not a simple decision like 'widen to 64 bits'; we have to actually
think about the range of years that need to be supported.  We should
probably inquire what the plans of the upstream zic people are before
making any decisions of our own.
This commit is contained in:
Tom Lane 2004-06-03 02:08:07 +00:00
parent 473ac70aca
commit 921d749bd4
28 changed files with 419 additions and 786 deletions

View File

@ -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 <time.h>
#include <unistd.h>
#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,

View File

@ -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 <fcntl.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
@ -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;
}

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"
/*

View File

@ -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 <signal.h>
#include <time.h>
#include "access/xlog.h"
#include "libpq/pqsignal.h"

View File

@ -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 <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include "pgstat.h"

View File

@ -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 <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/stat.h>
@ -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"

View File

@ -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 <time.h>
#include "access/xact.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"

View File

@ -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"

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <ctype.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <sys/time.h>
#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);

View File

@ -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)

View File

@ -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 <fcntl.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <ctype.h>
@ -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;

View File

@ -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 <time.h>
#include "access/xlogdefs.h"
#include "pgtime.h"
#include "utils/pg_crc.h"

View File

@ -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"

View File

@ -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 <time.h>
#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 <time.h>
/*
* 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 */

View File

@ -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 <limits.h>
#include <math.h>
#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)

View File

@ -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 <limits.h>
#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.
*/

View File

@ -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

View File

@ -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');

View File

@ -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');

View File

@ -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

View File

@ -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 <ctype.h>
#include <sys/stat.h>
#include <time.h>
#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;

View File

@ -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;

View File

@ -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 <locale.h>
#include <limits.h>
#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);
}