Header And Logo

PostgreSQL
| The world's most advanced open source database.

localtime.c

Go to the documentation of this file.
00001 /*
00002  * This file is in the public domain, so clarified as of
00003  * 1996-06-05 by Arthur David Olson.
00004  *
00005  * IDENTIFICATION
00006  *    src/timezone/localtime.c
00007  */
00008 
00009 /*
00010  * Leap second handling from Bradley White.
00011  * POSIX-style TZ environment variable handling from Guy Harris.
00012  */
00013 
00014 /* this file needs to build in both frontend and backend contexts */
00015 #include "c.h"
00016 
00017 #include <fcntl.h>
00018 
00019 #include "datatype/timestamp.h"
00020 #include "private.h"
00021 #include "pgtz.h"
00022 #include "tzfile.h"
00023 
00024 
00025 #ifndef WILDABBR
00026 /*----------
00027  * Someone might make incorrect use of a time zone abbreviation:
00028  *  1.  They might reference tzname[0] before calling tzset (explicitly
00029  *      or implicitly).
00030  *  2.  They might reference tzname[1] before calling tzset (explicitly
00031  *      or implicitly).
00032  *  3.  They might reference tzname[1] after setting to a time zone
00033  *      in which Daylight Saving Time is never observed.
00034  *  4.  They might reference tzname[0] after setting to a time zone
00035  *      in which Standard Time is never observed.
00036  *  5.  They might reference tm.TM_ZONE after calling offtime.
00037  * What's best to do in the above cases is open to debate;
00038  * for now, we just set things up so that in any of the five cases
00039  * WILDABBR is used. Another possibility:   initialize tzname[0] to the
00040  * string "tzname[0] used before set", and similarly for the other cases.
00041  * And another: initialize tzname[0] to "ERA", with an explanation in the
00042  * manual page of what this "time zone abbreviation" means (doing this so
00043  * that tzname[0] has the "normal" length of three characters).
00044  *----------
00045  */
00046 #define WILDABBR    "   "
00047 #endif   /* !defined WILDABBR */
00048 
00049 static char wildabbr[] = WILDABBR;
00050 
00051 static const char gmt[] = "GMT";
00052 
00053 /*
00054  * The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
00055  * We default to US rules as of 1999-08-17.
00056  * POSIX 1003.1 section 8.1.1 says that the default DST rules are
00057  * implementation dependent; for historical reasons, US rules are a
00058  * common default.
00059  */
00060 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
00061 
00062 struct rule
00063 {
00064     int         r_type;         /* type of rule--see below */
00065     int         r_day;          /* day number of rule */
00066     int         r_week;         /* week number of rule */
00067     int         r_mon;          /* month number of rule */
00068     long        r_time;         /* transition time of rule */
00069 };
00070 
00071 #define JULIAN_DAY      0       /* Jn - Julian day */
00072 #define DAY_OF_YEAR     1       /* n - day of year */
00073 #define MONTH_NTH_DAY_OF_WEEK   2       /* Mm.n.d - month, week, day of week */
00074 
00075 /*
00076  * Prototypes for static functions.
00077  */
00078 
00079 static long detzcode(const char *codep);
00080 static pg_time_t detzcode64(const char *codep);
00081 static int  differ_by_repeat(pg_time_t t1, pg_time_t t0);
00082 static const char *getzname(const char *strp);
00083 static const char *getqzname(const char *strp, int delim);
00084 static const char *getnum(const char *strp, int *nump, int min, int max);
00085 static const char *getsecs(const char *strp, long *secsp);
00086 static const char *getoffset(const char *strp, long *offsetp);
00087 static const char *getrule(const char *strp, struct rule * rulep);
00088 static void gmtload(struct state * sp);
00089 static struct pg_tm *gmtsub(const pg_time_t *timep, long offset,
00090        struct pg_tm * tmp);
00091 static struct pg_tm *localsub(const pg_time_t *timep, long offset,
00092          struct pg_tm * tmp, const pg_tz *tz);
00093 static int  increment_overflow(int *number, int delta);
00094 static pg_time_t transtime(pg_time_t janfirst, int year,
00095           const struct rule * rulep, long offset);
00096 static int  typesequiv(const struct state * sp, int a, int b);
00097 static struct pg_tm *timesub(const pg_time_t *timep, long offset,
00098         const struct state * sp, struct pg_tm * tmp);
00099 
00100 /* GMT timezone */
00101 static struct state gmtmem;
00102 
00103 #define gmtptr      (&gmtmem)
00104 
00105 
00106 static int  gmt_is_set = 0;
00107 
00108 /*
00109  * Section 4.12.3 of X3.159-1989 requires that
00110  *  Except for the strftime function, these functions [asctime,
00111  *  ctime, gmtime, localtime] return values in one of two static
00112  *  objects: a broken-down time structure and an array of char.
00113  * Thanks to Paul Eggert for noting this.
00114  */
00115 
00116 static struct pg_tm tm;
00117 
00118 
00119 static long
00120 detzcode(const char *codep)
00121 {
00122     long        result;
00123     int         i;
00124 
00125     result = (codep[0] & 0x80) ? ~0L : 0;
00126     for (i = 0; i < 4; ++i)
00127         result = (result << 8) | (codep[i] & 0xff);
00128     return result;
00129 }
00130 
00131 static pg_time_t
00132 detzcode64(const char *codep)
00133 {
00134     pg_time_t   result;
00135     int         i;
00136 
00137     result = (codep[0] & 0x80) ? (~(int64) 0) : 0;
00138     for (i = 0; i < 8; ++i)
00139         result = result * 256 + (codep[i] & 0xff);
00140     return result;
00141 }
00142 
00143 static int
00144 differ_by_repeat(pg_time_t t1, pg_time_t t0)
00145 {
00146     if (TYPE_INTEGRAL(pg_time_t) &&
00147         TYPE_BIT(pg_time_t) -TYPE_SIGNED(pg_time_t) <SECSPERREPEAT_BITS)
00148         return 0;
00149     return t1 - t0 == SECSPERREPEAT;
00150 }
00151 
00152 int
00153 tzload(const char *name, char *canonname, struct state * sp, int doextend)
00154 {
00155     const char *p;
00156     int         i;
00157     int         fid;
00158     int         stored;
00159     int         nread;
00160     union
00161     {
00162         struct tzhead tzhead;
00163         char        buf[2 * sizeof(struct tzhead) +
00164                                     2 * sizeof *sp +
00165                                     4 * TZ_MAX_TIMES];
00166     }           u;
00167 
00168     sp->goback = sp->goahead = FALSE;
00169     if (name == NULL && (name = TZDEFAULT) == NULL)
00170         return -1;
00171     if (name[0] == ':')
00172         ++name;
00173     fid = pg_open_tzfile(name, canonname);
00174     if (fid < 0)
00175         return -1;
00176     nread = read(fid, u.buf, sizeof u.buf);
00177     if (close(fid) != 0 || nread <= 0)
00178         return -1;
00179     for (stored = 4; stored <= 8; stored *= 2)
00180     {
00181         int         ttisstdcnt;
00182         int         ttisgmtcnt;
00183 
00184         ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
00185         ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
00186         sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
00187         sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
00188         sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
00189         sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
00190         p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
00191         if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
00192             sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
00193             sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
00194             sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
00195             (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
00196             (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
00197             return -1;
00198         if (nread - (p - u.buf) <
00199             sp->timecnt * stored +      /* ats */
00200             sp->timecnt +       /* types */
00201             sp->typecnt * 6 +   /* ttinfos */
00202             sp->charcnt +       /* chars */
00203             sp->leapcnt * (stored + 4) +        /* lsinfos */
00204             ttisstdcnt +        /* ttisstds */
00205             ttisgmtcnt)         /* ttisgmts */
00206             return -1;
00207         for (i = 0; i < sp->timecnt; ++i)
00208         {
00209             sp->ats[i] = (stored == 4) ? detzcode(p) : detzcode64(p);
00210             p += stored;
00211         }
00212         for (i = 0; i < sp->timecnt; ++i)
00213         {
00214             sp->types[i] = (unsigned char) *p++;
00215             if (sp->types[i] >= sp->typecnt)
00216                 return -1;
00217         }
00218         for (i = 0; i < sp->typecnt; ++i)
00219         {
00220             struct ttinfo *ttisp;
00221 
00222             ttisp = &sp->ttis[i];
00223             ttisp->tt_gmtoff = detzcode(p);
00224             p += 4;
00225             ttisp->tt_isdst = (unsigned char) *p++;
00226             if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
00227                 return -1;
00228             ttisp->tt_abbrind = (unsigned char) *p++;
00229             if (ttisp->tt_abbrind < 0 ||
00230                 ttisp->tt_abbrind > sp->charcnt)
00231                 return -1;
00232         }
00233         for (i = 0; i < sp->charcnt; ++i)
00234             sp->chars[i] = *p++;
00235         sp->chars[i] = '\0';    /* ensure '\0' at end */
00236         for (i = 0; i < sp->leapcnt; ++i)
00237         {
00238             struct lsinfo *lsisp;
00239 
00240             lsisp = &sp->lsis[i];
00241             lsisp->ls_trans = (stored == 4) ? detzcode(p) : detzcode64(p);
00242             p += stored;
00243             lsisp->ls_corr = detzcode(p);
00244             p += 4;
00245         }
00246         for (i = 0; i < sp->typecnt; ++i)
00247         {
00248             struct ttinfo *ttisp;
00249 
00250             ttisp = &sp->ttis[i];
00251             if (ttisstdcnt == 0)
00252                 ttisp->tt_ttisstd = FALSE;
00253             else
00254             {
00255                 ttisp->tt_ttisstd = *p++;
00256                 if (ttisp->tt_ttisstd != TRUE &&
00257                     ttisp->tt_ttisstd != FALSE)
00258                     return -1;
00259             }
00260         }
00261         for (i = 0; i < sp->typecnt; ++i)
00262         {
00263             struct ttinfo *ttisp;
00264 
00265             ttisp = &sp->ttis[i];
00266             if (ttisgmtcnt == 0)
00267                 ttisp->tt_ttisgmt = FALSE;
00268             else
00269             {
00270                 ttisp->tt_ttisgmt = *p++;
00271                 if (ttisp->tt_ttisgmt != TRUE &&
00272                     ttisp->tt_ttisgmt != FALSE)
00273                     return -1;
00274             }
00275         }
00276 
00277         /*
00278          * Out-of-sort ats should mean we're running on a signed time_t system
00279          * but using a data file with unsigned values (or vice versa).
00280          */
00281         for (i = 0; i < sp->timecnt - 2; ++i)
00282             if (sp->ats[i] > sp->ats[i + 1])
00283             {
00284                 ++i;
00285                 if (TYPE_SIGNED(pg_time_t))
00286                 {
00287                     /*
00288                      * Ignore the end (easy).
00289                      */
00290                     sp->timecnt = i;
00291                 }
00292                 else
00293                 {
00294                     /*
00295                      * Ignore the beginning (harder).
00296                      */
00297                     int         j;
00298 
00299                     for (j = 0; j + i < sp->timecnt; ++j)
00300                     {
00301                         sp->ats[j] = sp->ats[j + i];
00302                         sp->types[j] = sp->types[j + i];
00303                     }
00304                     sp->timecnt = j;
00305                 }
00306                 break;
00307             }
00308 
00309         /*
00310          * If this is an old file, we're done.
00311          */
00312         if (u.tzhead.tzh_version[0] == '\0')
00313             break;
00314         nread -= p - u.buf;
00315         for (i = 0; i < nread; ++i)
00316             u.buf[i] = p[i];
00317 
00318         /*
00319          * If this is a narrow integer time_t system, we're done.
00320          */
00321         if (stored >= (int) sizeof(pg_time_t) && TYPE_INTEGRAL(pg_time_t))
00322             break;
00323     }
00324     if (doextend && nread > 2 &&
00325         u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
00326         sp->typecnt + 2 <= TZ_MAX_TYPES)
00327     {
00328         struct state ts;
00329         int         result;
00330 
00331         u.buf[nread - 1] = '\0';
00332         result = tzparse(&u.buf[1], &ts, FALSE);
00333         if (result == 0 && ts.typecnt == 2 &&
00334             sp->charcnt + ts.charcnt <= TZ_MAX_CHARS)
00335         {
00336             for (i = 0; i < 2; ++i)
00337                 ts.ttis[i].tt_abbrind +=
00338                     sp->charcnt;
00339             for (i = 0; i < ts.charcnt; ++i)
00340                 sp->chars[sp->charcnt++] =
00341                     ts.chars[i];
00342             i = 0;
00343             while (i < ts.timecnt &&
00344                    ts.ats[i] <=
00345                    sp->ats[sp->timecnt - 1])
00346                 ++i;
00347             while (i < ts.timecnt &&
00348                    sp->timecnt < TZ_MAX_TIMES)
00349             {
00350                 sp->ats[sp->timecnt] =
00351                     ts.ats[i];
00352                 sp->types[sp->timecnt] =
00353                     sp->typecnt +
00354                     ts.types[i];
00355                 ++sp->timecnt;
00356                 ++i;
00357             }
00358             sp->ttis[sp->typecnt++] = ts.ttis[0];
00359             sp->ttis[sp->typecnt++] = ts.ttis[1];
00360         }
00361     }
00362     if (sp->timecnt > 1)
00363     {
00364         for (i = 1; i < sp->timecnt; ++i)
00365             if (typesequiv(sp, sp->types[i], sp->types[0]) &&
00366                 differ_by_repeat(sp->ats[i], sp->ats[0]))
00367             {
00368                 sp->goback = TRUE;
00369                 break;
00370             }
00371         for (i = sp->timecnt - 2; i >= 0; --i)
00372             if (typesequiv(sp, sp->types[sp->timecnt - 1],
00373                            sp->types[i]) &&
00374                 differ_by_repeat(sp->ats[sp->timecnt - 1],
00375                                  sp->ats[i]))
00376             {
00377                 sp->goahead = TRUE;
00378                 break;
00379             }
00380     }
00381     return 0;
00382 }
00383 
00384 static int
00385 typesequiv(const struct state * sp, int a, int b)
00386 {
00387     int         result;
00388 
00389     if (sp == NULL ||
00390         a < 0 || a >= sp->typecnt ||
00391         b < 0 || b >= sp->typecnt)
00392         result = FALSE;
00393     else
00394     {
00395         const struct ttinfo *ap = &sp->ttis[a];
00396         const struct ttinfo *bp = &sp->ttis[b];
00397 
00398         result = ap->tt_gmtoff == bp->tt_gmtoff &&
00399             ap->tt_isdst == bp->tt_isdst &&
00400             ap->tt_ttisstd == bp->tt_ttisstd &&
00401             ap->tt_ttisgmt == bp->tt_ttisgmt &&
00402             strcmp(&sp->chars[ap->tt_abbrind],
00403                    &sp->chars[bp->tt_abbrind]) == 0;
00404     }
00405     return result;
00406 }
00407 
00408 static const int mon_lengths[2][MONSPERYEAR] = {
00409     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
00410     {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
00411 };
00412 
00413 static const int year_lengths[2] = {
00414     DAYSPERNYEAR, DAYSPERLYEAR
00415 };
00416 
00417 /*
00418  * Given a pointer into a time zone string, scan until a character that is not
00419  * a valid character in a zone name is found. Return a pointer to that
00420  * character.
00421  */
00422 static const char *
00423 getzname(const char *strp)
00424 {
00425     char        c;
00426 
00427     while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
00428            c != '+')
00429         ++strp;
00430     return strp;
00431 }
00432 
00433 /*
00434  * Given a pointer into an extended time zone string, scan until the ending
00435  * delimiter of the zone name is located. Return a pointer to the delimiter.
00436  *
00437  * As with getzname above, the legal character set is actually quite
00438  * restricted, with other characters producing undefined results.
00439  * We don't do any checking here; checking is done later in common-case code.
00440  */
00441 static const char *
00442 getqzname(const char *strp, int delim)
00443 {
00444     int         c;
00445 
00446     while ((c = *strp) != '\0' && c != delim)
00447         ++strp;
00448     return strp;
00449 }
00450 
00451 /*
00452  * Given a pointer into a time zone string, extract a number from that string.
00453  * Check that the number is within a specified range; if it is not, return
00454  * NULL.
00455  * Otherwise, return a pointer to the first character not part of the number.
00456  */
00457 static const char *
00458 getnum(const char *strp, int *nump, int min, int max)
00459 {
00460     char        c;
00461     int         num;
00462 
00463     if (strp == NULL || !is_digit(c = *strp))
00464         return NULL;
00465     num = 0;
00466     do
00467     {
00468         num = num * 10 + (c - '0');
00469         if (num > max)
00470             return NULL;        /* illegal value */
00471         c = *++strp;
00472     } while (is_digit(c));
00473     if (num < min)
00474         return NULL;            /* illegal value */
00475     *nump = num;
00476     return strp;
00477 }
00478 
00479 /*
00480  * Given a pointer into a time zone string, extract a number of seconds,
00481  * in hh[:mm[:ss]] form, from the string.
00482  * If any error occurs, return NULL.
00483  * Otherwise, return a pointer to the first character not part of the number
00484  * of seconds.
00485  */
00486 static const char *
00487 getsecs(const char *strp, long *secsp)
00488 {
00489     int         num;
00490 
00491     /*
00492      * `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
00493      * "M10.4.6/26", which does not conform to Posix, but which specifies the
00494      * equivalent of ``02:00 on the first Sunday on or after 23 Oct''.
00495      */
00496     strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
00497     if (strp == NULL)
00498         return NULL;
00499     *secsp = num * (long) SECSPERHOUR;
00500     if (*strp == ':')
00501     {
00502         ++strp;
00503         strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
00504         if (strp == NULL)
00505             return NULL;
00506         *secsp += num * SECSPERMIN;
00507         if (*strp == ':')
00508         {
00509             ++strp;
00510             /* `SECSPERMIN' allows for leap seconds. */
00511             strp = getnum(strp, &num, 0, SECSPERMIN);
00512             if (strp == NULL)
00513                 return NULL;
00514             *secsp += num;
00515         }
00516     }
00517     return strp;
00518 }
00519 
00520 /*
00521  * Given a pointer into a time zone string, extract an offset, in
00522  * [+-]hh[:mm[:ss]] form, from the string.
00523  * If any error occurs, return NULL.
00524  * Otherwise, return a pointer to the first character not part of the time.
00525  */
00526 static const char *
00527 getoffset(const char *strp, long *offsetp)
00528 {
00529     int         neg = 0;
00530 
00531     if (*strp == '-')
00532     {
00533         neg = 1;
00534         ++strp;
00535     }
00536     else if (*strp == '+')
00537         ++strp;
00538     strp = getsecs(strp, offsetp);
00539     if (strp == NULL)
00540         return NULL;            /* illegal time */
00541     if (neg)
00542         *offsetp = -*offsetp;
00543     return strp;
00544 }
00545 
00546 /*
00547  * Given a pointer into a time zone string, extract a rule in the form
00548  * date[/time]. See POSIX section 8 for the format of "date" and "time".
00549  * If a valid rule is not found, return NULL.
00550  * Otherwise, return a pointer to the first character not part of the rule.
00551  */
00552 static const char *
00553 getrule(const char *strp, struct rule * rulep)
00554 {
00555     if (*strp == 'J')
00556     {
00557         /*
00558          * Julian day.
00559          */
00560         rulep->r_type = JULIAN_DAY;
00561         ++strp;
00562         strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
00563     }
00564     else if (*strp == 'M')
00565     {
00566         /*
00567          * Month, week, day.
00568          */
00569         rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
00570         ++strp;
00571         strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
00572         if (strp == NULL)
00573             return NULL;
00574         if (*strp++ != '.')
00575             return NULL;
00576         strp = getnum(strp, &rulep->r_week, 1, 5);
00577         if (strp == NULL)
00578             return NULL;
00579         if (*strp++ != '.')
00580             return NULL;
00581         strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
00582     }
00583     else if (is_digit(*strp))
00584     {
00585         /*
00586          * Day of year.
00587          */
00588         rulep->r_type = DAY_OF_YEAR;
00589         strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
00590     }
00591     else
00592         return NULL;            /* invalid format */
00593     if (strp == NULL)
00594         return NULL;
00595     if (*strp == '/')
00596     {
00597         /*
00598          * Time specified.
00599          */
00600         ++strp;
00601         strp = getsecs(strp, &rulep->r_time);
00602     }
00603     else
00604         rulep->r_time = 2 * SECSPERHOUR;        /* default = 2:00:00 */
00605     return strp;
00606 }
00607 
00608 /*
00609  * Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
00610  * year, a rule, and the offset from UTC at the time that rule takes effect,
00611  * calculate the Epoch-relative time that rule takes effect.
00612  */
00613 static pg_time_t
00614 transtime(pg_time_t janfirst, int year,
00615           const struct rule * rulep, long offset)
00616 {
00617     int         leapyear;
00618     pg_time_t   value = 0;
00619     int         i,
00620                 d,
00621                 m1,
00622                 yy0,
00623                 yy1,
00624                 yy2,
00625                 dow;
00626 
00627     leapyear = isleap(year);
00628     switch (rulep->r_type)
00629     {
00630 
00631         case JULIAN_DAY:
00632 
00633             /*
00634              * Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
00635              * years. In non-leap years, or if the day number is 59 or less,
00636              * just add SECSPERDAY times the day number-1 to the time of
00637              * January 1, midnight, to get the day.
00638              */
00639             value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
00640             if (leapyear && rulep->r_day >= 60)
00641                 value += SECSPERDAY;
00642             break;
00643 
00644         case DAY_OF_YEAR:
00645 
00646             /*
00647              * n - day of year. Just add SECSPERDAY times the day number to
00648              * the time of January 1, midnight, to get the day.
00649              */
00650             value = janfirst + rulep->r_day * SECSPERDAY;
00651             break;
00652 
00653         case MONTH_NTH_DAY_OF_WEEK:
00654 
00655             /*
00656              * Mm.n.d - nth "dth day" of month m.
00657              */
00658             value = janfirst;
00659             for (i = 0; i < rulep->r_mon - 1; ++i)
00660                 value += mon_lengths[leapyear][i] * SECSPERDAY;
00661 
00662             /*
00663              * Use Zeller's Congruence to get day-of-week of first day of
00664              * month.
00665              */
00666             m1 = (rulep->r_mon + 9) % 12 + 1;
00667             yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
00668             yy1 = yy0 / 100;
00669             yy2 = yy0 % 100;
00670             dow = ((26 * m1 - 2) / 10 +
00671                    1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
00672             if (dow < 0)
00673                 dow += DAYSPERWEEK;
00674 
00675             /*
00676              * "dow" is the day-of-week of the first day of the month. Get the
00677              * day-of-month (zero-origin) of the first "dow" day of the month.
00678              */
00679             d = rulep->r_day - dow;
00680             if (d < 0)
00681                 d += DAYSPERWEEK;
00682             for (i = 1; i < rulep->r_week; ++i)
00683             {
00684                 if (d + DAYSPERWEEK >=
00685                     mon_lengths[leapyear][rulep->r_mon - 1])
00686                     break;
00687                 d += DAYSPERWEEK;
00688             }
00689 
00690             /*
00691              * "d" is the day-of-month (zero-origin) of the day we want.
00692              */
00693             value += d * SECSPERDAY;
00694             break;
00695     }
00696 
00697     /*
00698      * "value" is the Epoch-relative time of 00:00:00 UTC on the day in
00699      * question.  To get the Epoch-relative time of the specified local time
00700      * on that day, add the transition time and the current offset from UTC.
00701      */
00702     return value + rulep->r_time + offset;
00703 }
00704 
00705 /*
00706  * Given a POSIX section 8-style TZ string, fill in the rule tables as
00707  * appropriate.
00708  */
00709 
00710 int
00711 tzparse(const char *name, struct state * sp, int lastditch)
00712 {
00713     const char *stdname;
00714     const char *dstname = NULL;
00715     size_t      stdlen;
00716     size_t      dstlen;
00717     long        stdoffset;
00718     long        dstoffset;
00719     pg_time_t  *atp;
00720     unsigned char *typep;
00721     char       *cp;
00722     int         load_result;
00723 
00724     stdname = name;
00725     if (lastditch)
00726     {
00727         stdlen = strlen(name);  /* length of standard zone name */
00728         name += stdlen;
00729         if (stdlen >= sizeof sp->chars)
00730             stdlen = (sizeof sp->chars) - 1;
00731         stdoffset = 0;
00732 
00733         /*
00734          * Unlike the original zic library, do NOT invoke tzload() here; we
00735          * can't assume pg_open_tzfile() is sane yet, and we don't care about
00736          * leap seconds anyway.
00737          */
00738         sp->goback = sp->goahead = FALSE;
00739         load_result = -1;
00740     }
00741     else
00742     {
00743         if (*name == '<')
00744         {
00745             name++;
00746             stdname = name;
00747             name = getqzname(name, '>');
00748             if (*name != '>')
00749                 return (-1);
00750             stdlen = name - stdname;
00751             name++;
00752         }
00753         else
00754         {
00755             name = getzname(name);
00756             stdlen = name - stdname;
00757         }
00758         if (*name == '\0')
00759             return -1;
00760         name = getoffset(name, &stdoffset);
00761         if (name == NULL)
00762             return -1;
00763         load_result = tzload(TZDEFRULES, NULL, sp, FALSE);
00764     }
00765     if (load_result != 0)
00766         sp->leapcnt = 0;        /* so, we're off a little */
00767     if (*name != '\0')
00768     {
00769         if (*name == '<')
00770         {
00771             dstname = ++name;
00772             name = getqzname(name, '>');
00773             if (*name != '>')
00774                 return -1;
00775             dstlen = name - dstname;
00776             name++;
00777         }
00778         else
00779         {
00780             dstname = name;
00781             name = getzname(name);
00782             dstlen = name - dstname;    /* length of DST zone name */
00783         }
00784         if (*name != '\0' && *name != ',' && *name != ';')
00785         {
00786             name = getoffset(name, &dstoffset);
00787             if (name == NULL)
00788                 return -1;
00789         }
00790         else
00791             dstoffset = stdoffset - SECSPERHOUR;
00792         if (*name == '\0' && load_result != 0)
00793             name = TZDEFRULESTRING;
00794         if (*name == ',' || *name == ';')
00795         {
00796             struct rule start;
00797             struct rule end;
00798             int         year;
00799             pg_time_t   janfirst;
00800             pg_time_t   starttime;
00801             pg_time_t   endtime;
00802 
00803             ++name;
00804             if ((name = getrule(name, &start)) == NULL)
00805                 return -1;
00806             if (*name++ != ',')
00807                 return -1;
00808             if ((name = getrule(name, &end)) == NULL)
00809                 return -1;
00810             if (*name != '\0')
00811                 return -1;
00812             sp->typecnt = 2;    /* standard time and DST */
00813 
00814             /*
00815              * Two transitions per year, from EPOCH_YEAR forward.
00816              */
00817             sp->ttis[0].tt_gmtoff = -dstoffset;
00818             sp->ttis[0].tt_isdst = 1;
00819             sp->ttis[0].tt_abbrind = stdlen + 1;
00820             sp->ttis[1].tt_gmtoff = -stdoffset;
00821             sp->ttis[1].tt_isdst = 0;
00822             sp->ttis[1].tt_abbrind = 0;
00823             atp = sp->ats;
00824             typep = sp->types;
00825             janfirst = 0;
00826             sp->timecnt = 0;
00827             for (year = EPOCH_YEAR;
00828                  sp->timecnt + 2 <= TZ_MAX_TIMES;
00829                  ++year)
00830             {
00831                 pg_time_t   newfirst;
00832 
00833                 starttime = transtime(janfirst, year, &start,
00834                                       stdoffset);
00835                 endtime = transtime(janfirst, year, &end,
00836                                     dstoffset);
00837                 if (starttime > endtime)
00838                 {
00839                     *atp++ = endtime;
00840                     *typep++ = 1;       /* DST ends */
00841                     *atp++ = starttime;
00842                     *typep++ = 0;       /* DST begins */
00843                 }
00844                 else
00845                 {
00846                     *atp++ = starttime;
00847                     *typep++ = 0;       /* DST begins */
00848                     *atp++ = endtime;
00849                     *typep++ = 1;       /* DST ends */
00850                 }
00851                 sp->timecnt += 2;
00852                 newfirst = janfirst;
00853                 newfirst += year_lengths[isleap(year)] *
00854                     SECSPERDAY;
00855                 if (newfirst <= janfirst)
00856                     break;
00857                 janfirst = newfirst;
00858             }
00859         }
00860         else
00861         {
00862             long        theirstdoffset;
00863             long        theirdstoffset;
00864             long        theiroffset;
00865             int         isdst;
00866             int         i;
00867             int         j;
00868 
00869             if (*name != '\0')
00870                 return -1;
00871 
00872             /*
00873              * Initial values of theirstdoffset and theirdstoffset.
00874              */
00875             theirstdoffset = 0;
00876             for (i = 0; i < sp->timecnt; ++i)
00877             {
00878                 j = sp->types[i];
00879                 if (!sp->ttis[j].tt_isdst)
00880                 {
00881                     theirstdoffset =
00882                         -sp->ttis[j].tt_gmtoff;
00883                     break;
00884                 }
00885             }
00886             theirdstoffset = 0;
00887             for (i = 0; i < sp->timecnt; ++i)
00888             {
00889                 j = sp->types[i];
00890                 if (sp->ttis[j].tt_isdst)
00891                 {
00892                     theirdstoffset =
00893                         -sp->ttis[j].tt_gmtoff;
00894                     break;
00895                 }
00896             }
00897 
00898             /*
00899              * Initially we're assumed to be in standard time.
00900              */
00901             isdst = FALSE;
00902             theiroffset = theirstdoffset;
00903 
00904             /*
00905              * Now juggle transition times and types tracking offsets as you
00906              * do.
00907              */
00908             for (i = 0; i < sp->timecnt; ++i)
00909             {
00910                 j = sp->types[i];
00911                 sp->types[i] = sp->ttis[j].tt_isdst;
00912                 if (sp->ttis[j].tt_ttisgmt)
00913                 {
00914                     /* No adjustment to transition time */
00915                 }
00916                 else
00917                 {
00918                     /*
00919                      * If summer time is in effect, and the transition time
00920                      * was not specified as standard time, add the summer time
00921                      * offset to the transition time; otherwise, add the
00922                      * standard time offset to the transition time.
00923                      */
00924 
00925                     /*
00926                      * Transitions from DST to DDST will effectively disappear
00927                      * since POSIX provides for only one DST offset.
00928                      */
00929                     if (isdst && !sp->ttis[j].tt_ttisstd)
00930                     {
00931                         sp->ats[i] += dstoffset -
00932                             theirdstoffset;
00933                     }
00934                     else
00935                     {
00936                         sp->ats[i] += stdoffset -
00937                             theirstdoffset;
00938                     }
00939                 }
00940                 theiroffset = -sp->ttis[j].tt_gmtoff;
00941                 if (sp->ttis[j].tt_isdst)
00942                     theirdstoffset = theiroffset;
00943                 else
00944                     theirstdoffset = theiroffset;
00945             }
00946 
00947             /*
00948              * Finally, fill in ttis. ttisstd and ttisgmt need not be handled.
00949              */
00950             sp->ttis[0].tt_gmtoff = -stdoffset;
00951             sp->ttis[0].tt_isdst = FALSE;
00952             sp->ttis[0].tt_abbrind = 0;
00953             sp->ttis[1].tt_gmtoff = -dstoffset;
00954             sp->ttis[1].tt_isdst = TRUE;
00955             sp->ttis[1].tt_abbrind = stdlen + 1;
00956             sp->typecnt = 2;
00957         }
00958     }
00959     else
00960     {
00961         dstlen = 0;
00962         sp->typecnt = 1;        /* only standard time */
00963         sp->timecnt = 0;
00964         sp->ttis[0].tt_gmtoff = -stdoffset;
00965         sp->ttis[0].tt_isdst = 0;
00966         sp->ttis[0].tt_abbrind = 0;
00967     }
00968     sp->charcnt = stdlen + 1;
00969     if (dstlen != 0)
00970         sp->charcnt += dstlen + 1;
00971     if ((size_t) sp->charcnt > sizeof sp->chars)
00972         return -1;
00973     cp = sp->chars;
00974     (void) strncpy(cp, stdname, stdlen);
00975     cp += stdlen;
00976     *cp++ = '\0';
00977     if (dstlen != 0)
00978     {
00979         (void) strncpy(cp, dstname, dstlen);
00980         *(cp + dstlen) = '\0';
00981     }
00982     return 0;
00983 }
00984 
00985 static void
00986 gmtload(struct state * sp)
00987 {
00988     if (tzload(gmt, NULL, sp, TRUE) != 0)
00989         (void) tzparse(gmt, sp, TRUE);
00990 }
00991 
00992 
00993 /*
00994  * The easy way to behave "as if no library function calls" localtime
00995  * is to not call it--so we drop its guts into "localsub", which can be
00996  * freely called. (And no, the PANS doesn't require the above behavior--
00997  * but it *is* desirable.)
00998  *
00999  * The unused offset argument is for the benefit of mktime variants.
01000  */
01001 static struct pg_tm *
01002 localsub(const pg_time_t *timep, long offset,
01003          struct pg_tm * tmp, const pg_tz *tz)
01004 {
01005     const struct state *sp;
01006     const struct ttinfo *ttisp;
01007     int         i;
01008     struct pg_tm *result;
01009     const pg_time_t t = *timep;
01010 
01011     sp = &tz->state;
01012     if ((sp->goback && t < sp->ats[0]) ||
01013         (sp->goahead && t > sp->ats[sp->timecnt - 1]))
01014     {
01015         pg_time_t   newt = t;
01016         pg_time_t   seconds;
01017         pg_time_t   tcycles;
01018         int64       icycles;
01019 
01020         if (t < sp->ats[0])
01021             seconds = sp->ats[0] - t;
01022         else
01023             seconds = t - sp->ats[sp->timecnt - 1];
01024         --seconds;
01025         tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01026         ++tcycles;
01027         icycles = tcycles;
01028         if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01029             return NULL;
01030         seconds = icycles;
01031         seconds *= YEARSPERREPEAT;
01032         seconds *= AVGSECSPERYEAR;
01033         if (t < sp->ats[0])
01034             newt += seconds;
01035         else
01036             newt -= seconds;
01037         if (newt < sp->ats[0] ||
01038             newt > sp->ats[sp->timecnt - 1])
01039             return NULL;        /* "cannot happen" */
01040         result = localsub(&newt, offset, tmp, tz);
01041         if (result == tmp)
01042         {
01043             pg_time_t   newy;
01044 
01045             newy = tmp->tm_year;
01046             if (t < sp->ats[0])
01047                 newy -= icycles * YEARSPERREPEAT;
01048             else
01049                 newy += icycles * YEARSPERREPEAT;
01050             tmp->tm_year = newy;
01051             if (tmp->tm_year != newy)
01052                 return NULL;
01053         }
01054         return result;
01055     }
01056     if (sp->timecnt == 0 || t < sp->ats[0])
01057     {
01058         i = 0;
01059         while (sp->ttis[i].tt_isdst)
01060             if (++i >= sp->typecnt)
01061             {
01062                 i = 0;
01063                 break;
01064             }
01065     }
01066     else
01067     {
01068         int         lo = 1;
01069         int         hi = sp->timecnt;
01070 
01071         while (lo < hi)
01072         {
01073             int         mid = (lo + hi) >> 1;
01074 
01075             if (t < sp->ats[mid])
01076                 hi = mid;
01077             else
01078                 lo = mid + 1;
01079         }
01080         i = (int) sp->types[lo - 1];
01081     }
01082     ttisp = &sp->ttis[i];
01083 
01084     result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
01085     tmp->tm_isdst = ttisp->tt_isdst;
01086     tmp->tm_zone = &sp->chars[ttisp->tt_abbrind];
01087     return result;
01088 }
01089 
01090 
01091 struct pg_tm *
01092 pg_localtime(const pg_time_t *timep, const pg_tz *tz)
01093 {
01094     return localsub(timep, 0L, &tm, tz);
01095 }
01096 
01097 
01098 /*
01099  * gmtsub is to gmtime as localsub is to localtime.
01100  */
01101 static struct pg_tm *
01102 gmtsub(const pg_time_t *timep, long offset, struct pg_tm * tmp)
01103 {
01104     struct pg_tm *result;
01105 
01106     if (!gmt_is_set)
01107     {
01108         gmt_is_set = TRUE;
01109         gmtload(gmtptr);
01110     }
01111     result = timesub(timep, offset, gmtptr, tmp);
01112 
01113     /*
01114      * Could get fancy here and deliver something such as "UTC+xxxx" or
01115      * "UTC-xxxx" if offset is non-zero, but this is no time for a treasure
01116      * hunt.
01117      */
01118     if (offset != 0)
01119         tmp->tm_zone = wildabbr;
01120     else
01121         tmp->tm_zone = gmtptr->chars;
01122 
01123     return result;
01124 }
01125 
01126 struct pg_tm *
01127 pg_gmtime(const pg_time_t *timep)
01128 {
01129     return gmtsub(timep, 0L, &tm);
01130 }
01131 
01132 /*
01133  * Return the number of leap years through the end of the given year
01134  * where, to make the math easy, the answer for year zero is defined as zero.
01135  */
01136 static int
01137 leaps_thru_end_of(const int y)
01138 {
01139     return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
01140         -(leaps_thru_end_of(-(y + 1)) + 1);
01141 }
01142 
01143 
01144 static struct pg_tm *
01145 timesub(const pg_time_t *timep, long offset,
01146         const struct state * sp, struct pg_tm * tmp)
01147 {
01148     const struct lsinfo *lp;
01149     pg_time_t   tdays;
01150     int         idays;          /* unsigned would be so 2003 */
01151     long        rem;
01152     int         y;
01153     const int  *ip;
01154     long        corr;
01155     int         hit;
01156     int         i;
01157 
01158     corr = 0;
01159     hit = 0;
01160     i = sp->leapcnt;
01161     while (--i >= 0)
01162     {
01163         lp = &sp->lsis[i];
01164         if (*timep >= lp->ls_trans)
01165         {
01166             if (*timep == lp->ls_trans)
01167             {
01168                 hit = ((i == 0 && lp->ls_corr > 0) ||
01169                        lp->ls_corr > sp->lsis[i - 1].ls_corr);
01170                 if (hit)
01171                     while (i > 0 &&
01172                            sp->lsis[i].ls_trans ==
01173                            sp->lsis[i - 1].ls_trans + 1 &&
01174                            sp->lsis[i].ls_corr ==
01175                            sp->lsis[i - 1].ls_corr + 1)
01176                     {
01177                         ++hit;
01178                         --i;
01179                     }
01180             }
01181             corr = lp->ls_corr;
01182             break;
01183         }
01184     }
01185     y = EPOCH_YEAR;
01186     tdays = *timep / SECSPERDAY;
01187     rem = *timep - tdays * SECSPERDAY;
01188     while (tdays < 0 || tdays >= year_lengths[isleap(y)])
01189     {
01190         int         newy;
01191         pg_time_t   tdelta;
01192         int         idelta;
01193         int         leapdays;
01194 
01195         tdelta = tdays / DAYSPERLYEAR;
01196         idelta = tdelta;
01197         if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
01198             return NULL;
01199         if (idelta == 0)
01200             idelta = (tdays < 0) ? -1 : 1;
01201         newy = y;
01202         if (increment_overflow(&newy, idelta))
01203             return NULL;
01204         leapdays = leaps_thru_end_of(newy - 1) -
01205             leaps_thru_end_of(y - 1);
01206         tdays -= ((pg_time_t) newy - y) * DAYSPERNYEAR;
01207         tdays -= leapdays;
01208         y = newy;
01209     }
01210     {
01211         long        seconds;
01212 
01213         seconds = tdays * SECSPERDAY + 0.5;
01214         tdays = seconds / SECSPERDAY;
01215         rem += seconds - tdays * SECSPERDAY;
01216     }
01217 
01218     /*
01219      * Given the range, we can now fearlessly cast...
01220      */
01221     idays = tdays;
01222     rem += offset - corr;
01223     while (rem < 0)
01224     {
01225         rem += SECSPERDAY;
01226         --idays;
01227     }
01228     while (rem >= SECSPERDAY)
01229     {
01230         rem -= SECSPERDAY;
01231         ++idays;
01232     }
01233     while (idays < 0)
01234     {
01235         if (increment_overflow(&y, -1))
01236             return NULL;
01237         idays += year_lengths[isleap(y)];
01238     }
01239     while (idays >= year_lengths[isleap(y)])
01240     {
01241         idays -= year_lengths[isleap(y)];
01242         if (increment_overflow(&y, 1))
01243             return NULL;
01244     }
01245     tmp->tm_year = y;
01246     if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
01247         return NULL;
01248     tmp->tm_yday = idays;
01249 
01250     /*
01251      * The "extra" mods below avoid overflow problems.
01252      */
01253     tmp->tm_wday = EPOCH_WDAY +
01254         ((y - EPOCH_YEAR) % DAYSPERWEEK) *
01255         (DAYSPERNYEAR % DAYSPERWEEK) +
01256         leaps_thru_end_of(y - 1) -
01257         leaps_thru_end_of(EPOCH_YEAR - 1) +
01258         idays;
01259     tmp->tm_wday %= DAYSPERWEEK;
01260     if (tmp->tm_wday < 0)
01261         tmp->tm_wday += DAYSPERWEEK;
01262     tmp->tm_hour = (int) (rem / SECSPERHOUR);
01263     rem %= SECSPERHOUR;
01264     tmp->tm_min = (int) (rem / SECSPERMIN);
01265 
01266     /*
01267      * A positive leap second requires a special representation. This uses
01268      * "... ??:59:60" et seq.
01269      */
01270     tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
01271     ip = mon_lengths[isleap(y)];
01272     for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
01273         idays -= ip[tmp->tm_mon];
01274     tmp->tm_mday = (int) (idays + 1);
01275     tmp->tm_isdst = 0;
01276     tmp->tm_gmtoff = offset;
01277     return tmp;
01278 }
01279 
01280 /*
01281  * Simplified normalize logic courtesy Paul Eggert.
01282  */
01283 
01284 static int
01285 increment_overflow(int *number, int delta)
01286 {
01287     int         number0;
01288 
01289     number0 = *number;
01290     *number += delta;
01291     return (*number < number0) != (delta < 0);
01292 }
01293 
01294 /*
01295  * Find the next DST transition time after the given time
01296  *
01297  * *timep is the input value, the other parameters are output values.
01298  *
01299  * When the function result is 1, *boundary is set to the time_t
01300  * representation of the next DST transition time after *timep,
01301  * *before_gmtoff and *before_isdst are set to the GMT offset and isdst
01302  * state prevailing just before that boundary (in particular, the state
01303  * prevailing at *timep), and *after_gmtoff and *after_isdst are set to
01304  * the state prevailing just after that boundary.
01305  *
01306  * When the function result is 0, there is no known DST transition
01307  * after *timep, but *before_gmtoff and *before_isdst indicate the GMT
01308  * offset and isdst state prevailing at *timep.  (This would occur in
01309  * DST-less time zones, or if a zone has permanently ceased using DST.)
01310  *
01311  * A function result of -1 indicates failure (this case does not actually
01312  * occur in our current implementation).
01313  */
01314 int
01315 pg_next_dst_boundary(const pg_time_t *timep,
01316                      long int *before_gmtoff,
01317                      int *before_isdst,
01318                      pg_time_t *boundary,
01319                      long int *after_gmtoff,
01320                      int *after_isdst,
01321                      const pg_tz *tz)
01322 {
01323     const struct state *sp;
01324     const struct ttinfo *ttisp;
01325     int         i;
01326     int         j;
01327     const pg_time_t t = *timep;
01328 
01329     sp = &tz->state;
01330     if (sp->timecnt == 0)
01331     {
01332         /* non-DST zone, use lowest-numbered standard type */
01333         i = 0;
01334         while (sp->ttis[i].tt_isdst)
01335             if (++i >= sp->typecnt)
01336             {
01337                 i = 0;
01338                 break;
01339             }
01340         ttisp = &sp->ttis[i];
01341         *before_gmtoff = ttisp->tt_gmtoff;
01342         *before_isdst = ttisp->tt_isdst;
01343         return 0;
01344     }
01345     if ((sp->goback && t < sp->ats[0]) ||
01346         (sp->goahead && t > sp->ats[sp->timecnt - 1]))
01347     {
01348         /* For values outside the transition table, extrapolate */
01349         pg_time_t   newt = t;
01350         pg_time_t   seconds;
01351         pg_time_t   tcycles;
01352         int64       icycles;
01353         int         result;
01354 
01355         if (t < sp->ats[0])
01356             seconds = sp->ats[0] - t;
01357         else
01358             seconds = t - sp->ats[sp->timecnt - 1];
01359         --seconds;
01360         tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
01361         ++tcycles;
01362         icycles = tcycles;
01363         if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
01364             return -1;
01365         seconds = icycles;
01366         seconds *= YEARSPERREPEAT;
01367         seconds *= AVGSECSPERYEAR;
01368         if (t < sp->ats[0])
01369             newt += seconds;
01370         else
01371             newt -= seconds;
01372         if (newt < sp->ats[0] ||
01373             newt > sp->ats[sp->timecnt - 1])
01374             return -1;          /* "cannot happen" */
01375 
01376         result = pg_next_dst_boundary(&newt, before_gmtoff,
01377                                       before_isdst,
01378                                       boundary,
01379                                       after_gmtoff,
01380                                       after_isdst,
01381                                       tz);
01382         if (t < sp->ats[0])
01383             *boundary -= seconds;
01384         else
01385             *boundary += seconds;
01386         return result;
01387     }
01388 
01389     if (t >= sp->ats[sp->timecnt - 1])
01390     {
01391         /* No known transition > t, so use last known segment's type */
01392         i = sp->types[sp->timecnt - 1];
01393         ttisp = &sp->ttis[i];
01394         *before_gmtoff = ttisp->tt_gmtoff;
01395         *before_isdst = ttisp->tt_isdst;
01396         return 0;
01397     }
01398     if (t < sp->ats[0])
01399     {
01400         /* For "before", use lowest-numbered standard type */
01401         i = 0;
01402         while (sp->ttis[i].tt_isdst)
01403             if (++i >= sp->typecnt)
01404             {
01405                 i = 0;
01406                 break;
01407             }
01408         ttisp = &sp->ttis[i];
01409         *before_gmtoff = ttisp->tt_gmtoff;
01410         *before_isdst = ttisp->tt_isdst;
01411         *boundary = sp->ats[0];
01412         /* And for "after", use the first segment's type */
01413         i = sp->types[0];
01414         ttisp = &sp->ttis[i];
01415         *after_gmtoff = ttisp->tt_gmtoff;
01416         *after_isdst = ttisp->tt_isdst;
01417         return 1;
01418     }
01419     /* Else search to find the boundary following t */
01420     {
01421         int         lo = 1;
01422         int         hi = sp->timecnt - 1;
01423 
01424         while (lo < hi)
01425         {
01426             int         mid = (lo + hi) >> 1;
01427 
01428             if (t < sp->ats[mid])
01429                 hi = mid;
01430             else
01431                 lo = mid + 1;
01432         }
01433         i = lo;
01434     }
01435     j = sp->types[i - 1];
01436     ttisp = &sp->ttis[j];
01437     *before_gmtoff = ttisp->tt_gmtoff;
01438     *before_isdst = ttisp->tt_isdst;
01439     *boundary = sp->ats[i];
01440     j = sp->types[i];
01441     ttisp = &sp->ttis[j];
01442     *after_gmtoff = ttisp->tt_gmtoff;
01443     *after_isdst = ttisp->tt_isdst;
01444     return 1;
01445 }
01446 
01447 /*
01448  * If the given timezone uses only one GMT offset, store that offset
01449  * into *gmtoff and return TRUE, else return FALSE.
01450  */
01451 bool
01452 pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff)
01453 {
01454     /*
01455      * The zone could have more than one ttinfo, if it's historically used
01456      * more than one abbreviation.  We return TRUE as long as they all have
01457      * the same gmtoff.
01458      */
01459     const struct state *sp;
01460     int         i;
01461 
01462     sp = &tz->state;
01463     for (i = 1; i < sp->typecnt; i++)
01464     {
01465         if (sp->ttis[i].tt_gmtoff != sp->ttis[0].tt_gmtoff)
01466             return false;
01467     }
01468     *gmtoff = sp->ttis[0].tt_gmtoff;
01469     return true;
01470 }
01471 
01472 /*
01473  * Return the name of the current timezone
01474  */
01475 const char *
01476 pg_get_timezone_name(pg_tz *tz)
01477 {
01478     if (tz)
01479         return tz->TZname;
01480     return NULL;
01481 }
01482 
01483 /*
01484  * Check whether timezone is acceptable.
01485  *
01486  * What we are doing here is checking for leap-second-aware timekeeping.
01487  * We need to reject such TZ settings because they'll wreak havoc with our
01488  * date/time arithmetic.
01489  */
01490 bool
01491 pg_tz_acceptable(pg_tz *tz)
01492 {
01493     struct pg_tm *tt;
01494     pg_time_t   time2000;
01495 
01496     /*
01497      * To detect leap-second timekeeping, run pg_localtime for what should be
01498      * GMT midnight, 2000-01-01.  Insist that the tm_sec value be zero; any
01499      * other result has to be due to leap seconds.
01500      */
01501     time2000 = (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
01502     tt = pg_localtime(&time2000, tz);
01503     if (!tt || tt->tm_sec != 0)
01504         return false;
01505 
01506     return true;
01507 }