@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $ Header : / cvsroot / pgsql / src / backend / utils / adt / Attic / dt . c , v 1.59 .2 .1 1998 / 12 / 31 16 : 34 : 48 thomas Exp $
* $ Header : / cvsroot / pgsql / src / backend / utils / adt / Attic / dt . c , v 1.59 .2 .2 1999 / 02 / 13 05 : 59 : 34 thomas Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -31,11 +31,12 @@
# endif
# include "utils/builtins.h"
static int DecodeDate ( char * str , int fmask , int * tmask , struct tm * tm ) ;
static int DecodeNumber ( int flen , char * field ,
int fmask , int * tmask , struct tm * tm , double * fsec ) ;
int fmask , int * tmask , struct tm * tm , double * fsec , int * is2digits ) ;
static int DecodeNumberField ( int len , char * str ,
int fmask , int * tmask , struct tm * tm , double * fsec ) ;
int fmask , int * tmask , struct tm * tm , double * fsec , int * is2digits ) ;
static int DecodeSpecial ( int field , char * lowtoken , int * val ) ;
static int DecodeTime ( char * str , int fmask , int * tmask ,
struct tm * tm , double * fsec ) ;
@ -50,12 +51,20 @@ static double time2t(const int hour, const int min, const double sec);
static int timespan2tm ( TimeSpan span , struct tm * tm , float8 * fsec ) ;
static int tm2timespan ( struct tm * tm , double fsec , TimeSpan * span ) ;
# define USE_DATE_CACHE 1
# define ROUND_ALL 0
#if 0
# define isleap(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
int mdays [ ] = { 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 , 0 } ;
# endif
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 } } ;
char * months [ ] = { " Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " ,
" Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec " , NULL } ;
@ -240,7 +249,7 @@ timespan_in(char *str)
case DTK_DELTA :
if ( tm2timespan ( tm , fsec , span ) ! = 0 )
{
# if FALSE
# if NOT_USED
TIMESPAN_INVALID ( span ) ;
# endif
elog ( ERROR , " Bad timespan external representation '%s' " , str ) ;
@ -873,6 +882,7 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
}
/* adjust for end of month boundary problems... */
#if 0
if ( tm - > tm_mday > mdays [ tm - > tm_mon - 1 ] )
{
if ( ( tm - > tm_mon = = 2 ) & & isleap ( tm - > tm_year ) )
@ -880,6 +890,9 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
else
tm - > tm_mday = mdays [ tm - > tm_mon - 1 ] ;
}
# endif
if ( tm - > tm_mday > day_tab [ isleap ( tm - > tm_year ) ] [ tm - > tm_mon - 1 ] )
tm - > tm_mday = ( day_tab [ isleap ( tm - > tm_year ) ] [ tm - > tm_mon - 1 ] ) ;
# ifdef DATEDEBUG
printf ( " datetime_pl_span- date becomes %04d-%02d-%02d %02d:%02d:%02d \n " ,
@ -1184,16 +1197,22 @@ datetime_age(DateTime *datetime1, DateTime *datetime2)
{
if ( dt1 < dt2 )
{
#if 0
tm - > tm_mday + = mdays [ tm1 - > tm_mon - 1 ] ;
if ( isleap ( tm1 - > tm_year ) & & ( tm1 - > tm_mon = = 2 ) )
tm - > tm_mday + + ;
# endif
tm - > tm_mday + = day_tab [ isleap ( tm1 - > tm_year ) ] [ tm1 - > tm_mon - 1 ] ;
tm - > tm_mon - - ;
}
else
{
#if 0
tm - > tm_mday + = mdays [ tm2 - > tm_mon - 1 ] ;
if ( isleap ( tm2 - > tm_year ) & & ( tm2 - > tm_mon = = 2 ) )
tm - > tm_mday + + ;
# endif
tm - > tm_mday + = day_tab [ isleap ( tm2 - > tm_year ) ] [ tm2 - > tm_mon - 1 ] ;
tm - > tm_mon - - ;
}
}
@ -1393,7 +1412,7 @@ datetime_trunc(text *units, DateTime *datetime)
if ( DATETIME_NOT_FINITE ( * datetime ) )
{
# if FALSE
# if NOT_USED
/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */
elog ( ERROR , " Datetime is not finite " , NULL ) ;
# endif
@ -1475,7 +1494,7 @@ datetime_trunc(text *units, DateTime *datetime)
if ( tm2datetime ( tm , fsec , & tz , result ) ! = 0 )
elog ( ERROR , " Unable to truncate datetime to '%s' " , lowunits ) ;
# if FALSE
# if NOT_USED
}
else if ( ( type = = RESERV ) & & ( val = = DTK_EPOCH ) )
{
@ -1533,7 +1552,7 @@ timespan_trunc(text *units, TimeSpan *timespan)
if ( TIMESPAN_IS_INVALID ( * timespan ) )
{
# if FALSE
# if NOT_USED
elog ( ERROR , " Timespan is not finite " , NULL ) ;
# endif
result = NULL ;
@ -1591,7 +1610,7 @@ timespan_trunc(text *units, TimeSpan *timespan)
result = NULL ;
}
# if FALSE
# if NOT_USED
}
else if ( ( type = = RESERV ) & & ( val = = DTK_EPOCH ) )
{
@ -1659,7 +1678,7 @@ datetime_part(text *units, DateTime *datetime)
if ( DATETIME_NOT_FINITE ( * datetime ) )
{
# if FALSE
# if NOT_USED
/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */
elog ( ERROR , " Datetime is not finite " , NULL ) ;
# endif
@ -1824,7 +1843,7 @@ timespan_part(text *units, TimeSpan *timespan)
if ( TIMESPAN_IS_INVALID ( * timespan ) )
{
# if FALSE
# if NOT_USED
elog ( ERROR , " Timespan is not finite " , NULL ) ;
# endif
* result = 0 ;
@ -1874,15 +1893,15 @@ timespan_part(text *units, TimeSpan *timespan)
break ;
case DTK_DECADE :
* result = ( tm - > tm_year / 10 ) + 1 ;
* result = ( tm - > tm_year / 10 ) ;
break ;
case DTK_CENTURY :
* result = ( tm - > tm_year / 100 ) + 1 ;
* result = ( tm - > tm_year / 100 ) ;
break ;
case DTK_MILLENIUM :
* result = ( tm - > tm_year / 1000 ) + 1 ;
* result = ( tm - > tm_year / 1000 ) ;
break ;
default :
@ -2036,7 +2055,7 @@ static datetkn datetktbl[] = {
{ " adt " , DTZ , NEG ( 18 ) } , /* Atlantic Daylight Time */
{ " aesst " , DTZ , 66 } , /* E. Australia */
{ " aest " , TZ , 60 } , /* Australia Eastern Std Time */
{ " ahst " , TZ , 60 } , /* Alaska-Hawaii Std Time */
{ " ahst " , TZ , NEG ( 60 ) } , /* Alaska-Hawaii Std Time */
{ " allballs " , RESERV , DTK_ZULU } , /* 00:00:00 */
{ " am " , AMPM , AM } ,
{ " apr " , MONTH , 4 } ,
@ -2087,12 +2106,12 @@ static datetkn datetktbl[] = {
{ " hmt " , DTZ , 18 } , /* Hellas ? ? */
{ " hst " , TZ , NEG ( 60 ) } , /* Hawaii Std Time */
{ " idle " , TZ , 72 } , /* Intl. Date Line, East */
{ " idlw " , TZ , NEG ( 72 ) } , /* Intl. Date Line,, est */
{ " idlw " , TZ , NEG ( 72 ) } , /* Intl. Date Line, W est */
{ LATE , RESERV , DTK_LATE } , /* "infinity" reserved for "late time" */
{ INVALID , RESERV , DTK_INVALID } , /* "invalid" reserved for invalid
* time */
{ INVALID , RESERV , DTK_INVALID } ,
/* "invalid" reserved for invalid time */
{ " ist " , TZ , 12 } , /* Israel */
{ " it " , TZ , 22 } , /* Iran Time */
{ " it " , TZ , 21 } , /* Iran Time */
{ " jan " , MONTH , 1 } ,
{ " january " , MONTH , 1 } ,
{ " jst " , TZ , 54 } , /* Japan Std Time,USSR Zone 8 */
@ -2283,6 +2302,8 @@ datetkn *deltacache[MAXDATEFIELDS] = {NULL};
* These routines will be used by other date / time packages - tgl 97 / 02 / 25
*/
#if 0
XXX moved to dt . h - thomas 1999 - 01 - 15
/* Set the minimum year to one greater than the year of the first valid day
* to avoid having to check year and day both . - tgl 97 / 05 / 08
*/
@ -2294,6 +2315,7 @@ datetkn *deltacache[MAXDATEFIELDS] = {NULL};
# define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \
| | ( ( y = = JULIAN_MINYEAR ) & & ( ( m > JULIAN_MINMONTH ) \
| | ( ( m = = JULIAN_MINMONTH ) & & ( d > = JULIAN_MINDAY ) ) ) ) )
# endif
int
date2j ( int y , int m , int d )
@ -2432,7 +2454,7 @@ datetime2tm(DateTime dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
tm - > tm_mday = tx - > tm_mday ;
tm - > tm_hour = tx - > tm_hour ;
tm - > tm_min = tx - > tm_min ;
# if FALSE
# if NOT_USED
/* XXX HACK
* Argh ! My Linux box puts in a 1 second offset for dates less than 1970
* but only if the seconds field was non - zero . So , don ' t copy the seconds
@ -2792,6 +2814,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
int flen ,
val ;
int mer = HR24 ;
int haveTextMonth = FALSE ;
int is2digits = FALSE ;
int bc = FALSE ;
* dtype = DTK_DATE ;
@ -2839,15 +2863,18 @@ DecodeDateTime(char **field, int *ftype, int nf,
case DTK_NUMBER :
flen = strlen ( field [ i ] ) ;
if ( flen > 4 )
/* long numeric string and either no date or no time read yet?
* then interpret as a concatenated date or time . . . */
if ( ( flen > 4 ) & & ! ( ( fmask & DTK_DATE_M ) & & ( fmask & DTK_TIME_M ) ) )
{
if ( DecodeNumberField ( flen , field [ i ] , fmask , & tmask , tm , fsec ) ! = 0 )
if ( DecodeNumberField ( flen , field [ i ] , fmask , & tmask , tm , fsec , & is2digits ) ! = 0 )
return - 1 ;
}
/* otherwise it is a single date/time field... */
else
{
if ( DecodeNumber ( flen , field [ i ] , fmask , & tmask , tm , fsec ) ! = 0 )
if ( DecodeNumber ( flen , field [ i ] , fmask , & tmask , tm , fsec , & is2digits ) ! = 0 )
return - 1 ;
}
break ;
@ -2929,14 +2956,23 @@ DecodeDateTime(char **field, int *ftype, int nf,
# ifdef DATEDEBUG
printf ( " DecodeDateTime- month field %s value is %d \n " , field [ i ] , val ) ;
# endif
/* already have a (numeric) month? then see if we can substitute... */
if ( ( fmask & DTK_M ( MONTH ) ) & & ( ! haveTextMonth )
& & ( ! ( fmask & DTK_M ( DAY ) ) )
& & ( ( tm - > tm_mon > = 1 ) & & ( tm - > tm_mon < = 31 ) ) )
{
tm - > tm_mday = tm - > tm_mon ;
tmask = DTK_M ( DAY ) ;
# ifdef DATEDEBUG
printf ( " DecodeNumber- misidentified month previously; assign as day %d \n " , tm - > tm_mday ) ;
# endif
}
haveTextMonth = TRUE ;
tm - > tm_mon = val ;
break ;
/*
* daylight savings time modifier ( solves " MET
* DST " syntax)
*/
case DTZMOD :
/* daylight savings time modifier (solves "MET DST" syntax) */
tmask | = DTK_M ( DTZ ) ;
tm - > tm_isdst = 1 ;
if ( tzp = = NULL )
@ -3000,7 +3036,19 @@ DecodeDateTime(char **field, int *ftype, int nf,
/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
if ( bc )
tm - > tm_year = - ( tm - > tm_year - 1 ) ;
{
if ( tm - > tm_year > 0 )
tm - > tm_year = - ( tm - > tm_year - 1 ) ;
else
elog ( ERROR , " Inconsistant use of year %04d and 'BC' " , tm - > tm_year ) ;
}
else if ( is2digits )
{
if ( tm - > tm_year < 70 )
tm - > tm_year + = 2000 ;
else if ( tm - > tm_year < 100 )
tm - > tm_year + = 1900 ;
}
if ( ( mer ! = HR24 ) & & ( tm - > tm_hour > 12 ) )
return - 1 ;
@ -3075,6 +3123,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, dou
int i ;
int flen ,
val ;
int is2digits = FALSE ;
int mer = HR24 ;
* dtype = DTK_TIME ;
@ -3102,7 +3151,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, dou
case DTK_NUMBER :
flen = strlen ( field [ i ] ) ;
if ( DecodeNumberField ( flen , field [ i ] , fmask , & tmask , tm , fsec ) ! = 0 )
if ( DecodeNumberField ( flen , field [ i ] , fmask , & tmask , tm , fsec , & is2digits ) ! = 0 )
return - 1 ;
break ;
@ -3201,6 +3250,8 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
int nf = 0 ;
int i ,
len ;
int bc = FALSE ;
int is2digits = FALSE ;
int type ,
val ,
dmask = 0 ;
@ -3230,9 +3281,11 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
nf + + ;
}
#if 0
/* don't allow too many fields */
if ( nf > 3 )
return - 1 ;
# endif
* tmask = 0 ;
@ -3255,6 +3308,10 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
tm - > tm_mon = val ;
break ;
case ADBC :
bc = ( val = = BC ) ;
break ;
default :
# ifdef DATEDEBUG
printf ( " DecodeDate- illegal field %s value is %d \n " , field [ i ] , val ) ;
@ -3281,7 +3338,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
if ( ( len = strlen ( field [ i ] ) ) < = 0 )
return - 1 ;
if ( DecodeNumber ( len , field [ i ] , fmask , & dmask , tm , & fsec ) ! = 0 )
if ( DecodeNumber ( len , field [ i ] , fmask , & dmask , tm , & fsec , & is2digits ) ! = 0 )
return - 1 ;
if ( fmask & dmask )
@ -3291,6 +3348,25 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
* tmask | = dmask ;
}
if ( ( fmask & ~ ( DTK_M ( DOY ) | DTK_M ( TZ ) ) ) ! = DTK_DATE_M )
return - 1 ;
/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
if ( bc )
{
if ( tm - > tm_year > 0 )
tm - > tm_year = - ( tm - > tm_year - 1 ) ;
else
elog ( ERROR , " Inconsistant use of year %04d and 'BC' " , tm - > tm_year ) ;
}
else if ( is2digits )
{
if ( tm - > tm_year < 70 )
tm - > tm_year + = 2000 ;
else if ( tm - > tm_year < 100 )
tm - > tm_year + = 1900 ;
}
return 0 ;
} /* DecodeDate() */
@ -3354,7 +3430,8 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
* Interpret numeric field as a date value in context .
*/
static int
DecodeNumber ( int flen , char * str , int fmask , int * tmask , struct tm * tm , double * fsec )
DecodeNumber ( int flen , char * str , int fmask ,
int * tmask , struct tm * tm , double * fsec , int * is2digits )
{
int val ;
char * cp ;
@ -3375,8 +3452,23 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double
printf ( " DecodeNumber- %s is %d fmask=%08x tmask=%08x \n " , str , val , fmask , * tmask ) ;
# endif
/* enough digits to be unequivocal year? */
if ( flen = = 4 )
/* Special case day of year? */
if ( ( flen = = 3 ) & & ( fmask & DTK_M ( YEAR ) )
& & ( ( val > = 1 ) & & ( val < = 366 ) ) )
{
* tmask = ( DTK_M ( DOY ) | DTK_M ( MONTH ) | DTK_M ( DAY ) ) ;
tm - > tm_yday = val ;
j2date ( ( date2j ( tm - > tm_year , 1 , 1 ) + tm - > tm_yday - 1 ) ,
& tm - > tm_year , & tm - > tm_mon , & tm - > tm_mday ) ;
}
/* Enough digits to be unequivocal year?
* Used to test for 4 digits or more ,
* but we now test first for a three - digit doy
* so anything bigger than two digits had better be
* an explicit year . - thomas 1999 - 01 - 09
*/
else if ( flen > 2 )
{
# ifdef DATEDEBUG
printf ( " DecodeNumber- match %d (%s) as year \n " , val , str ) ;
@ -3384,33 +3476,20 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double
* tmask = DTK_M ( YEAR ) ;
/* already have a year? then see if we can substitute... */
if ( fmask & DTK_M ( YEAR ) )
if ( ( fmask & DTK_M ( YEAR ) ) & & ( ! ( fmask & DTK_M ( DAY ) ) )
& & ( ( tm - > tm_year > = 1 ) & & ( tm - > tm_year < = 31 ) ) )
{
if ( ( ! ( fmask & DTK_M ( DAY ) ) )
& & ( ( tm - > tm_year > = 1 ) & & ( tm - > tm_year < = 31 ) ) )
{
tm - > tm_mday = tm - > tm_year ;
* tmask = DTK_M ( DAY ) ;
# ifdef DATEDEBUG
printf ( " DecodeNumber- misidentified year previously; swap with day %d \n " , tm - > tm_mday ) ;
printf ( " DecodeNumber- misidentified year previously; assign as day %d \n " , tm - > tm_mday ) ;
# endif
tm - > tm_mday = tm - > tm_year ;
* tmask = DTK_M ( DAY ) ;
}
}
tm - > tm_year = val ;
/* special case day of year? */
}
else if ( ( flen = = 3 ) & & ( fmask & DTK_M ( YEAR ) )
& & ( ( val > = 1 ) & & ( val < = 366 ) ) )
{
* tmask = ( DTK_M ( DOY ) | DTK_M ( MONTH ) | DTK_M ( DAY ) ) ;
tm - > tm_yday = val ;
j2date ( ( date2j ( tm - > tm_year , 1 , 1 ) + tm - > tm_yday - 1 ) ,
& tm - > tm_year , & tm - > tm_mon , & tm - > tm_mday ) ;
/* already have year? then could be month */
}
/* already have year? then could be month */
else if ( ( fmask & DTK_M ( YEAR ) ) & & ( ! ( fmask & DTK_M ( MONTH ) ) )
& & ( ( val > = 1 ) & & ( val < = 12 ) ) )
{
@ -3460,10 +3539,18 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double
# endif
* tmask = DTK_M ( YEAR ) ;
tm - > tm_year = val ;
if ( tm - > tm_year < 70 )
tm - > tm_year + = 2000 ;
else if ( tm - > tm_year < 100 )
tm - > tm_year + = 1900 ;
/* adjust ONLY if exactly two digits... */
#if 0
if ( flen = = 2 )
{
if ( tm - > tm_year < 70 )
tm - > tm_year + = 2000 ;
else if ( tm - > tm_year < 100 )
tm - > tm_year + = 1900 ;
}
# endif
* is2digits = ( flen = = 2 ) ;
}
else
@ -3477,7 +3564,8 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double
* Interpret numeric string as a concatenated date field .
*/
static int
DecodeNumberField ( int len , char * str , int fmask , int * tmask , struct tm * tm , double * fsec )
DecodeNumberField ( int len , char * str , int fmask ,
int * tmask , struct tm * tm , double * fsec , int * is2digits )
{
char * cp ;
@ -3527,9 +3615,36 @@ DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, dou
tm - > tm_mon = atoi ( str + 2 ) ;
* ( str + 2 ) = ' \0 ' ;
tm - > tm_year = atoi ( str + 0 ) ;
#if 0
if ( tm - > tm_year < 70 )
tm - > tm_year + = 2000 ;
else if ( tm - > tm_year < 100 )
tm - > tm_year + = 1900 ;
# endif
* is2digits = TRUE ;
}
}
else if ( ( len = = 5 ) & & ! ( fmask & DTK_DATE_M ) )
{
# ifdef DATEDEBUG
printf ( " DecodeNumberField- %s is 5 characters fmask=%08x tmask=%08x \n " , str , fmask , * tmask ) ;
# endif
* tmask = DTK_DATE_M ;
tm - > tm_mday = atoi ( str + 2 ) ;
* ( str + 2 ) = ' \0 ' ;
tm - > tm_mon = 1 ;
tm - > tm_year = atoi ( str + 0 ) ;
#if 0
if ( tm - > tm_year < 70 )
tm - > tm_year + = 2000 ;
else if ( tm - > tm_year < 100 )
tm - > tm_year + = 1900 ;
# endif
* is2digits = TRUE ;
}
else if ( strchr ( str , ' . ' ) ! = NULL )
{
# ifdef DATEDEBUG