postgresql/src/backend/utils/adt/nabstime.c

435 lines
10 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* nabstime.c--
* parse almost any absolute date getdate(3) can (& some it can't)
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.16 1997/03/21 18:53:28 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include "postgres.h"
#include <miscadmin.h>
#ifndef USE_POSIX_TIME
#include <sys/timeb.h>
#endif
#include "access/xact.h"
1997-03-15 00:21:12 +01:00
#define MIN_DAYNUM -24856 /* December 13, 1901 */
#define MAX_DAYNUM 24854 /* January 18, 2038 */
/* GetCurrentAbsoluteTime()
* Get the current system time. Set timezone parameters if not specified elsewhere.
* Define HasTZSet to allow clients to specify the default timezone.
*
* Returns the number of seconds since epoch (January 1 1970 GMT)
*/
1997-03-15 00:21:12 +01:00
AbsoluteTime
1997-03-15 00:21:12 +01:00
GetCurrentAbsoluteTime(void)
{
1997-03-15 00:21:12 +01:00
time_t now;
1997-03-15 00:21:12 +01:00
#ifdef USE_POSIX_TIME
now = time(NULL);
#else /* ! USE_POSIX_TIME */
struct timeb tbnow; /* the old V7-ism */
(void) ftime(&tbnow);
now = tbnow.time;
#endif
if (! HasCTZSet) {
#ifdef USE_POSIX_TIME
#if defined(HAVE_TZSET) && defined(HAVE_INT_TIMEZONE)
tzset();
CTimeZone = timezone;
CDayLight = daylight;
strcpy( CTZName, tzname[0]);
#else /* !HAVE_TZSET */
struct tm *tmnow = localtime(&now);
1997-03-15 00:21:12 +01:00
CTimeZone = - tmnow->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
CDayLight = (tmnow->tm_isdst > 0);
/* XXX is there a better way to get local timezone string in V7? - tgl 97/03/18 */
strftime( CTZName, 8, "%Z", localtime(&now));
#endif
1997-03-15 00:21:12 +01:00
#else /* ! USE_POSIX_TIME */
CTimeZone = tbnow.timezone * 60;
CDayLight = (tbnow.dstflag != 0);
/* XXX does this work to get the local timezone string in V7? - tgl 97/03/18 */
strftime( CTZName, 8, "%Z", localtime(&now));
#endif
};
#ifdef DATEDEBUG
printf( "GetCurrentAbsoluteTime- timezone is %s -> %d seconds from UTC\n",
CTZName, CTimeZone);
#endif
1997-03-15 00:21:12 +01:00
return((AbsoluteTime) now);
} /* GetCurrentAbsoluteTime() */
1997-03-15 00:21:12 +01:00
void
GetCurrentTime(struct tm *tm)
{
1997-03-15 00:21:12 +01:00
time_t now;
struct tm *tt;
1997-03-15 00:21:12 +01:00
now = GetCurrentTransactionStartTime();
tt = gmtime( &now);
1997-03-15 00:21:12 +01:00
tm->tm_year = tt->tm_year+1900;
tm->tm_mon = tt->tm_mon+1;
tm->tm_mday = tt->tm_mday;
tm->tm_hour = tt->tm_hour;
tm->tm_min = tt->tm_min;
tm->tm_sec = tt->tm_sec;
tm->tm_isdst = tt->tm_isdst;
return;
} /* GetCurrentTime() */
/* nabstimein()
* Decode date/time string and return abstime.
*/
1997-03-15 00:21:12 +01:00
AbsoluteTime
nabstimein(char* str)
{
1997-03-15 00:21:12 +01:00
int sec;
double fsec;
int day, tz = 0;
struct tm date, *tm = &date;
char *field[MAXDATEFIELDS];
char lowstr[MAXDATELEN+1];
int dtype;
int nf, ftype[MAXDATEFIELDS];
if (!PointerIsValid(str))
elog(WARN,"Bad (null) abstime external representation",NULL);
if (strlen(str) > MAXDATELEN)
elog( WARN, "Bad (length) abstime external representation '%s'",str);
if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
|| (DecodeDateTime( field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
elog( WARN, "Bad abstime external representation '%s'",str);
#ifdef DATEDEBUG
printf( "nabstimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE);
#endif
switch (dtype) {
case DTK_DATE:
#if FALSE
return(dateconv( &date, tz));
#endif
/* validate, before going out of range on some members */
if (tm->tm_year < 1901 || tm->tm_year > 2038
|| tm->tm_mon < 1 || tm->tm_mon > 12
|| tm->tm_mday < 1 || tm->tm_mday > 31
|| tm->tm_hour < 0 || tm->tm_hour >= 24
|| tm->tm_min < 0 || tm->tm_min > 59
|| tm->tm_sec < 0 || tm->tm_sec > 59)
return INVALID_ABSTIME;
day = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 1970, 1, 1));
/* check for time out of range */
if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
return INVALID_ABSTIME;
/* convert to seconds */
sec = tm->tm_sec + tz + (tm->tm_min +(day*24 + tm->tm_hour)*60)*60;
/* check for overflow */
if ((day == MAX_DAYNUM && sec < 0) ||
(day == MIN_DAYNUM && sec > 0))
return INVALID_ABSTIME;
/* daylight correction */
if (tm->tm_isdst < 0) { /* unknown; find out */
tm->tm_isdst = (CDayLight > 0);
1997-03-15 00:21:12 +01:00
};
if (tm->tm_isdst > 0)
sec -= 60*60;
/* check for reserved values (e.g. "current" on edge of usual range */
if (!AbsoluteTimeIsReal(sec))
return INVALID_ABSTIME;
return sec;
case DTK_EPOCH:
return EPOCH_ABSTIME;
case DTK_CURRENT:
return CURRENT_ABSTIME;
case DTK_LATE:
return NOEND_ABSTIME;
case DTK_EARLY:
return NOSTART_ABSTIME;
case DTK_INVALID:
return INVALID_ABSTIME;
default:
};
elog(WARN,"Bad abstime (internal coding error) '%s'",str);
return INVALID_ABSTIME;
} /* nabstimein() */
/*
* Given an AbsoluteTime return the English text version of the date
*/
char *
nabstimeout(AbsoluteTime time)
{
/*
* Fri Jan 28 23:05:29 1994 PST
* 0 1 2
* 12345678901234567890123456789
*
* we allocate some extra -- timezones are usually 3 characters but
* this is not in the POSIX standard...
*/
char buf[40];
char* result;
switch (time) {
1997-03-15 00:21:12 +01:00
case EPOCH_ABSTIME: (void) strcpy(buf, EPOCH); break;
case INVALID_ABSTIME: (void) strcpy(buf, INVALID); break;
case CURRENT_ABSTIME: (void) strcpy(buf, DCURRENT); break;
case NOEND_ABSTIME: (void) strcpy(buf, LATE); break;
case NOSTART_ABSTIME: (void) strcpy(buf, EARLY); break;
default:
/* hack -- localtime happens to work for negative times */
(void) strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Y %Z",
localtime((time_t *) &time));
break;
}
result = (char*)palloc(strlen(buf) + 1);
strcpy(result, buf);
return result;
}
1997-03-15 00:21:12 +01:00
/* turn a (struct tm) and a few variables into a time_t, with range checking */
AbsoluteTime
dateconv(register struct tm *tm, int zone)
{
tm->tm_wday = tm->tm_yday = 0;
1997-03-15 00:21:12 +01:00
#if FALSE
if (tm->tm_year < 70) {
tm->tm_year += 2000;
} else if (tm->tm_year < 1000) {
tm->tm_year += 1900;
};
#endif
/* validate, before going out of range on some members */
1997-03-15 00:21:12 +01:00
if (tm->tm_year < 1901 || tm->tm_year > 2038
|| tm->tm_mon < 1 || tm->tm_mon > 12
|| tm->tm_mday < 1 || tm->tm_mday > 31
|| tm->tm_hour < 0 || tm->tm_hour >= 24
|| tm->tm_min < 0 || tm->tm_min > 59
|| tm->tm_sec < 0 || tm->tm_sec > 59)
return INVALID_ABSTIME;
/*
* zone should really be -zone, and tz should be set to tp->value, not
* -tp->value. Or the table could be fixed.
*/
1997-03-15 00:21:12 +01:00
tm->tm_sec += zone; /* mktime lets it be out of range */
/* convert to seconds */
return qmktime(tm);
}
/*
* near-ANSI qmktime suitable for use by dateconv; not necessarily as paranoid
* as ANSI requires, and it may not canonicalise the struct tm. Ignores tm_wday
* and tm_yday.
*/
time_t
1997-03-15 00:21:12 +01:00
qmktime(struct tm *tm)
{
1997-03-15 00:21:12 +01:00
time_t sec;
int day;
#if FALSE
/* If it was a 2 digit year */
1997-03-15 00:21:12 +01:00
if (tm->tm_year < 100)
tm->tm_year += 1900;
#endif
day = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 1970, 1, 1));
/* check for time out of range */
1997-03-15 00:21:12 +01:00
if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
return INVALID_ABSTIME;
1997-03-15 00:21:12 +01:00
/* convert to seconds */
1997-03-15 00:21:12 +01:00
sec = tm->tm_sec + (tm->tm_min +(day*24 + tm->tm_hour)*60)*60;
/* check for overflow */
1997-03-15 00:21:12 +01:00
if ((day == MAX_DAYNUM && sec < 0) ||
(day == MIN_DAYNUM && sec > 0))
return INVALID_ABSTIME;
1997-03-15 00:21:12 +01:00
/* check for reserved values (e.g. "current" on edge of usual range */
if (!AbsoluteTimeIsReal(sec))
return INVALID_ABSTIME;
1997-03-15 00:21:12 +01:00
/* daylight correction */
if (tm->tm_isdst < 0) { /* unknown; find out */
tm->tm_isdst = (CDayLight > 0);
1997-03-15 00:21:12 +01:00
};
if (tm->tm_isdst > 0)
sec -= 60*60;
1997-03-15 00:21:12 +01:00
return sec;
} /* qmktime() */
/*
* AbsoluteTimeIsBefore -- true iff time1 is before time2.
1997-03-15 00:21:12 +01:00
* AbsoluteTimeIsBefore -- true iff time1 is after time2.
*/
bool
AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2)
{
Assert(AbsoluteTimeIsValid(time1));
Assert(AbsoluteTimeIsValid(time2));
1997-03-15 00:21:12 +01:00
if (time1 == CURRENT_ABSTIME)
1997-03-15 00:21:12 +01:00
time1 = GetCurrentTransactionStartTime();
if (time2 == CURRENT_ABSTIME)
1997-03-15 00:21:12 +01:00
time2 = GetCurrentTransactionStartTime();
return (time1 < time2);
}
bool
AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
{
Assert(AbsoluteTimeIsValid(time1));
Assert(AbsoluteTimeIsValid(time2));
1997-03-15 00:21:12 +01:00
if (time1 == CURRENT_ABSTIME)
1997-03-15 00:21:12 +01:00
time1 = GetCurrentTransactionStartTime();
if (time2 == CURRENT_ABSTIME)
1997-03-15 00:21:12 +01:00
time2 = GetCurrentTransactionStartTime();
return (time1 > time2);
}
/*
* abstimeeq - returns 1, iff arguments are equal
* abstimene - returns 1, iff arguments are not equal
* abstimelt - returns 1, iff t1 less than t2
* abstimegt - returns 1, iff t1 greater than t2
* abstimele - returns 1, iff t1 less than or equal to t2
* abstimege - returns 1, iff t1 greater than or equal to t2
*/
1997-03-15 00:21:12 +01:00
bool
abstimeeq(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
1997-03-15 00:21:12 +01:00
return(t1 == t2);
}
1997-03-15 00:21:12 +01:00
bool
abstimene(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
1997-03-15 00:21:12 +01:00
return(t1 != t2);
}
1997-03-15 00:21:12 +01:00
bool
abstimelt(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
1997-03-15 00:21:12 +01:00
return(t1 < t2);
}
1997-03-15 00:21:12 +01:00
bool
abstimegt(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
1997-03-15 00:21:12 +01:00
return(t1 > t2);
}
1997-03-15 00:21:12 +01:00
bool
abstimele(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
1997-03-15 00:21:12 +01:00
return(t1 <= t2);
}
1997-03-15 00:21:12 +01:00
bool
abstimege(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
1997-03-15 00:21:12 +01:00
return(t1 >= t2);
}