PostgreSQL Source Code git master
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
 

Macros

#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)
 
bool pg_interpret_timezone_abbrev (const char *abbrev, const pg_time_t *timep, long int *gmtoff, int *isdst, const pg_tz *tz)
 
bool pg_timezone_abbrev_is_known (const char *abbrev, bool *isfixed, long int *gmtoff, int *isdst, const pg_tz *tz)
 
const char * pg_get_next_timezone_abbrev (int *indx, const pg_tz *tz)
 
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)
 
size_t pg_strftime (char *s, size_t maxsize, const char *format, const struct pg_tm *t)
 
void pg_timezone_initialize (void)
 
pg_tzpg_tzset (const char *tzname)
 
pg_tzpg_tzset_offset (long gmtoffset)
 
pg_tzenumpg_tzenumerate_start (void)
 
pg_tzpg_tzenumerate_next (pg_tzenum *dir)
 
void pg_tzenumerate_end (pg_tzenum *dir)
 

Variables

PGDLLIMPORT pg_tzsession_timezone
 
PGDLLIMPORT pg_tzlog_timezone
 

Macro Definition Documentation

◆ TZ_STRLEN_MAX

#define TZ_STRLEN_MAX   255

Definition at line 54 of file pgtime.h.

Typedef Documentation

◆ pg_time_t

typedef int64 pg_time_t

Definition at line 23 of file pgtime.h.

◆ pg_tz

typedef struct pg_tz pg_tz

Definition at line 50 of file pgtime.h.

◆ pg_tzenum

typedef struct pg_tzenum pg_tzenum

Definition at line 51 of file pgtime.h.

Function Documentation

◆ pg_get_next_timezone_abbrev()

const char * pg_get_next_timezone_abbrev ( int *  indx,
const pg_tz tz 
)

Definition at line 1937 of file localtime.c.

1939{
1940 const char *result;
1941 const struct state *sp = &tz->state;
1942 const char *abbrs;
1943 int abbrind;
1944
1945 /* If we're still in range, the result is the current abbrev. */
1946 abbrs = sp->chars;
1947 abbrind = *indx;
1948 if (abbrind < 0 || abbrind >= sp->charcnt)
1949 return NULL;
1950 result = abbrs + abbrind;
1951
1952 /* Advance *indx past this abbrev and its trailing null. */
1953 while (abbrs[abbrind] != '\0')
1954 abbrind++;
1955 abbrind++;
1956 *indx = abbrind;
1957
1958 return result;
1959}
struct state state
Definition: pgtz.h:69
Definition: regguts.h:323
int charcnt
Definition: pgtz.h:46
char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS+1, 4),(2 *(TZ_STRLEN_MAX+1)))]
Definition: pgtz.h:53

References state::charcnt, state::chars, and pg_tz::state.

Referenced by pg_timezone_abbrevs_zone().

◆ pg_get_timezone_name()

const char * pg_get_timezone_name ( pg_tz tz)

Definition at line 1990 of file localtime.c.

1991{
1992 if (tz)
1993 return tz->TZname;
1994 return NULL;
1995}
char TZname[TZ_STRLEN_MAX+1]
Definition: pgtz.h:68

References pg_tz::TZname.

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

◆ pg_get_timezone_offset()

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

Definition at line 1966 of file localtime.c.

1967{
1968 /*
1969 * The zone could have more than one ttinfo, if it's historically used
1970 * more than one abbreviation. We return true as long as they all have
1971 * the same gmtoff.
1972 */
1973 const struct state *sp;
1974 int i;
1975
1976 sp = &tz->state;
1977 for (i = 1; i < sp->typecnt; i++)
1978 {
1979 if (sp->ttis[i].tt_utoff != sp->ttis[0].tt_utoff)
1980 return false;
1981 }
1982 *gmtoff = sp->ttis[0].tt_utoff;
1983 return true;
1984}
int i
Definition: isn.c:77
struct ttinfo ttis[TZ_MAX_TYPES]
Definition: pgtz.h:51
int typecnt
Definition: pgtz.h:45
int_fast32_t tt_utoff
Definition: pgtz.h:28

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

Referenced by DecodeTimeOnly(), and TimestampTimestampTzRequiresRewrite().

◆ pg_gmtime()

struct pg_tm * pg_gmtime ( const pg_time_t timep)

Definition at line 1390 of file localtime.c.

1391{
1392 return gmtsub(timep, 0, &tm);
1393}
static struct pg_tm * gmtsub(pg_time_t const *timep, int_fast32_t offset, struct pg_tm *tmp)
Definition: localtime.c:1358
static struct pg_tm tm
Definition: localtime.c:104

References gmtsub(), and tm.

Referenced by AddFileToBackupManifest(), and GetEpochTime().

◆ pg_interpret_timezone_abbrev()

bool pg_interpret_timezone_abbrev ( const char *  abbrev,
const pg_time_t timep,
long int *  gmtoff,
int *  isdst,
const pg_tz tz 
)

Definition at line 1744 of file localtime.c.

1749{
1750 const struct state *sp;
1751 const char *abbrs;
1752 const struct ttinfo *ttisp;
1753 int abbrind;
1754 int cutoff;
1755 int i;
1756 const pg_time_t t = *timep;
1757
1758 sp = &tz->state;
1759
1760 /*
1761 * Locate the abbreviation in the zone's abbreviation list. We assume
1762 * there are not duplicates in the list.
1763 */
1764 abbrs = sp->chars;
1765 abbrind = 0;
1766 while (abbrind < sp->charcnt)
1767 {
1768 if (strcmp(abbrev, abbrs + abbrind) == 0)
1769 break;
1770 while (abbrs[abbrind] != '\0')
1771 abbrind++;
1772 abbrind++;
1773 }
1774 if (abbrind >= sp->charcnt)
1775 return false; /* not there! */
1776
1777 /*
1778 * Unlike pg_next_dst_boundary, we needn't sweat about extrapolation
1779 * (goback/goahead zones). Finding the newest or oldest meaning of the
1780 * abbreviation should get us what we want, since extrapolation would just
1781 * be repeating the newest or oldest meanings.
1782 *
1783 * Use binary search to locate the first transition > cutoff time. (Note
1784 * that sp->timecnt could be zero, in which case this loop does nothing
1785 * and only the defaulttype entry will be checked.)
1786 */
1787 {
1788 int lo = 0;
1789 int hi = sp->timecnt;
1790
1791 while (lo < hi)
1792 {
1793 int mid = (lo + hi) >> 1;
1794
1795 if (t < sp->ats[mid])
1796 hi = mid;
1797 else
1798 lo = mid + 1;
1799 }
1800 cutoff = lo;
1801 }
1802
1803 /*
1804 * Scan backwards to find the latest interval using the given abbrev
1805 * before the cutoff time.
1806 */
1807 for (i = cutoff - 1; i >= 0; i--)
1808 {
1809 ttisp = &sp->ttis[sp->types[i]];
1810 if (ttisp->tt_desigidx == abbrind)
1811 {
1812 *gmtoff = ttisp->tt_utoff;
1813 *isdst = ttisp->tt_isdst;
1814 return true;
1815 }
1816 }
1817
1818 /*
1819 * Not found yet; check the defaulttype, which is notionally the era
1820 * before any of the entries in sp->types[].
1821 */
1822 ttisp = &sp->ttis[sp->defaulttype];
1823 if (ttisp->tt_desigidx == abbrind)
1824 {
1825 *gmtoff = ttisp->tt_utoff;
1826 *isdst = ttisp->tt_isdst;
1827 return true;
1828 }
1829
1830 /*
1831 * Not there, so scan forwards to find the first one after the cutoff.
1832 */
1833 for (i = cutoff; i < sp->timecnt; i++)
1834 {
1835 ttisp = &sp->ttis[sp->types[i]];
1836 if (ttisp->tt_desigidx == abbrind)
1837 {
1838 *gmtoff = ttisp->tt_utoff;
1839 *isdst = ttisp->tt_isdst;
1840 return true;
1841 }
1842 }
1843
1844 return false; /* hm, not actually used in any interval? */
1845}
int64 pg_time_t
Definition: pgtime.h:23
int timecnt
Definition: pgtz.h:44
unsigned char types[TZ_MAX_TIMES]
Definition: pgtz.h:50
int defaulttype
Definition: pgtz.h:61
Definition: pgtz.h:27
int tt_desigidx
Definition: pgtz.h:30
bool tt_isdst
Definition: pgtz.h:29
static int charcnt
Definition: zic.c:178

References state::charcnt, charcnt, state::chars, state::defaulttype, i, pg_tz::state, state::timecnt, ttinfo::tt_desigidx, ttinfo::tt_isdst, ttinfo::tt_utoff, state::ttis, and state::types.

Referenced by DetermineTimeZoneAbbrevOffsetInternal(), and pg_timezone_abbrevs_zone().

◆ pg_localtime()

struct pg_tm * pg_localtime ( const pg_time_t timep,
const pg_tz tz 
)

Definition at line 1345 of file localtime.c.

1346{
1347 return localsub(&tz->state, timep, &tm);
1348}
static struct pg_tm * localsub(struct state const *sp, pg_time_t const *timep, struct pg_tm *const tmp)
Definition: localtime.c:1260

References localsub(), pg_tz::state, and tm.

Referenced by build_backup_content(), get_formatted_log_time(), get_formatted_start_time(), log_status_format(), logfile_getname(), pg_tz_acceptable(), score_timezone(), set_next_rotation_time(), str_time(), timeofday(), and timestamp2tm().

◆ pg_next_dst_boundary()

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 1611 of file localtime.c.

1618{
1619 const struct state *sp;
1620 const struct ttinfo *ttisp;
1621 int i;
1622 int j;
1623 const pg_time_t t = *timep;
1624
1625 sp = &tz->state;
1626 if (sp->timecnt == 0)
1627 {
1628 /* non-DST zone, use the defaulttype */
1629 ttisp = &sp->ttis[sp->defaulttype];
1630 *before_gmtoff = ttisp->tt_utoff;
1631 *before_isdst = ttisp->tt_isdst;
1632 return 0;
1633 }
1634 if ((sp->goback && t < sp->ats[0]) ||
1635 (sp->goahead && t > sp->ats[sp->timecnt - 1]))
1636 {
1637 /* For values outside the transition table, extrapolate */
1638 pg_time_t newt = t;
1639 pg_time_t seconds;
1640 pg_time_t tcycles;
1641 int64 icycles;
1642 int result;
1643
1644 if (t < sp->ats[0])
1645 seconds = sp->ats[0] - t;
1646 else
1647 seconds = t - sp->ats[sp->timecnt - 1];
1648 --seconds;
1649 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1650 ++tcycles;
1651 icycles = tcycles;
1652 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1653 return -1;
1654 seconds = icycles;
1655 seconds *= YEARSPERREPEAT;
1656 seconds *= AVGSECSPERYEAR;
1657 if (t < sp->ats[0])
1658 newt += seconds;
1659 else
1660 newt -= seconds;
1661 if (newt < sp->ats[0] ||
1662 newt > sp->ats[sp->timecnt - 1])
1663 return -1; /* "cannot happen" */
1664
1665 result = pg_next_dst_boundary(&newt, before_gmtoff,
1666 before_isdst,
1667 boundary,
1668 after_gmtoff,
1669 after_isdst,
1670 tz);
1671 if (t < sp->ats[0])
1672 *boundary -= seconds;
1673 else
1674 *boundary += seconds;
1675 return result;
1676 }
1677
1678 if (t >= sp->ats[sp->timecnt - 1])
1679 {
1680 /* No known transition > t, so use last known segment's type */
1681 i = sp->types[sp->timecnt - 1];
1682 ttisp = &sp->ttis[i];
1683 *before_gmtoff = ttisp->tt_utoff;
1684 *before_isdst = ttisp->tt_isdst;
1685 return 0;
1686 }
1687 if (t < sp->ats[0])
1688 {
1689 /* For "before", use the defaulttype */
1690 ttisp = &sp->ttis[sp->defaulttype];
1691 *before_gmtoff = ttisp->tt_utoff;
1692 *before_isdst = ttisp->tt_isdst;
1693 *boundary = sp->ats[0];
1694 /* And for "after", use the first segment's type */
1695 i = sp->types[0];
1696 ttisp = &sp->ttis[i];
1697 *after_gmtoff = ttisp->tt_utoff;
1698 *after_isdst = ttisp->tt_isdst;
1699 return 1;
1700 }
1701 /* Else search to find the boundary following t */
1702 {
1703 int lo = 1;
1704 int hi = sp->timecnt - 1;
1705
1706 while (lo < hi)
1707 {
1708 int mid = (lo + hi) >> 1;
1709
1710 if (t < sp->ats[mid])
1711 hi = mid;
1712 else
1713 lo = mid + 1;
1714 }
1715 i = lo;
1716 }
1717 j = sp->types[i - 1];
1718 ttisp = &sp->ttis[j];
1719 *before_gmtoff = ttisp->tt_utoff;
1720 *before_isdst = ttisp->tt_isdst;
1721 *boundary = sp->ats[i];
1722 j = sp->types[i];
1723 ttisp = &sp->ttis[j];
1724 *after_gmtoff = ttisp->tt_utoff;
1725 *after_isdst = ttisp->tt_isdst;
1726 return 1;
1727}
int64_t int64
Definition: c.h:538
int j
Definition: isn.c:78
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: localtime.c:1611
#define AVGSECSPERYEAR
Definition: private.h:150
#define YEARSPERREPEAT
Definition: private.h:91
bool goback
Definition: pgtz.h:47
pg_time_t ats[TZ_MAX_TIMES]
Definition: pgtz.h:49
bool goahead
Definition: pgtz.h:48

References state::ats, AVGSECSPERYEAR, state::defaulttype, state::goahead, state::goback, i, j, pg_next_dst_boundary(), pg_tz::state, state::timecnt, ttinfo::tt_isdst, ttinfo::tt_utoff, state::ttis, state::types, and YEARSPERREPEAT.

Referenced by DetermineTimeZoneOffsetInternal(), and pg_next_dst_boundary().

◆ pg_strftime()

size_t pg_strftime ( char *  s,
size_t  maxsize,
const char *  format,
const struct pg_tm t 
)

Definition at line 128 of file strftime.c.

129{
130 char *p;
131 int saved_errno = errno;
132 enum warn warn = IN_NONE;
133
134 p = _fmt(format, t, s, s + maxsize, &warn);
135 if (!p)
136 {
137 errno = EOVERFLOW;
138 return 0;
139 }
140 if (p == s + maxsize)
141 {
142 errno = ERANGE;
143 return 0;
144 }
145 *p = '\0';
146 errno = saved_errno;
147 return p - s;
148}
static char format
#define EOVERFLOW
Definition: private.h:41
warn
Definition: strftime.c:110
@ IN_NONE
Definition: strftime.c:111
static char * _fmt(const char *format, const struct pg_tm *t, char *pt, const char *ptlim, enum warn *warnp)
Definition: strftime.c:151

References _fmt(), EOVERFLOW, format, and IN_NONE.

Referenced by AddFileToBackupManifest(), build_backup_content(), get_formatted_log_time(), get_formatted_start_time(), log_status_format(), logfile_getname(), str_time(), and timeofday().

◆ pg_timezone_abbrev_is_known()

bool pg_timezone_abbrev_is_known ( const char *  abbrev,
bool *  isfixed,
long int *  gmtoff,
int *  isdst,
const pg_tz tz 
)

Definition at line 1862 of file localtime.c.

1867{
1868 bool result = false;
1869 const struct state *sp = &tz->state;
1870 const char *abbrs;
1871 int abbrind;
1872
1873 /*
1874 * Locate the abbreviation in the zone's abbreviation list. We assume
1875 * there are not duplicates in the list.
1876 */
1877 abbrs = sp->chars;
1878 abbrind = 0;
1879 while (abbrind < sp->charcnt)
1880 {
1881 if (strcmp(abbrev, abbrs + abbrind) == 0)
1882 break;
1883 while (abbrs[abbrind] != '\0')
1884 abbrind++;
1885 abbrind++;
1886 }
1887 if (abbrind >= sp->charcnt)
1888 return false; /* definitely not there */
1889
1890 /*
1891 * Scan the ttinfo array to find uses of the abbreviation.
1892 */
1893 for (int i = 0; i < sp->typecnt; i++)
1894 {
1895 const struct ttinfo *ttisp = &sp->ttis[i];
1896
1897 if (ttisp->tt_desigidx == abbrind)
1898 {
1899 if (!result)
1900 {
1901 /* First usage */
1902 *isfixed = true; /* for the moment */
1903 *gmtoff = ttisp->tt_utoff;
1904 *isdst = ttisp->tt_isdst;
1905 result = true;
1906 }
1907 else
1908 {
1909 /* Second or later usage, does it match? */
1910 if (*gmtoff != ttisp->tt_utoff ||
1911 *isdst != ttisp->tt_isdst)
1912 {
1913 *isfixed = false;
1914 break; /* no point in looking further */
1915 }
1916 }
1917 }
1918 }
1919
1920 return result;
1921}

References state::charcnt, charcnt, state::chars, i, pg_tz::state, ttinfo::tt_desigidx, ttinfo::tt_isdst, ttinfo::tt_utoff, state::ttis, and state::typecnt.

Referenced by TimeZoneAbbrevIsKnown().

◆ pg_timezone_initialize()

void pg_timezone_initialize ( void  )

Definition at line 361 of file pgtz.c.

362{
363 /*
364 * We may not yet know where PGSHAREDIR is (in particular this is true in
365 * an EXEC_BACKEND subprocess). So use "GMT", which pg_tzset forces to be
366 * interpreted without reference to the filesystem. This corresponds to
367 * the bootstrap default for these variables in guc_parameters.dat,
368 * although in principle it could be different.
369 */
370 session_timezone = pg_tzset("GMT");
372}
pg_tz * log_timezone
Definition: pgtz.c:31
pg_tz * pg_tzset(const char *tzname)
Definition: pgtz.c:234
pg_tz * session_timezone
Definition: pgtz.c:28

References log_timezone, pg_tzset(), and session_timezone.

Referenced by InitializeGUCOptions().

◆ pg_tz_acceptable()

bool pg_tz_acceptable ( pg_tz tz)

Definition at line 2005 of file localtime.c.

2006{
2007 struct pg_tm *tt;
2008 pg_time_t time2000;
2009
2010 /*
2011 * To detect leap-second timekeeping, run pg_localtime for what should be
2012 * GMT midnight, 2000-01-01. Insist that the tm_sec value be zero; any
2013 * other result has to be due to leap seconds.
2014 */
2016 tt = pg_localtime(&time2000, tz);
2017 if (!tt || tt->tm_sec != 0)
2018 return false;
2019
2020 return true;
2021}
#define UNIX_EPOCH_JDATE
Definition: timestamp.h:234
#define SECS_PER_DAY
Definition: timestamp.h:126
#define POSTGRES_EPOCH_JDATE
Definition: timestamp.h:235
struct pg_tm * pg_localtime(const pg_time_t *timep, const pg_tz *tz)
Definition: localtime.c:1345
Definition: pgtime.h:35
int tm_sec
Definition: pgtime.h:36

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

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

◆ pg_tzenumerate_end()

void pg_tzenumerate_end ( pg_tzenum dir)

Definition at line 414 of file pgtz.c.

415{
416 while (dir->depth >= 0)
417 {
418 FreeDir(dir->dirdesc[dir->depth]);
419 pfree(dir->dirname[dir->depth]);
420 dir->depth--;
421 }
422 pfree(dir);
423}
int FreeDir(DIR *dir)
Definition: fd.c:3022
void pfree(void *pointer)
Definition: mcxt.c:1594
char * dirname[MAX_TZDIR_DEPTH]
Definition: pgtz.c:390
int depth
Definition: pgtz.c:388
DIR * dirdesc[MAX_TZDIR_DEPTH]
Definition: pgtz.c:389

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

◆ pg_tzenumerate_next()

pg_tz * pg_tzenumerate_next ( pg_tzenum dir)

Definition at line 426 of file pgtz.c.

427{
428 while (dir->depth >= 0)
429 {
430 struct dirent *direntry;
431 char fullname[MAXPGPATH * 2];
432
433 direntry = ReadDir(dir->dirdesc[dir->depth], dir->dirname[dir->depth]);
434
435 if (!direntry)
436 {
437 /* End of this directory */
438 FreeDir(dir->dirdesc[dir->depth]);
439 pfree(dir->dirname[dir->depth]);
440 dir->depth--;
441 continue;
442 }
443
444 if (direntry->d_name[0] == '.')
445 continue;
446
447 snprintf(fullname, sizeof(fullname), "%s/%s",
448 dir->dirname[dir->depth], direntry->d_name);
449
450 if (get_dirent_type(fullname, direntry, true, ERROR) == PGFILETYPE_DIR)
451 {
452 /* Step into the subdirectory */
453 if (dir->depth >= MAX_TZDIR_DEPTH - 1)
455 (errmsg_internal("timezone directory stack overflow")));
456 dir->depth++;
457 dir->dirname[dir->depth] = pstrdup(fullname);
458 dir->dirdesc[dir->depth] = AllocateDir(fullname);
459 if (!dir->dirdesc[dir->depth])
462 errmsg("could not open directory \"%s\": %m",
463 fullname)));
464
465 /* Start over reading in the new directory */
466 continue;
467 }
468
469 /*
470 * Load this timezone using tzload() not pg_tzset(), so we don't fill
471 * the cache. Also, don't ask for the canonical spelling: we already
472 * know it, and pg_open_tzfile's way of finding it out is pretty
473 * inefficient.
474 */
475 if (tzload(fullname + dir->baselen, NULL, &dir->tz.state, true) != 0)
476 {
477 /* Zone could not be loaded, ignore it */
478 continue;
479 }
480
481 if (!pg_tz_acceptable(&dir->tz))
482 {
483 /* Ignore leap-second zones */
484 continue;
485 }
486
487 /* OK, return the canonical zone name spelling. */
488 strlcpy(dir->tz.TZname, fullname + dir->baselen,
489 sizeof(dir->tz.TZname));
490
491 /* Timezone loaded OK. */
492 return &dir->tz;
493 }
494
495 /* Nothing more found */
496 return NULL;
497}
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1170
int errcode_for_file_access(void)
Definition: elog.c:886
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2904
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2970
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition: file_utils.c:547
@ PGFILETYPE_DIR
Definition: file_utils.h:23
int tzload(char const *name, char *canonname, struct state *sp, bool doextend)
Definition: localtime.c:587
char * pstrdup(const char *in)
Definition: mcxt.c:1759
#define MAXPGPATH
bool pg_tz_acceptable(pg_tz *tz)
Definition: localtime.c:2005
#define MAX_TZDIR_DEPTH
Definition: pgtz.c:383
#define snprintf
Definition: port.h:260
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
int baselen
Definition: pgtz.c:387
struct pg_tz tz
Definition: pgtz.c:391

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

◆ pg_tzenumerate_start()

pg_tzenum * pg_tzenumerate_start ( void  )

Definition at line 397 of file pgtz.c.

398{
399 pg_tzenum *ret = (pg_tzenum *) palloc0(sizeof(pg_tzenum));
400 char *startdir = pstrdup(pg_TZDIR());
401
402 ret->baselen = strlen(startdir) + 1;
403 ret->depth = 0;
404 ret->dirname[0] = startdir;
405 ret->dirdesc[0] = AllocateDir(startdir);
406 if (!ret->dirdesc[0])
409 errmsg("could not open directory \"%s\": %m", startdir)));
410 return ret;
411}
void * palloc0(Size size)
Definition: mcxt.c:1395
static const char * pg_TZDIR(void)
Definition: pgtz.c:43

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().

◆ pg_tzset()

pg_tz * pg_tzset ( const char *  tzname)

Definition at line 234 of file pgtz.c.

235{
236 pg_tz_cache *tzp;
237 struct state tzstate;
238 char uppername[TZ_STRLEN_MAX + 1];
239 char canonname[TZ_STRLEN_MAX + 1];
240 char *p;
241
242 if (strlen(tzname) > TZ_STRLEN_MAX)
243 return NULL; /* not going to fit */
244
245 if (!timezone_cache)
247 return NULL;
248
249 /*
250 * Upcase the given name to perform a case-insensitive hashtable search.
251 * (We could alternatively downcase it, but we prefer upcase so that we
252 * can get consistently upcased results from tzparse() in case the name is
253 * a POSIX-style timezone spec.)
254 */
255 p = uppername;
256 while (*tzname)
257 *p++ = pg_toupper((unsigned char) *tzname++);
258 *p = '\0';
259
261 uppername,
262 HASH_FIND,
263 NULL);
264 if (tzp)
265 {
266 /* Timezone found in cache, nothing more to do */
267 return &tzp->tz;
268 }
269
270 /*
271 * "GMT" is always sent to tzparse(), as per discussion above.
272 */
273 if (strcmp(uppername, "GMT") == 0)
274 {
275 if (!tzparse(uppername, &tzstate, true))
276 {
277 /* This really, really should not happen ... */
278 elog(ERROR, "could not initialize GMT time zone");
279 }
280 /* Use uppercase name as canonical */
281 strcpy(canonname, uppername);
282 }
283 else if (tzload(uppername, canonname, &tzstate, true) != 0)
284 {
285 if (uppername[0] == ':' || !tzparse(uppername, &tzstate, false))
286 {
287 /* Unknown timezone. Fail our call instead of loading GMT! */
288 return NULL;
289 }
290 /* For POSIX timezone specs, use uppercase name as canonical */
291 strcpy(canonname, uppername);
292 }
293
294 /* Save timezone in the cache */
296 uppername,
298 NULL);
299
300 /* hash_search already copied uppername into the hash key */
301 strcpy(tzp->tz.TZname, canonname);
302 memcpy(&tzp->tz.state, &tzstate, sizeof(tzstate));
303
304 return &tzp->tz;
305}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
#define elog(elevel,...)
Definition: elog.h:226
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_ENTER
Definition: hsearch.h:114
bool tzparse(const char *name, struct state *sp, bool lastditch)
Definition: localtime.c:937
#define TZ_STRLEN_MAX
Definition: pgtime.h:54
static HTAB * timezone_cache
Definition: pgtz.c:198
static bool init_timezone_hashtable(void)
Definition: pgtz.c:202
unsigned char pg_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:101
pg_tz tz
Definition: pgtz.c:195

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

Referenced by check_log_timezone(), check_timezone(), DecodeDateTime(), DecodeTimeOnly(), DecodeTimezoneName(), FetchDynamicTimeZone(), pg_timezone_initialize(), and pg_tzset_offset().

◆ pg_tzset_offset()

pg_tz * pg_tzset_offset ( long  gmtoffset)

Definition at line 320 of file pgtz.c.

321{
322 long absoffset = (gmtoffset < 0) ? -gmtoffset : gmtoffset;
323 char offsetstr[64];
324 char tzname[128];
325
326 snprintf(offsetstr, sizeof(offsetstr),
327 "%02ld", absoffset / SECS_PER_HOUR);
328 absoffset %= SECS_PER_HOUR;
329 if (absoffset != 0)
330 {
331 snprintf(offsetstr + strlen(offsetstr),
332 sizeof(offsetstr) - strlen(offsetstr),
333 ":%02ld", absoffset / SECS_PER_MINUTE);
334 absoffset %= SECS_PER_MINUTE;
335 if (absoffset != 0)
336 snprintf(offsetstr + strlen(offsetstr),
337 sizeof(offsetstr) - strlen(offsetstr),
338 ":%02ld", absoffset);
339 }
340 if (gmtoffset > 0)
341 snprintf(tzname, sizeof(tzname), "<-%s>+%s",
342 offsetstr, offsetstr);
343 else
344 snprintf(tzname, sizeof(tzname), "<+%s>-%s",
345 offsetstr, offsetstr);
346
347 return pg_tzset(tzname);
348}
#define SECS_PER_HOUR
Definition: timestamp.h:127
#define SECS_PER_MINUTE
Definition: timestamp.h:128

References pg_tzset(), SECS_PER_HOUR, SECS_PER_MINUTE, and snprintf.

Referenced by check_timezone(), and DecodeTimezoneNameToTz().

Variable Documentation

◆ log_timezone

◆ session_timezone