Header And Logo

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

Data Structures | Defines | Typedefs | Functions | Variables

pgtime.h File Reference

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  pg_tm

Defines

#define TZ_STRLEN_MAX   255

Typedefs

typedef int64 pg_time_t
typedef struct pg_tz pg_tz
typedef struct pg_tzenum pg_tzenum

Functions

struct pg_tmpg_localtime (const pg_time_t *timep, const pg_tz *tz)
struct pg_tmpg_gmtime (const pg_time_t *timep)
int pg_next_dst_boundary (const pg_time_t *timep, long int *before_gmtoff, int *before_isdst, pg_time_t *boundary, long int *after_gmtoff, int *after_isdst, const pg_tz *tz)
size_t pg_strftime (char *s, size_t max, const char *format, const struct pg_tm *tm)
bool pg_get_timezone_offset (const pg_tz *tz, long int *gmtoff)
const char * pg_get_timezone_name (pg_tz *tz)
bool pg_tz_acceptable (pg_tz *tz)
void pg_timezone_initialize (void)
pg_tzpg_tzset (const char *tzname)
pg_tzenumpg_tzenumerate_start (void)
pg_tzpg_tzenumerate_next (pg_tzenum *dir)
void pg_tzenumerate_end (pg_tzenum *dir)

Variables

pg_tzsession_timezone
pg_tzlog_timezone

Define Documentation

#define TZ_STRLEN_MAX   255

Typedef Documentation

typedef int64 pg_time_t

Definition at line 23 of file pgtime.h.

typedef struct pg_tz pg_tz

Definition at line 40 of file pgtime.h.

typedef struct pg_tzenum pg_tzenum

Definition at line 41 of file pgtime.h.


Function Documentation

const char* pg_get_timezone_name ( pg_tz tz  ) 

Definition at line 1476 of file localtime.c.

References pg_tz::TZname.

Referenced by pg_timezone_names(), show_log_timezone(), and show_timezone().

{
    if (tz)
        return tz->TZname;
    return NULL;
}

bool pg_get_timezone_offset ( const pg_tz tz,
long int *  gmtoff 
)

Definition at line 1452 of file localtime.c.

References i, pg_tz::state, ttinfo::tt_gmtoff, state::ttis, and state::typecnt.

Referenced by DecodeTimeOnly().

{
    /*
     * The zone could have more than one ttinfo, if it's historically used
     * more than one abbreviation.  We return TRUE as long as they all have
     * the same gmtoff.
     */
    const struct state *sp;
    int         i;

    sp = &tz->state;
    for (i = 1; i < sp->typecnt; i++)
    {
        if (sp->ttis[i].tt_gmtoff != sp->ttis[0].tt_gmtoff)
            return false;
    }
    *gmtoff = sp->ttis[0].tt_gmtoff;
    return true;
}

struct pg_tm* pg_gmtime ( const pg_time_t timep  )  [read]

Definition at line 1127 of file localtime.c.

References gmtsub(), and tm.

Referenced by abstime2tm(), and GetEpochTime().

{
    return gmtsub(timep, 0L, &tm);
}

struct pg_tm* pg_localtime ( const pg_time_t timep,
const pg_tz tz 
) [read]
int pg_next_dst_boundary ( const pg_time_t timep,
long int *  before_gmtoff,
int *  before_isdst,
pg_time_t boundary,
long int *  after_gmtoff,
int *  after_isdst,
const pg_tz tz 
)

Definition at line 1315 of file localtime.c.

References state::ats, state::goahead, state::goback, i, pg_next_dst_boundary(), pg_tz::state, state::timecnt, ttinfo::tt_gmtoff, ttinfo::tt_isdst, state::ttis, state::typecnt, state::types, and YEARSPERREPEAT.

Referenced by DetermineTimeZoneOffset(), and pg_next_dst_boundary().

{
    const struct state *sp;
    const struct ttinfo *ttisp;
    int         i;
    int         j;
    const pg_time_t t = *timep;

    sp = &tz->state;
    if (sp->timecnt == 0)
    {
        /* non-DST zone, use lowest-numbered standard type */
        i = 0;
        while (sp->ttis[i].tt_isdst)
            if (++i >= sp->typecnt)
            {
                i = 0;
                break;
            }
        ttisp = &sp->ttis[i];
        *before_gmtoff = ttisp->tt_gmtoff;
        *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 */
        i = sp->types[sp->timecnt - 1];
        ttisp = &sp->ttis[i];
        *before_gmtoff = ttisp->tt_gmtoff;
        *before_isdst = ttisp->tt_isdst;
        return 0;
    }
    if (t < sp->ats[0])
    {
        /* For "before", use lowest-numbered standard type */
        i = 0;
        while (sp->ttis[i].tt_isdst)
            if (++i >= sp->typecnt)
            {
                i = 0;
                break;
            }
        ttisp = &sp->ttis[i];
        *before_gmtoff = ttisp->tt_gmtoff;
        *before_isdst = ttisp->tt_isdst;
        *boundary = sp->ats[0];
        /* And for "after", use the first segment's type */
        i = sp->types[0];
        ttisp = &sp->ttis[i];
        *after_gmtoff = ttisp->tt_gmtoff;
        *after_isdst = ttisp->tt_isdst;
        return 1;
    }
    /* Else search to find the boundary following t */
    {
        int         lo = 1;
        int         hi = sp->timecnt - 1;

        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;
    *before_isdst = ttisp->tt_isdst;
    *boundary = sp->ats[i];
    j = sp->types[i];
    ttisp = &sp->ttis[j];
    *after_gmtoff = ttisp->tt_gmtoff;
    *after_isdst = ttisp->tt_isdst;
    return 1;
}

size_t pg_strftime ( char *  s,
size_t  max,
const char *  format,
const struct pg_tm tm 
)

Definition at line 105 of file strftime.c.

References _fmt(), and NULL.

Referenced by do_pg_start_backup(), do_pg_stop_backup(), log_line_prefix(), logfile_getname(), setup_formatted_log_time(), setup_formatted_start_time(), str_time(), and timeofday().

{
    char       *p;
    int         warn;

    warn = IN_NONE;
    p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
    if (p == s + maxsize)
        return 0;
    *p = '\0';
    return p - s;
}

void pg_timezone_initialize ( void   ) 

Definition at line 302 of file pgtz.c.

References pg_tzset().

Referenced by InitializeGUCOptions().

{
    /*
     * We may not yet know where PGSHAREDIR is (in particular this is true in
     * an EXEC_BACKEND subprocess).  So use "GMT", which pg_tzset forces to be
     * interpreted without reference to the filesystem.  This corresponds to
     * the bootstrap default for these variables in guc.c, although in
     * principle it could be different.
     */
    session_timezone = pg_tzset("GMT");
    log_timezone = session_timezone;
}

bool pg_tz_acceptable ( pg_tz tz  ) 

Definition at line 1491 of file localtime.c.

References pg_localtime(), POSTGRES_EPOCH_JDATE, SECS_PER_DAY, and pg_tm::tm_sec.

Referenced by check_log_timezone(), check_timezone(), pg_tzenumerate_next(), score_timezone(), and validate_zone().

{
    struct pg_tm *tt;
    pg_time_t   time2000;

    /*
     * To detect leap-second timekeeping, run pg_localtime for what should be
     * GMT midnight, 2000-01-01.  Insist that the tm_sec value be zero; any
     * other result has to be due to leap seconds.
     */
    time2000 = (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
    tt = pg_localtime(&time2000, tz);
    if (!tt || tt->tm_sec != 0)
        return false;

    return true;
}

void pg_tzenumerate_end ( pg_tzenum dir  ) 

Definition at line 355 of file pgtz.c.

References pg_tzenum::depth, pg_tzenum::dirdesc, pg_tzenum::dirname, FreeDir(), and pfree().

Referenced by pg_timezone_names().

{
    while (dir->depth >= 0)
    {
        FreeDir(dir->dirdesc[dir->depth]);
        pfree(dir->dirname[dir->depth]);
        dir->depth--;
    }
    pfree(dir);
}

pg_tz* pg_tzenumerate_next ( pg_tzenum dir  ) 

Definition at line 367 of file pgtz.c.

References AllocateDir(), pg_tzenum::baselen, pg_tzenum::depth, pg_tzenum::dirdesc, pg_tzenum::dirname, ereport, errcode_for_file_access(), errmsg(), errmsg_internal(), ERROR, FreeDir(), MAX_TZDIR_DEPTH, MAXPGPATH, pfree(), pg_tz_acceptable(), pstrdup(), ReadDir(), snprintf(), pg_tz::state, TRUE, pg_tzenum::tz, tzload(), and pg_tz::TZname.

Referenced by pg_timezone_names().

{
    while (dir->depth >= 0)
    {
        struct dirent *direntry;
        char        fullname[MAXPGPATH];
        struct stat statbuf;

        direntry = ReadDir(dir->dirdesc[dir->depth], dir->dirname[dir->depth]);

        if (!direntry)
        {
            /* End of this directory */
            FreeDir(dir->dirdesc[dir->depth]);
            pfree(dir->dirname[dir->depth]);
            dir->depth--;
            continue;
        }

        if (direntry->d_name[0] == '.')
            continue;

        snprintf(fullname, MAXPGPATH, "%s/%s",
                 dir->dirname[dir->depth], direntry->d_name);
        if (stat(fullname, &statbuf) != 0)
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("could not stat \"%s\": %m", fullname)));

        if (S_ISDIR(statbuf.st_mode))
        {
            /* Step into the subdirectory */
            if (dir->depth >= MAX_TZDIR_DEPTH - 1)
                ereport(ERROR,
                     (errmsg_internal("timezone directory stack overflow")));
            dir->depth++;
            dir->dirname[dir->depth] = pstrdup(fullname);
            dir->dirdesc[dir->depth] = AllocateDir(fullname);
            if (!dir->dirdesc[dir->depth])
                ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not open directory \"%s\": %m",
                                fullname)));

            /* Start over reading in the new directory */
            continue;
        }

        /*
         * Load this timezone using tzload() not pg_tzset(), so we don't fill
         * the cache
         */
        if (tzload(fullname + dir->baselen, dir->tz.TZname, &dir->tz.state,
                   TRUE) != 0)
        {
            /* Zone could not be loaded, ignore it */
            continue;
        }

        if (!pg_tz_acceptable(&dir->tz))
        {
            /* Ignore leap-second zones */
            continue;
        }

        /* Timezone loaded OK. */
        return &dir->tz;
    }

    /* Nothing more found */
    return NULL;
}

pg_tzenum* pg_tzenumerate_start ( void   ) 

Definition at line 338 of file pgtz.c.

References AllocateDir(), pg_tzenum::baselen, pg_tzenum::depth, pg_tzenum::dirdesc, pg_tzenum::dirname, ereport, errcode_for_file_access(), errmsg(), ERROR, palloc0(), pg_TZDIR(), and pstrdup().

Referenced by pg_timezone_names().

{
    pg_tzenum  *ret = (pg_tzenum *) palloc0(sizeof(pg_tzenum));
    char       *startdir = pstrdup(pg_TZDIR());

    ret->baselen = strlen(startdir) + 1;
    ret->depth = 0;
    ret->dirname[0] = startdir;
    ret->dirdesc[0] = AllocateDir(startdir);
    if (!ret->dirdesc[0])
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not open directory \"%s\": %m", startdir)));
    return ret;
}

pg_tz* pg_tzset ( const char *  tzname  ) 

Definition at line 218 of file pgtz.c.

References elog, ERROR, FALSE, HASH_ENTER, HASH_FIND, hash_search(), init_timezone_hashtable(), NULL, pg_toupper(), pg_tz::state, TRUE, pg_tz_cache::tz, TZ_STRLEN_MAX, tzload(), pg_tz::TZname, and tzparse().

Referenced by check_log_timezone(), check_timezone(), DecodeDateTime(), DecodeTimeOnly(), pg_timezone_initialize(), timestamp_zone(), timestamptz_zone(), and timetz_zone().

{
    pg_tz_cache *tzp;
    struct state tzstate;
    char        uppername[TZ_STRLEN_MAX + 1];
    char        canonname[TZ_STRLEN_MAX + 1];
    char       *p;

    if (strlen(name) > TZ_STRLEN_MAX)
        return NULL;            /* not going to fit */

    if (!timezone_cache)
        if (!init_timezone_hashtable())
            return NULL;

    /*
     * Upcase the given name to perform a case-insensitive hashtable search.
     * (We could alternatively downcase it, but we prefer upcase so that we
     * can get consistently upcased results from tzparse() in case the name is
     * a POSIX-style timezone spec.)
     */
    p = uppername;
    while (*name)
        *p++ = pg_toupper((unsigned char) *name++);
    *p = '\0';

    tzp = (pg_tz_cache *) hash_search(timezone_cache,
                                      uppername,
                                      HASH_FIND,
                                      NULL);
    if (tzp)
    {
        /* Timezone found in cache, nothing more to do */
        return &tzp->tz;
    }

    /*
     * "GMT" is always sent to tzparse(), as per discussion above.
     */
    if (strcmp(uppername, "GMT") == 0)
    {
        if (tzparse(uppername, &tzstate, TRUE) != 0)
        {
            /* This really, really should not happen ... */
            elog(ERROR, "could not initialize GMT time zone");
        }
        /* Use uppercase name as canonical */
        strcpy(canonname, uppername);
    }
    else if (tzload(uppername, canonname, &tzstate, TRUE) != 0)
    {
        if (uppername[0] == ':' || tzparse(uppername, &tzstate, FALSE) != 0)
        {
            /* Unknown timezone. Fail our call instead of loading GMT! */
            return NULL;
        }
        /* For POSIX timezone specs, use uppercase name as canonical */
        strcpy(canonname, uppername);
    }

    /* Save timezone in the cache */
    tzp = (pg_tz_cache *) hash_search(timezone_cache,
                                      uppername,
                                      HASH_ENTER,
                                      NULL);

    /* hash_search already copied uppername into the hash key */
    strcpy(tzp->tz.TZname, canonname);
    memcpy(&tzp->tz.state, &tzstate, sizeof(tzstate));

    return &tzp->tz;
}


Variable Documentation