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_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 23 of file pgtime.h.

◆ pg_tzenum

typedef struct pg_tzenum pg_tzenum

Definition at line 23 of file pgtime.h.

Function Documentation

◆ pg_get_timezone_name()

const char* pg_get_timezone_name ( pg_tz tz)

Definition at line 1875 of file localtime.c.

1876 {
1877  if (tz)
1878  return tz->TZname;
1879  return NULL;
1880 }
char TZname[TZ_STRLEN_MAX+1]
Definition: pgtz.h:68

References pg_tz::TZname.

Referenced by show_log_timezone(), and show_timezone().

◆ pg_get_timezone_offset()

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

Definition at line 1851 of file localtime.c.

1852 {
1853  /*
1854  * The zone could have more than one ttinfo, if it's historically used
1855  * more than one abbreviation. We return true as long as they all have
1856  * the same gmtoff.
1857  */
1858  const struct state *sp;
1859  int i;
1860 
1861  sp = &tz->state;
1862  for (i = 1; i < sp->typecnt; i++)
1863  {
1864  if (sp->ttis[i].tt_utoff != sp->ttis[0].tt_utoff)
1865  return false;
1866  }
1867  *gmtoff = sp->ttis[0].tt_utoff;
1868  return true;
1869 }
int i
Definition: isn.c:73
struct state state
Definition: pgtz.h:69
Definition: regguts.h:318
struct ttinfo ttis[TZ_MAX_TYPES]
Definition: pgtz.h:51
int typecnt
Definition: pgtz.h:45
int32 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 1389 of file localtime.c.

1390 {
1391  return gmtsub(timep, 0, &tm);
1392 }
static struct pg_tm * gmtsub(pg_time_t const *timep, int32 offset, struct pg_tm *tmp)
Definition: localtime.c:1357
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 1757 of file localtime.c.

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

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

Referenced by DetermineTimeZoneAbbrevOffsetInternal().

◆ pg_localtime()

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

Definition at line 1344 of file localtime.c.

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

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(), 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 1610 of file localtime.c.

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

1891 {
1892  struct pg_tm *tt;
1893  pg_time_t time2000;
1894 
1895  /*
1896  * To detect leap-second timekeeping, run pg_localtime for what should be
1897  * GMT midnight, 2000-01-01. Insist that the tm_sec value be zero; any
1898  * other result has to be due to leap seconds.
1899  */
1901  tt = pg_localtime(&time2000, tz);
1902  if (!tt || tt->tm_sec != 0)
1903  return false;
1904 
1905  return true;
1906 }
#define UNIX_EPOCH_JDATE
Definition: timestamp.h:201
#define SECS_PER_DAY
Definition: timestamp.h:125
#define POSTGRES_EPOCH_JDATE
Definition: timestamp.h:202
struct pg_tm * pg_localtime(const pg_time_t *timep, const pg_tz *tz)
Definition: localtime.c:1344
Definition: pgtime.h:35
int tm_sec
Definition: pgtime.h:36

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:2761
void pfree(void *pointer)
Definition: mcxt.c:1306
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)
454  ereport(ERROR,
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])
460  ereport(ERROR,
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:993
int errcode_for_file_access(void)
Definition: elog.c:718
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2709
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2643
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition: file_utils.c:406
@ PGFILETYPE_DIR
Definition: file_utils.h:23
int tzload(const char *name, char *canonname, struct state *sp, bool doextend)
Definition: localtime.c:586
char * pstrdup(const char *in)
Definition: mcxt.c:1483
#define MAXPGPATH
bool pg_tz_acceptable(pg_tz *tz)
Definition: localtime.c:1890
#define MAX_TZDIR_DEPTH
Definition: pgtz.c:383
#define snprintf
Definition: port.h:238
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])
407  ereport(ERROR,
409  errmsg("could not open directory \"%s\": %m", startdir)));
410  return ret;
411 }
void * palloc0(Size size)
Definition: mcxt.c:1230
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,
297  HASH_ENTER,
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:953
@ 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:936
#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:105
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(), FetchDynamicTimeZone(), parse_sane_timezone(), pg_timezone_initialize(), pg_tzset_offset(), timestamp_zone(), timestamptz_trunc_zone(), timestamptz_zone(), and timetz_zone().

◆ 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:126
#define SECS_PER_MINUTE
Definition: timestamp.h:127

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

Referenced by check_timezone(), and timestamptz_trunc_zone().

Variable Documentation

◆ log_timezone

◆ session_timezone