@ -1,15 +1,14 @@
/*
* This file is in the public domain , so clarified as of
* 1996 - 06 - 05 by Arthur David Olson ( arthur_david_olson @ nih . gov ) .
* 1996 - 06 - 05 by Arthur David Olson .
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / timezone / localtime . c , v 1.19 2007 / 11 / 15 21 : 14 : 46 momjian Exp $
* $ PostgreSQL : pgsql / src / timezone / localtime . c , v 1.20 2008 / 02 / 16 21 : 16 : 04 tgl Exp $
*/
/*
* Leap second handling from Bradley White ( bww @ k . gp . cs . cmu . edu ) .
* POSIX - style TZ environment variable handling from Guy Harris
* ( guy @ auspex . com ) .
* Leap second handling from Bradley White .
* POSIX - style TZ environment variable handling from Guy Harris .
*/
/* this file needs to build in both frontend and backend contexts */
@ -36,9 +35,9 @@
* 5. They might reference tm . TM_ZONE after calling offtime .
* What ' s best to do in the above cases is open to debate ;
* for now , we just set things up so that in any of the five cases
* WILDABBR is used . Another possibility : initialize tzname [ 0 ] to the
* WILDABBR is used . Another possibility : initialize tzname [ 0 ] to the
* string " tzname[0] used before set " , and similarly for the other cases .
* And another : initialize tzname [ 0 ] to " ERA " , with an explanation in the
* And another : initialize tzname [ 0 ] to " ERA " , with an explanation in the
* manual page of what this " time zone abbreviation " means ( doing this so
* that tzname [ 0 ] has the " normal " length of three characters ) .
* - - - - - - - - - -
@ -46,7 +45,7 @@
# define WILDABBR " "
# endif /* !defined WILDABBR */
static char wildabbr [ ] = " WILDABBR " ;
static char wildabbr [ ] = WILDABBR ;
static const char gmt [ ] = " GMT " ;
@ -77,18 +76,25 @@ struct rule
*/
static long detzcode ( const char * codep ) ;
static pg_time_t detzcode64 ( const char * codep ) ;
static int differ_by_repeat ( pg_time_t t1 , pg_time_t t0 ) ;
static const char * getzname ( const char * strp ) ;
static const char * getqzname ( const char * strp , int delim ) ;
static const char * getnum ( const char * strp , int * nump , int min , int max ) ;
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 pg_time_t * timep , long offset , struct pg_tm * tmp ) ;
static void localsub ( const pg_time_t * timep , long offset , struct pg_tm * tmp , const pg_tz * tz ) ;
static void timesub ( const pg_time_t * timep , long offset ,
const struct state * sp , struct pg_tm * tmp ) ;
static struct pg_tm * gmtsub ( const pg_time_t * timep , long offset ,
struct pg_tm * tmp ) ;
static struct pg_tm * localsub ( const pg_time_t * timep , long offset ,
struct pg_tm * tmp , const pg_tz * tz ) ;
static int increment_overflow ( int * number , int delta ) ;
static pg_time_t transtime ( pg_time_t janfirst , int year ,
const struct rule * rulep , long offset ) ;
const struct rule * rulep , long offset ) ;
static int typesequiv ( const struct state * sp , int a , int b ) ;
static struct pg_tm * timesub ( const pg_time_t * timep , long offset ,
const struct state * sp , struct pg_tm * tmp ) ;
/* GMT timezone */
static struct state gmtmem ;
@ -103,7 +109,7 @@ static int gmt_is_set = 0;
* Except for the strftime function , these functions [ asctime ,
* ctime , gmtime , localtime ] return values in one of two static
* objects : a broken - down time structure and an array of char .
* Thanks to Paul Eggert ( eggert @ twinsun . com ) for noting this .
* Thanks to Paul Eggert for noting this .
*/
static struct pg_tm tm ;
@ -115,18 +121,48 @@ detzcode(const char *codep)
long result ;
int i ;
result = ( codep [ 0 ] & 0x80 ) ? ~ 0L : 0L ;
result = ( codep [ 0 ] & 0x80 ) ? ~ 0L : 0 ;
for ( i = 0 ; i < 4 ; + + i )
result = ( result < < 8 ) | ( codep [ i ] & 0xff ) ;
return result ;
}
static pg_time_t
detzcode64 ( const char * codep )
{
pg_time_t result ;
int i ;
result = ( codep [ 0 ] & 0x80 ) ? ( ~ ( int64 ) 0 ) : 0 ;
for ( i = 0 ; i < 8 ; + + i )
result = result * 256 + ( codep [ i ] & 0xff ) ;
return result ;
}
static int
differ_by_repeat ( pg_time_t t1 , pg_time_t t0 )
{
if ( TYPE_INTEGRAL ( pg_time_t ) & &
TYPE_BIT ( pg_time_t ) - TYPE_SIGNED ( pg_time_t ) < SECSPERREPEAT_BITS )
return 0 ;
return t1 - t0 = = SECSPERREPEAT ;
}
int
tzload ( const char * name , char * canonname , struct state * sp )
tzload ( const char * name , char * canonname , struct state * sp , int doextend )
{
const char * p ;
int i ;
int fid ;
int stored ;
int nread ;
union
{
struct tzhead tzhead ;
char buf [ 2 * sizeof ( struct tzhead ) +
2 * sizeof * sp +
4 * TZ_MAX_TIMES ] ;
} u ;
if ( name = = NULL & & ( name = TZDEFAULT ) = = NULL )
return - 1 ;
@ -135,19 +171,14 @@ tzload(const char *name, char *canonname, struct state * sp)
fid = pg_open_tzfile ( name , canonname ) ;
if ( fid < 0 )
return - 1 ;
nread = read ( fid , u . buf , sizeof u . buf ) ;
if ( close ( fid ) ! = 0 | | nread < = 0 )
return - 1 ;
for ( stored = 4 ; stored < = 8 ; stored * = 2 )
{
struct tzhead * tzhp ;
union
{
struct tzhead tzhead ;
char buf [ sizeof * sp + sizeof * tzhp ] ;
} u ;
int ttisstdcnt ;
int ttisgmtcnt ;
i = read ( fid , u . buf , sizeof u . buf ) ;
if ( close ( fid ) ! = 0 )
return - 1 ;
ttisstdcnt = ( int ) detzcode ( u . tzhead . tzh_ttisstdcnt ) ;
ttisgmtcnt = ( int ) detzcode ( u . tzhead . tzh_ttisgmtcnt ) ;
sp - > leapcnt = ( int ) detzcode ( u . tzhead . tzh_leapcnt ) ;
@ -162,18 +193,19 @@ tzload(const char *name, char *canonname, struct state * sp)
( ttisstdcnt ! = sp - > typecnt & & ttisstdcnt ! = 0 ) | |
( ttisgmtcnt ! = sp - > typecnt & & ttisgmtcnt ! = 0 ) )
return - 1 ;
if ( i - ( p - u . buf ) < sp - > timecnt * 4 + /* ats */
if ( nread - ( p - u . buf ) <
sp - > timecnt * stored + /* ats */
sp - > timecnt + /* types */
sp - > typecnt * ( 4 + 2 ) + /* ttinfos */
sp - > typecnt * 6 + /* ttinfos */
sp - > charcnt + /* chars */
sp - > leapcnt * ( 4 + 4 ) + /* lsinfos */
sp - > leapcnt * ( stored + 4 ) + /* lsinfos */
ttisstdcnt + /* ttisstds */
ttisgmtcnt ) /* ttisgmts */
return - 1 ;
for ( i = 0 ; i < sp - > timecnt ; + + i )
{
sp - > ats [ i ] = detzcode ( p ) ;
p + = 4 ;
sp - > ats [ i ] = ( stored = = 4 ) ? detzcode ( p ) : detzcode64 ( p ) ;
p + = stored ;
}
for ( i = 0 ; i < sp - > timecnt ; + + i )
{
@ -204,8 +236,8 @@ tzload(const char *name, char *canonname, struct state * sp)
struct lsinfo * lsisp ;
lsisp = & sp - > lsis [ i ] ;
lsisp - > ls_trans = detzcode ( p ) ;
p + = 4 ;
lsisp - > ls_trans = ( stored = = 4 ) ? detzcode ( p ) : detzcode64 ( p ) ;
p + = stored ;
lsisp - > ls_corr = detzcode ( p ) ;
p + = 4 ;
}
@ -239,10 +271,127 @@ tzload(const char *name, char *canonname, struct state * sp)
return - 1 ;
}
}
/*
* Out - of - sort ats should mean we ' re running on a
* signed time_t system but using a data file with
* unsigned values ( or vice versa ) .
*/
for ( i = 0 ; i < sp - > timecnt - 2 ; + + i )
if ( sp - > ats [ i ] > sp - > ats [ i + 1 ] )
{
+ + i ;
if ( TYPE_SIGNED ( pg_time_t ) )
{
/*
* Ignore the end ( easy ) .
*/
sp - > timecnt = i ;
}
else
{
/*
* Ignore the beginning ( harder ) .
*/
int j ;
for ( j = 0 ; j + i < sp - > timecnt ; + + j )
{
sp - > ats [ j ] = sp - > ats [ j + i ] ;
sp - > types [ j ] = sp - > types [ j + i ] ;
}
sp - > timecnt = j ;
}
break ;
}
/*
* If this is an old file , we ' re done .
*/
if ( u . tzhead . tzh_version [ 0 ] = = ' \0 ' )
break ;
nread - = p - u . buf ;
for ( i = 0 ; i < nread ; + + i )
u . buf [ i ] = p [ i ] ;
/*
* If this is a narrow integer time_t system , we ' re done .
*/
if ( stored > = ( int ) sizeof ( pg_time_t ) & & TYPE_INTEGRAL ( pg_time_t ) )
break ;
}
if ( doextend & & nread > 2 & &
u . buf [ 0 ] = = ' \n ' & & u . buf [ nread - 1 ] = = ' \n ' & &
sp - > typecnt + 2 < = TZ_MAX_TYPES )
{
struct state ts ;
int result ;
u . buf [ nread - 1 ] = ' \0 ' ;
result = tzparse ( & u . buf [ 1 ] , & ts , FALSE ) ;
if ( result = = 0 & & ts . typecnt = = 2 & &
sp - > charcnt + ts . charcnt < = TZ_MAX_CHARS )
{
for ( i = 0 ; i < 2 ; + + i )
ts . ttis [ i ] . tt_abbrind + =
sp - > charcnt ;
for ( i = 0 ; i < ts . charcnt ; + + i )
sp - > chars [ sp - > charcnt + + ] =
ts . chars [ i ] ;
i = 0 ;
while ( i < ts . timecnt & &
ts . ats [ i ] < =
sp - > ats [ sp - > timecnt - 1 ] )
+ + i ;
while ( i < ts . timecnt & &
sp - > timecnt < TZ_MAX_TIMES )
{
sp - > ats [ sp - > timecnt ] =
ts . ats [ i ] ;
sp - > types [ sp - > timecnt ] =
sp - > typecnt +
ts . types [ i ] ;
+ + sp - > timecnt ;
+ + i ;
}
sp - > ttis [ sp - > typecnt + + ] = ts . ttis [ 0 ] ;
sp - > ttis [ sp - > typecnt + + ] = ts . ttis [ 1 ] ;
}
}
i = 2 * YEARSPERREPEAT ;
sp - > goback = sp - > goahead = sp - > timecnt > i ;
sp - > goback = sp - > goback & &
typesequiv ( sp , sp - > types [ i ] , sp - > types [ 0 ] ) & &
differ_by_repeat ( sp - > ats [ i ] , sp - > ats [ 0 ] ) ;
sp - > goahead = sp - > goahead & &
typesequiv ( sp , sp - > types [ sp - > timecnt - 1 ] ,
sp - > types [ sp - > timecnt - 1 - i ] ) & &
differ_by_repeat ( sp - > ats [ sp - > timecnt - 1 ] ,
sp - > ats [ sp - > timecnt - 1 - i ] ) ;
return 0 ;
}
static int
typesequiv ( const struct state * sp , int a , int b )
{
int result ;
if ( sp = = NULL | |
a < 0 | | a > = sp - > typecnt | |
b < 0 | | b > = sp - > typecnt )
result = FALSE ;
else
{
const struct ttinfo * ap = & sp - > ttis [ a ] ;
const struct ttinfo * bp = & sp - > ttis [ b ] ;
result = ap - > tt_gmtoff = = bp - > tt_gmtoff & &
ap - > tt_isdst = = bp - > tt_isdst & &
ap - > tt_ttisstd = = bp - > tt_ttisstd & &
ap - > tt_ttisgmt = = bp - > tt_ttisgmt & &
strcmp ( & sp - > chars [ ap - > tt_abbrind ] ,
& sp - > chars [ bp - > tt_abbrind ] ) = = 0 ;
}
return result ;
}
static const int mon_lengths [ 2 ] [ MONSPERYEAR ] = {
{ 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 } ,
{ 31 , 29 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 }
@ -254,7 +403,7 @@ static const int year_lengths[2] = {
/*
* Given a pointer into a time zone string , scan until a character that is not
* a valid character in a zone name is found . Return a pointer to that
* a valid character in a zone name is found . Return a pointer to that
* character .
*/
static const char *
@ -268,6 +417,24 @@ getzname(const char *strp)
return strp ;
}
/*
* Given a pointer into an extended time zone string , scan until the ending
* delimiter of the zone name is located . Return a pointer to the delimiter .
*
* As with getzname above , the legal character set is actually quite
* restricted , with other characters producing undefined results .
* We don ' t do any checking here ; checking is done later in common - case code .
*/
static const char *
getqzname ( const char * strp , int delim )
{
int c ;
while ( ( c = * strp ) ! = ' \0 ' & & c ! = delim )
+ + strp ;
return strp ;
}
/*
* Given a pointer into a time zone string , extract a number from that string .
* Check that the number is within a specified range ; if it is not , return
@ -327,7 +494,7 @@ getsecs(const char *strp, long *secsp)
if ( * strp = = ' : ' )
{
+ + strp ;
/* `SECSPERMIN' allows for leap seconds. */
/* `SECSPERMIN' allows for leap seconds. */
strp = getnum ( strp , & num , 0 , SECSPERMIN ) ;
if ( strp = = NULL )
return NULL ;
@ -365,7 +532,7 @@ getoffset(const char *strp, long *offsetp)
/*
* Given a pointer into a time zone string , extract a rule in the form
* date [ / time ] . See POSIX section 8 for the format of " date " and " time " .
* date [ / time ] . See POSIX section 8 for the format of " date " and " time " .
* If a valid rule is not found , return NULL .
* Otherwise , return a pointer to the first character not part of the rule .
*/
@ -559,26 +726,47 @@ tzparse(const char *name, struct state * sp, int lastditch)
}
else
{
name = getzname ( name ) ;
stdlen = name - stdname ;
if ( stdlen < 3 )
return - 1 ;
if ( * name = = ' < ' )
{
name + + ;
stdname = name ;
name = getqzname ( name , ' > ' ) ;
if ( * name ! = ' > ' )
return ( - 1 ) ;
stdlen = name - stdname ;
name + + ;
}
else
{
name = getzname ( name ) ;
stdlen = name - stdname ;
}
if ( * name = = ' \0 ' )
return - 1 ;
name = getoffset ( name , & stdoffset ) ;
if ( name = = NULL )
return - 1 ;
load_result = tzload ( TZDEFRULES , NULL , sp ) ;
load_result = tzload ( TZDEFRULES , NULL , sp , FALSE ) ;
}
if ( load_result ! = 0 )
sp - > leapcnt = 0 ; /* so, we're off a little */
if ( * name ! = ' \0 ' )
{
dstname = name ;
name = getzname ( name ) ;
dstlen = name - dstname ; /* length of DST zone name */
if ( dstlen < 3 )
return - 1 ;
if ( * name = = ' < ' )
{
dstname = + + name ;
name = getqzname ( name , ' > ' ) ;
if ( * name ! = ' > ' )
return - 1 ;
dstlen = name - dstname ;
name + + ;
}
else
{
dstname = name ;
name = getzname ( name ) ;
dstlen = name - dstname ; /* length of DST zone name */
}
if ( * name ! = ' \0 ' & & * name ! = ' , ' & & * name ! = ' ; ' )
{
name = getoffset ( name , & dstoffset ) ;
@ -610,11 +798,8 @@ tzparse(const char *name, struct state * sp, int lastditch)
sp - > typecnt = 2 ; /* standard time and DST */
/*
* Two transitions per year , from EPOCH_YEAR to 2037 .
* Two transitions per year , from EPOCH_YEAR forward .
*/
sp - > timecnt = 2 * ( 2037 - EPOCH_YEAR + 1 ) ;
if ( sp - > timecnt > TZ_MAX_TIMES )
return - 1 ;
sp - > ttis [ 0 ] . tt_gmtoff = - dstoffset ;
sp - > ttis [ 0 ] . tt_isdst = 1 ;
sp - > ttis [ 0 ] . tt_abbrind = stdlen + 1 ;
@ -624,8 +809,13 @@ tzparse(const char *name, struct state * sp, int lastditch)
atp = sp - > ats ;
typep = sp - > types ;
janfirst = 0 ;
for ( year = EPOCH_YEAR ; year < = 2037 ; + + year )
sp - > timecnt = 0 ;
for ( year = EPOCH_YEAR ;
sp - > timecnt + 2 < = TZ_MAX_TIMES ;
+ + year )
{
pg_time_t newfirst ;
starttime = transtime ( janfirst , year , & start ,
stdoffset ) ;
endtime = transtime ( janfirst , year , & end ,
@ -644,8 +834,13 @@ tzparse(const char *name, struct state * sp, int lastditch)
* atp + + = endtime ;
* typep + + = 1 ; /* DST ends */
}
janfirst + = year_lengths [ isleap ( year ) ] *
sp - > timecnt + = 2 ;
newfirst = janfirst ;
newfirst + = year_lengths [ isleap ( year ) ] *
SECSPERDAY ;
if ( newfirst < = janfirst )
break ;
janfirst = newfirst ;
}
}
else
@ -776,7 +971,7 @@ tzparse(const char *name, struct state * sp, int lastditch)
static void
gmtload ( struct state * sp )
{
if ( tzload ( gmt , NULL , sp ) ! = 0 )
if ( tzload ( gmt , NULL , sp , TRUE ) ! = 0 )
( void ) tzparse ( gmt , sp , TRUE ) ;
}
@ -784,20 +979,63 @@ gmtload(struct state * sp)
/*
* The easy way to behave " as if no library function calls " localtime
* is to not call it - - so we drop its guts into " localsub " , which can be
* freely called . ( And no , the PANS doesn ' t require the above behavior - -
* freely called . ( And no , the PANS doesn ' t require the above behavior - -
* but it * is * desirable . )
*
* The unused offset argument is for the benefit of mktime variants .
*/
static void
localsub ( const pg_time_t * timep , long offset , struct pg_tm * tmp , const pg_tz * tz )
static struct pg_tm *
localsub ( const pg_time_t * timep , long offset ,
struct pg_tm * tmp , const pg_tz * tz )
{
const struct state * sp ;
const struct ttinfo * ttisp ;
int i ;
struct pg_tm * result ;
const pg_time_t t = * timep ;
sp = & tz - > state ;
if ( ( sp - > goback & & t < sp - > ats [ 0 ] ) | |
( sp - > goahead & & t > sp - > ats [ sp - > timecnt - 1 ] ) )
{
pg_time_t newt = t ;
pg_time_t seconds ;
pg_time_t tcycles ;
int64 icycles ;
if ( t < sp - > ats [ 0 ] )
seconds = sp - > ats [ 0 ] - t ;
else seconds = t - sp - > ats [ sp - > timecnt - 1 ] ;
- - seconds ;
tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR ;
+ + tcycles ;
icycles = tcycles ;
if ( tcycles - icycles > = 1 | | icycles - tcycles > = 1 )
return NULL ;
seconds = icycles ;
seconds * = YEARSPERREPEAT ;
seconds * = AVGSECSPERYEAR ;
if ( t < sp - > ats [ 0 ] )
newt + = seconds ;
else newt - = seconds ;
if ( newt < sp - > ats [ 0 ] | |
newt > sp - > ats [ sp - > timecnt - 1 ] )
return NULL ; /* "cannot happen" */
result = localsub ( & newt , offset , tmp , tz ) ;
if ( result = = tmp )
{
pg_time_t newy ;
newy = tmp - > tm_year ;
if ( t < sp - > ats [ 0 ] )
newy - = icycles * YEARSPERREPEAT ;
else newy + = icycles * YEARSPERREPEAT ;
tmp - > tm_year = newy ;
if ( tmp - > tm_year ! = newy )
return NULL ;
}
return result ;
}
if ( sp - > timecnt = = 0 | | t < sp - > ats [ 0 ] )
{
i = 0 ;
@ -810,39 +1048,49 @@ localsub(const pg_time_t *timep, long offset, struct pg_tm * tmp, const pg_tz *t
}
else
{
for ( i = 1 ; i < sp - > timecnt ; + + i )
if ( t < sp - > ats [ i ] )
break ;
i = sp - > types [ i - 1 ] ;
int lo = 1 ;
int hi = sp - > timecnt ;
while ( lo < hi )
{
int mid = ( lo + hi ) > > 1 ;
if ( t < sp - > ats [ mid ] )
hi = mid ;
else lo = mid + 1 ;
}
i = ( int ) sp - > types [ lo - 1 ] ;
}
ttisp = & sp - > ttis [ i ] ;
timesub ( & t , ttisp - > tt_gmtoff , sp , tmp ) ;
result = timesub ( & t , ttisp - > tt_gmtoff , sp , tmp ) ;
tmp - > tm_isdst = ttisp - > tt_isdst ;
tmp - > tm_zone = & sp - > chars [ ttisp - > tt_abbrind ] ;
return result ;
}
struct pg_tm *
pg_localtime ( const pg_time_t * timep , const pg_tz * tz )
{
localsub ( timep , 0L , & tm , tz ) ;
return & tm ;
return localsub ( timep , 0L , & tm , tz ) ;
}
/*
* gmtsub is to gmtime as localsub is to localtime .
*/
static void
gmtsub ( const pg_time_t * timep , long offset , struct pg_tm * tmp )
static struct pg_tm *
gmtsub ( const pg_time_t * timep , long offset , struct pg_tm * tmp )
{
struct pg_tm * result ;
if ( ! gmt_is_set )
{
gmt_is_set = TRUE ;
gmtload ( gmtptr ) ;
}
timesub ( timep , offset , gmtptr , tmp ) ;
result = timesub ( timep , offset , gmtptr , tmp ) ;
/*
* Could get fancy here and deliver something such as " UTC+xxxx " or
@ -853,28 +1101,37 @@ gmtsub(const pg_time_t *timep, long offset, struct pg_tm * tmp)
tmp - > tm_zone = wildabbr ;
else
tmp - > tm_zone = gmtptr - > chars ;
return result ;
}
struct pg_tm *
pg_gmtime ( const pg_time_t * timep )
{
gmtsub ( timep , 0L , & tm ) ;
return & tm ;
return gmtsub ( timep , 0L , & tm ) ;
}
/*
* Return the number of leap years through the end of the given year
* where , to make the math easy , the answer for year zero is defined as zero .
*/
static int
leaps_thru_end_of ( const int y )
{
return ( y > = 0 ) ? ( y / 4 - y / 100 + y / 400 ) :
- ( leaps_thru_end_of ( - ( y + 1 ) ) + 1 ) ;
}
static void
static struct pg_tm *
timesub ( const pg_time_t * timep , long offset ,
const struct state * sp , struct pg_tm * tmp )
const struct state * sp , struct pg_tm * tmp )
{
const struct lsinfo * lp ;
/* expand days to 64 bits to support full Julian-day range */
int64 days ;
int idays ;
pg_time_t tdays ;
int idays ; /* unsigned would be so 2003 */
long rem ;
int y ;
int yleap ;
const int * ip ;
long corr ;
int hit ;
@ -907,74 +1164,111 @@ timesub(const pg_time_t *timep, long offset,
break ;
}
}
days = * timep / SECSPERDAY ;
rem = * timep % SECSPERDAY ;
# ifdef mc68k
if ( * timep = = 0x80000000 )
y = EPOCH_YEAR ;
tdays = * timep / SECSPERDAY ;
rem = * timep - tdays * SECSPERDAY ;
while ( tdays < 0 | | tdays > = year_lengths [ isleap ( y ) ] )
{
/*
* A 3 B1 muffs the division on the most negative number .
*/
days = - 24855 ;
rem = - 11648 ;
int newy ;
pg_time_t tdelta ;
int idelta ;
int leapdays ;
tdelta = tdays / DAYSPERLYEAR ;
idelta = tdelta ;
if ( tdelta - idelta > = 1 | | idelta - tdelta > = 1 )
return NULL ;
if ( idelta = = 0 )
idelta = ( tdays < 0 ) ? - 1 : 1 ;
newy = y ;
if ( increment_overflow ( & newy , idelta ) )
return NULL ;
leapdays = leaps_thru_end_of ( newy - 1 ) -
leaps_thru_end_of ( y - 1 ) ;
tdays - = ( ( pg_time_t ) newy - y ) * DAYSPERNYEAR ;
tdays - = leapdays ;
y = newy ;
}
{
long seconds ;
seconds = tdays * SECSPERDAY + 0.5 ;
tdays = seconds / SECSPERDAY ;
rem + = seconds - tdays * SECSPERDAY ;
}
# endif /* defined mc68k */
rem + = ( offset - corr ) ;
/*
* Given the range , we can now fearlessly cast . . .
*/
idays = tdays ;
rem + = offset - corr ;
while ( rem < 0 )
{
rem + = SECSPERDAY ;
- - days ;
- - i days;
}
while ( rem > = SECSPERDAY )
{
rem - = SECSPERDAY ;
+ + days ;
+ + i days;
}
tmp - > tm_hour = ( int ) ( rem / SECSPERHOUR ) ;
rem = rem % SECSPERHOUR ;
tmp - > tm_min = ( int ) ( rem / SECSPERMIN ) ;
while ( idays < 0 )
{
if ( increment_overflow ( & y , - 1 ) )
return NULL ;
idays + = year_lengths [ isleap ( y ) ] ;
}
while ( idays > = year_lengths [ isleap ( y ) ] )
{
idays - = year_lengths [ isleap ( y ) ] ;
if ( increment_overflow ( & y , 1 ) )
return NULL ;
}
tmp - > tm_year = y ;
if ( increment_overflow ( & tmp - > tm_year , - TM_YEAR_BASE ) )
return NULL ;
tmp - > tm_yday = idays ;
/*
* A positive leap second requires a special representation . This uses
* " ... ??:59:60 " et seq .
* The " extra " mods below avoid overflow problems .
*/
tmp - > tm_sec = ( int ) ( rem % SECSPERMIN ) + hit ;
tmp - > tm_wday = ( int ) ( ( EPOCH_WDAY + days ) % DAYSPERWEEK ) ;
tmp - > tm_wday = EPOCH_WDAY +
( ( y - EPOCH_YEAR ) % DAYSPERWEEK ) *
( DAYSPERNYEAR % DAYSPERWEEK ) +
leaps_thru_end_of ( y - 1 ) -
leaps_thru_end_of ( EPOCH_YEAR - 1 ) +
idays ;
tmp - > tm_wday % = DAYSPERWEEK ;
if ( tmp - > tm_wday < 0 )
tmp - > tm_wday + = DAYSPERWEEK ;
y = EPOCH_YEAR ;
tmp - > tm_hour = ( int ) ( rem / SECSPERHOUR ) ;
rem % = SECSPERHOUR ;
tmp - > tm_min = ( int ) ( rem / SECSPERMIN ) ;
/*
* 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 4713 BC 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 . . .
* A positive leap second requires a special representation . This uses
* " ... ??:59:60 " et seq .
*/
# 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 ) ] )
{
int newy ;
newy = y + days / DAYSPERNYEAR ;
if ( days < 0 )
- - newy ;
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 ;
idays = ( int ) days ; /* no longer have a range problem */
tmp - > tm_yday = idays ;
ip = mon_lengths [ yleap ] ;
for ( i = 0 ; idays > = ip [ i ] ; + + i )
idays - = ip [ i ] ;
tmp - > tm_mon = i ;
tmp - > tm_mday = idays + 1 ;
tmp - > tm_sec = ( int ) ( rem % SECSPERMIN ) + hit ;
ip = mon_lengths [ isleap ( y ) ] ;
for ( tmp - > tm_mon = 0 ; idays > = ip [ tmp - > tm_mon ] ; + + ( tmp - > tm_mon ) )
idays - = ip [ tmp - > tm_mon ] ;
tmp - > tm_mday = ( int ) ( idays + 1 ) ;
tmp - > tm_isdst = 0 ;
tmp - > tm_gmtoff = offset ;
return tmp ;
}
/*
* Simplified normalize logic courtesy Paul Eggert .
*/
static int
increment_overflow ( int * number , int delta )
{
int number0 ;
number0 = * number ;
* number + = delta ;
return ( * number < number0 ) ! = ( delta < 0 ) ;
}
/*
@ -1027,6 +1321,48 @@ pg_next_dst_boundary(const pg_time_t *timep,
* before_isdst = ttisp - > tt_isdst ;
return 0 ;
}
if ( ( sp - > goback & & t < sp - > ats [ 0 ] ) | |
( sp - > goahead & & t > sp - > ats [ sp - > timecnt - 1 ] ) )
{
/* For values outside the transition table, extrapolate */
pg_time_t newt = t ;
pg_time_t seconds ;
pg_time_t tcycles ;
int64 icycles ;
int result ;
if ( t < sp - > ats [ 0 ] )
seconds = sp - > ats [ 0 ] - t ;
else seconds = t - sp - > ats [ sp - > timecnt - 1 ] ;
- - seconds ;
tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR ;
+ + tcycles ;
icycles = tcycles ;
if ( tcycles - icycles > = 1 | | icycles - tcycles > = 1 )
return - 1 ;
seconds = icycles ;
seconds * = YEARSPERREPEAT ;
seconds * = AVGSECSPERYEAR ;
if ( t < sp - > ats [ 0 ] )
newt + = seconds ;
else newt - = seconds ;
if ( newt < sp - > ats [ 0 ] | |
newt > sp - > ats [ sp - > timecnt - 1 ] )
return - 1 ; /* "cannot happen" */
result = pg_next_dst_boundary ( & newt , before_gmtoff ,
before_isdst ,
boundary ,
after_gmtoff ,
after_isdst ,
tz ) ;
if ( t < sp - > ats [ 0 ] )
* boundary - = seconds ;
else
* boundary + = seconds ;
return result ;
}
if ( t > sp - > ats [ sp - > timecnt - 1 ] )
{
/* No known transition >= t, so use last known segment's type */
@ -1058,9 +1394,20 @@ pg_next_dst_boundary(const pg_time_t *timep,
return 1 ;
}
/* Else search to find the containing segment */
for ( i = 1 ; i < sp - > timecnt ; + + i )
if ( t < = sp - > ats [ i ] )
break ;
{
int lo = 1 ;
int hi = sp - > timecnt ;
while ( lo < hi )
{
int mid = ( lo + hi ) > > 1 ;
if ( t < sp - > ats [ mid ] )
hi = mid ;
else lo = mid + 1 ;
}
i = lo ;
}
j = sp - > types [ i - 1 ] ;
ttisp = & sp - > ttis [ j ] ;
* before_gmtoff = ttisp - > tt_gmtoff ;