PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
datetime.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/memutils.h"
#include "utils/tzparser.h"
Include dependency graph for datetime.c:

Go to the source code of this file.

Macros

#define APPEND_CHAR(bufptr, end, newchar)
 

Functions

static int DecodeNumber (int flen, char *field, bool haveTextMonth, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
 
static int DecodeNumberField (int len, char *str, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
 
static int DecodeTime (char *str, int fmask, int range, int *tmask, struct pg_tm *tm, fsec_t *fsec)
 
static const datetkndatebsearch (const char *key, const datetkn *base, int nel)
 
static int DecodeDate (char *str, int fmask, int *tmask, bool *is2digits, struct pg_tm *tm)
 
static char * AppendSeconds (char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
 
static void AdjustFractSeconds (double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
 
static void AdjustFractDays (double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
 
static int DetermineTimeZoneOffsetInternal (struct pg_tm *tm, pg_tz *tzp, pg_time_t *tp)
 
static bool DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t, const char *abbr, pg_tz *tzp, int *offset, int *isdst)
 
static pg_tzFetchDynamicTimeZone (TimeZoneAbbrevTable *tbl, const datetkn *tp)
 
static int strtoint (const char *nptr, char **endptr, int base)
 
int date2j (int y, int m, int d)
 
void j2date (int jd, int *year, int *month, int *day)
 
int j2day (int date)
 
void GetCurrentDateTime (struct pg_tm *tm)
 
void GetCurrentTimeUsec (struct pg_tm *tm, fsec_t *fsec, int *tzp)
 
static char * AppendTimestampSeconds (char *cp, struct pg_tm *tm, fsec_t fsec)
 
static int ParseFractionalSecond (char *cp, fsec_t *fsec)
 
int ParseDateTime (const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
 
int DecodeDateTime (char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp)
 
int DetermineTimeZoneOffset (struct pg_tm *tm, pg_tz *tzp)
 
int DetermineTimeZoneAbbrevOffset (struct pg_tm *tm, const char *abbr, pg_tz *tzp)
 
int DetermineTimeZoneAbbrevOffsetTS (TimestampTz ts, const char *abbr, pg_tz *tzp, int *isdst)
 
int DecodeTimeOnly (char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp)
 
int ValidateDate (int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
 
int DecodeTimezone (char *str, int *tzp)
 
int DecodeTimezoneAbbrev (int field, char *lowtoken, int *offset, pg_tz **tz)
 
int DecodeSpecial (int field, char *lowtoken, int *val)
 
static void ClearPgTm (struct pg_tm *tm, fsec_t *fsec)
 
int DecodeInterval (char **field, int *ftype, int nf, int range, int *dtype, struct pg_tm *tm, fsec_t *fsec)
 
static int ParseISO8601Number (char *str, char **endptr, int *ipart, double *fpart)
 
static int ISO8601IntegerWidth (char *fieldstart)
 
int DecodeISO8601Interval (char *str, int *dtype, struct pg_tm *tm, fsec_t *fsec)
 
int DecodeUnits (int field, char *lowtoken, int *val)
 
void DateTimeParseError (int dterr, const char *str, const char *datatype)
 
static char * EncodeTimezone (char *str, int tz, int style)
 
void EncodeDateOnly (struct pg_tm *tm, int style, char *str)
 
void EncodeTimeOnly (struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, int style, char *str)
 
void EncodeDateTime (struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
 
static char * AddISO8601IntPart (char *cp, int value, char units)
 
static char * AddPostgresIntPart (char *cp, int value, const char *units, bool *is_zero, bool *is_before)
 
static char * AddVerboseIntPart (char *cp, int value, const char *units, bool *is_zero, bool *is_before)
 
void EncodeInterval (struct pg_tm *tm, fsec_t fsec, int style, char *str)
 
static bool CheckDateTokenTable (const char *tablename, const datetkn *base, int nel)
 
bool CheckDateTokenTables (void)
 
NodeTemporalTransform (int32 max_precis, Node *node)
 
TimeZoneAbbrevTableConvertTimeZoneAbbrevs (struct tzEntry *abbrevs, int n)
 
void InstallTimeZoneAbbrevs (TimeZoneAbbrevTable *tbl)
 
Datum pg_timezone_abbrevs (PG_FUNCTION_ARGS)
 
Datum pg_timezone_names (PG_FUNCTION_ARGS)
 

Variables

const int day_tab [2][13]
 
const char *const months []
 
const char *const days []
 
static const datetkn datetktbl []
 
static int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0]
 
static const datetkn deltatktbl []
 
static int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0]
 
static TimeZoneAbbrevTablezoneabbrevtbl = NULL
 
static const datetkndatecache [MAXDATEFIELDS] = {NULL}
 
static const datetkndeltacache [MAXDATEFIELDS] = {NULL}
 
static const datetknabbrevcache [MAXDATEFIELDS] = {NULL}
 

Macro Definition Documentation

#define APPEND_CHAR (   bufptr,
  end,
  newchar 
)
Value:
do \
{ \
if (((bufptr) + 1) >= (end)) \
return DTERR_BAD_FORMAT; \
*(bufptr)++ = newchar; \
} while (0)
#define DTERR_BAD_FORMAT
Definition: datetime.h:282

Referenced by ParseDateTime().

Function Documentation

static char* AddISO8601IntPart ( char *  cp,
int  value,
char  units 
)
static

Definition at line 4169 of file datetime.c.

Referenced by EncodeInterval().

4170 {
4171  if (value == 0)
4172  return cp;
4173  sprintf(cp, "%d%c", value, units);
4174  return cp + strlen(cp);
4175 }
static struct @114 value
static char* AddPostgresIntPart ( char *  cp,
int  value,
const char *  units,
bool is_zero,
bool is_before 
)
static

Definition at line 4179 of file datetime.c.

References FALSE.

Referenced by EncodeInterval().

4181 {
4182  if (value == 0)
4183  return cp;
4184  sprintf(cp, "%s%s%d %s%s",
4185  (!*is_zero) ? " " : "",
4186  (*is_before && value > 0) ? "+" : "",
4187  value,
4188  units,
4189  (value != 1) ? "s" : "");
4190 
4191  /*
4192  * Each nonzero field sets is_before for (only) the next one. This is a
4193  * tad bizarre but it's how it worked before...
4194  */
4195  *is_before = (value < 0);
4196  *is_zero = FALSE;
4197  return cp + strlen(cp);
4198 }
static struct @114 value
#define FALSE
Definition: c.h:221
static char* AddVerboseIntPart ( char *  cp,
int  value,
const char *  units,
bool is_zero,
bool is_before 
)
static

Definition at line 4202 of file datetime.c.

References FALSE, and value.

Referenced by EncodeInterval().

4204 {
4205  if (value == 0)
4206  return cp;
4207  /* first nonzero value sets is_before */
4208  if (*is_zero)
4209  {
4210  *is_before = (value < 0);
4211  value = abs(value);
4212  }
4213  else if (*is_before)
4214  value = -value;
4215  sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
4216  *is_zero = FALSE;
4217  return cp + strlen(cp);
4218 }
static struct @114 value
#define FALSE
Definition: c.h:221
static void AdjustFractDays ( double  frac,
struct pg_tm tm,
fsec_t fsec,
int  scale 
)
static

Definition at line 499 of file datetime.c.

References AdjustFractSeconds(), scale, SECS_PER_DAY, and pg_tm::tm_mday.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

500 {
501  int extra_days;
502 
503  if (frac == 0)
504  return;
505  frac *= scale;
506  extra_days = (int) frac;
507  tm->tm_mday += extra_days;
508  frac -= extra_days;
509  AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
510 }
int scale
Definition: pgbench.c:106
static void AdjustFractSeconds(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:484
#define SECS_PER_DAY
Definition: timestamp.h:86
int tm_mday
Definition: pgtime.h:30
static void AdjustFractSeconds ( double  frac,
struct pg_tm tm,
fsec_t fsec,
int  scale 
)
static

Definition at line 484 of file datetime.c.

References rint(), scale, and pg_tm::tm_sec.

Referenced by AdjustFractDays(), DecodeInterval(), and DecodeISO8601Interval().

485 {
486  int sec;
487 
488  if (frac == 0)
489  return;
490  frac *= scale;
491  sec = (int) frac;
492  tm->tm_sec += sec;
493  frac -= sec;
494  *fsec += rint(frac * 1000000);
495 }
int scale
Definition: pgbench.c:106
double rint(double x)
Definition: rint.c:22
int tm_sec
Definition: pgtime.h:27
static char * AppendSeconds ( char *  cp,
int  sec,
fsec_t  fsec,
int  precision,
bool  fillzeros 
)
static

Definition at line 411 of file datetime.c.

References Abs, Assert, pg_ltostr(), pg_ltostr_zeropad(), and value.

Referenced by AppendTimestampSeconds(), EncodeInterval(), and EncodeTimeOnly().

412 {
413  Assert(precision >= 0);
414 
415  if (fillzeros)
416  cp = pg_ltostr_zeropad(cp, Abs(sec), 2);
417  else
418  cp = pg_ltostr(cp, Abs(sec));
419 
420  /* fsec_t is just an int32 */
421  if (fsec != 0)
422  {
423  int32 value = Abs(fsec);
424  char *end = &cp[precision + 1];
425  bool gotnonzero = false;
426 
427  *cp++ = '.';
428 
429  /*
430  * Append the fractional seconds part. Note that we don't want any
431  * trailing zeros here, so since we're building the number in reverse
432  * we'll skip appending zeros until we've output a non-zero digit.
433  */
434  while (precision--)
435  {
436  int32 oldval = value;
437  int32 remainder;
438 
439  value /= 10;
440  remainder = oldval - value * 10;
441 
442  /* check if we got a non-zero */
443  if (remainder)
444  gotnonzero = true;
445 
446  if (gotnonzero)
447  cp[precision] = '0' + remainder;
448  else
449  end = &cp[precision];
450  }
451 
452  /*
453  * If we still have a non-zero value then precision must have not been
454  * enough to print the number. We punt the problem to pg_ltostr(),
455  * which will generate a correct answer in the minimum valid width.
456  */
457  if (value)
458  return pg_ltostr(cp, Abs(fsec));
459 
460  return end;
461  }
462  else
463  return cp;
464 }
signed int int32
Definition: c.h:256
#define Abs(x)
Definition: c.h:812
static struct @114 value
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
char * pg_ltostr(char *str, int32 value)
Definition: numutils.c:334
#define Assert(condition)
Definition: c.h:675
static char* AppendTimestampSeconds ( char *  cp,
struct pg_tm tm,
fsec_t  fsec 
)
static

Definition at line 474 of file datetime.c.

References AppendSeconds(), MAX_TIMESTAMP_PRECISION, and pg_tm::tm_sec.

Referenced by EncodeDateTime().

475 {
476  return AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
477 }
#define MAX_TIMESTAMP_PRECISION
Definition: timestamp.h:53
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:411
int tm_sec
Definition: pgtime.h:27
static bool CheckDateTokenTable ( const char *  tablename,
const datetkn base,
int  nel 
)
static

Definition at line 4432 of file datetime.c.

References elog, i, LOG, and TOKMAXLEN.

Referenced by CheckDateTokenTables(), and ConvertTimeZoneAbbrevs().

4433 {
4434  bool ok = true;
4435  int i;
4436 
4437  for (i = 0; i < nel; i++)
4438  {
4439  /* check for token strings that don't fit */
4440  if (strlen(base[i].token) > TOKMAXLEN)
4441  {
4442  /* %.*s is safe since all our tokens are ASCII */
4443  elog(LOG, "token too long in %s table: \"%.*s\"",
4444  tablename,
4445  TOKMAXLEN + 1, base[i].token);
4446  ok = false;
4447  break; /* don't risk applying strcmp */
4448  }
4449  /* check for out of order */
4450  if (i > 0 &&
4451  strcmp(base[i - 1].token, base[i].token) >= 0)
4452  {
4453  elog(LOG, "ordering error in %s table: \"%s\" >= \"%s\"",
4454  tablename,
4455  base[i - 1].token,
4456  base[i].token);
4457  ok = false;
4458  }
4459  }
4460  return ok;
4461 }
#define LOG
Definition: elog.h:26
int i
#define TOKMAXLEN
Definition: datetime.h:207
#define elog
Definition: elog.h:219
bool CheckDateTokenTables ( void  )

Definition at line 4464 of file datetime.c.

References Assert, CheckDateTokenTable(), date2j(), POSTGRES_EPOCH_JDATE, szdatetktbl, szdeltatktbl, and UNIX_EPOCH_JDATE.

Referenced by PostmasterMain().

4465 {
4466  bool ok = true;
4467 
4468  Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1));
4469  Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1));
4470 
4471  ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
4472  ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
4473  return ok;
4474 }
static const datetkn datetktbl[]
Definition: datetime.c:90
static int szdatetktbl
Definition: datetime.c:168
static bool CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
Definition: datetime.c:4432
static const datetkn deltatktbl[]
Definition: datetime.c:174
int date2j(int y, int m, int d)
Definition: datetime.c:292
static int szdeltatktbl
Definition: datetime.c:241
#define Assert(condition)
Definition: c.h:675
#define UNIX_EPOCH_JDATE
Definition: timestamp.h:162
#define POSTGRES_EPOCH_JDATE
Definition: timestamp.h:163
static void ClearPgTm ( struct pg_tm tm,
fsec_t fsec 
)
inlinestatic

Definition at line 3071 of file datetime.c.

References pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, and pg_tm::tm_year.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

3072 {
3073  tm->tm_year = 0;
3074  tm->tm_mon = 0;
3075  tm->tm_mday = 0;
3076  tm->tm_hour = 0;
3077  tm->tm_min = 0;
3078  tm->tm_sec = 0;
3079  *fsec = 0;
3080 }
int tm_hour
Definition: pgtime.h:29
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
int tm_year
Definition: pgtime.h:32
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
TimeZoneAbbrevTable* ConvertTimeZoneAbbrevs ( struct tzEntry abbrevs,
int  n 
)

Definition at line 4519 of file datetime.c.

References tzEntry::abbrev, TimeZoneAbbrevTable::abbrevs, Assert, CheckDateTokenTable(), DTZ, DYNTZ, i, tzEntry::is_dst, malloc, MAXALIGN, NULL, TimeZoneAbbrevTable::numabbrevs, tzEntry::offset, offsetof, strlcpy(), TimeZoneAbbrevTable::tblsize, datetkn::token, TOKMAXLEN, datetkn::type, TZ, DynamicZoneAbbrev::tz, datetkn::value, tzEntry::zone, and DynamicZoneAbbrev::zone.

Referenced by load_tzoffsets().

4520 {
4521  TimeZoneAbbrevTable *tbl;
4522  Size tbl_size;
4523  int i;
4524 
4525  /* Space for fixed fields and datetkn array */
4526  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4527  n * sizeof(datetkn);
4528  tbl_size = MAXALIGN(tbl_size);
4529  /* Count up space for dynamic abbreviations */
4530  for (i = 0; i < n; i++)
4531  {
4532  struct tzEntry *abbr = abbrevs + i;
4533 
4534  if (abbr->zone != NULL)
4535  {
4536  Size dsize;
4537 
4538  dsize = offsetof(DynamicZoneAbbrev, zone) +
4539  strlen(abbr->zone) + 1;
4540  tbl_size += MAXALIGN(dsize);
4541  }
4542  }
4543 
4544  /* Alloc the result ... */
4545  tbl = malloc(tbl_size);
4546  if (!tbl)
4547  return NULL;
4548 
4549  /* ... and fill it in */
4550  tbl->tblsize = tbl_size;
4551  tbl->numabbrevs = n;
4552  /* in this loop, tbl_size reprises the space calculation above */
4553  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4554  n * sizeof(datetkn);
4555  tbl_size = MAXALIGN(tbl_size);
4556  for (i = 0; i < n; i++)
4557  {
4558  struct tzEntry *abbr = abbrevs + i;
4559  datetkn *dtoken = tbl->abbrevs + i;
4560 
4561  /* use strlcpy to truncate name if necessary */
4562  strlcpy(dtoken->token, abbr->abbrev, TOKMAXLEN + 1);
4563  if (abbr->zone != NULL)
4564  {
4565  /* Allocate a DynamicZoneAbbrev for this abbreviation */
4566  DynamicZoneAbbrev *dtza;
4567  Size dsize;
4568 
4569  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tbl_size);
4570  dtza->tz = NULL;
4571  strcpy(dtza->zone, abbr->zone);
4572 
4573  dtoken->type = DYNTZ;
4574  /* value is offset from table start to DynamicZoneAbbrev */
4575  dtoken->value = (int32) tbl_size;
4576 
4577  dsize = offsetof(DynamicZoneAbbrev, zone) +
4578  strlen(abbr->zone) + 1;
4579  tbl_size += MAXALIGN(dsize);
4580  }
4581  else
4582  {
4583  dtoken->type = abbr->is_dst ? DTZ : TZ;
4584  dtoken->value = abbr->offset;
4585  }
4586  }
4587 
4588  /* Assert the two loops above agreed on size calculations */
4589  Assert(tbl->tblsize == tbl_size);
4590 
4591  /* Check the ordering, if testing */
4592  Assert(CheckDateTokenTable("timezone abbreviations", tbl->abbrevs, n));
4593 
4594  return tbl;
4595 }
int offset
Definition: tzparser.h:29
#define TZ
Definition: datetime.h:96
int32 value
Definition: datetime.h:214
signed int int32
Definition: c.h:256
char * zone
Definition: tzparser.h:27
bool is_dst
Definition: tzparser.h:30
#define malloc(a)
Definition: header.h:50
char token[TOKMAXLEN+1]
Definition: datetime.h:212
static bool CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
Definition: datetime.c:4432
datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:222
char * abbrev
Definition: tzparser.h:26
char zone[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:230
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
size_t Size
Definition: c.h:356
#define MAXALIGN(LEN)
Definition: c.h:588
#define DTZ
Definition: datetime.h:97
Definition: zic.c:90
#define DYNTZ
Definition: datetime.h:98
int i
#define TOKMAXLEN
Definition: datetime.h:207
#define offsetof(type, field)
Definition: c.h:555
int date2j ( int  y,
int  m,
int  d 
)

Definition at line 292 of file datetime.c.

Referenced by abstime_date(), CheckDateTokenTables(), date2isoweek(), date2isoyear(), date2isoyearday(), date_in(), DCH_to_char(), DecodeDateTime(), DetermineTimeZoneOffsetInternal(), EncodeDateTime(), GetSQLCurrentDate(), isoweek2j(), make_date(), make_timestamp_internal(), PGTYPESdate_dayofweek(), PGTYPESdate_defmt_asc(), PGTYPESdate_fmt_asc(), PGTYPESdate_from_asc(), PGTYPESdate_julmdy(), PGTYPESdate_mdyjul(), PGTYPESdate_to_asc(), PGTYPESdate_today(), timestamp2tm(), timestamp_date(), timestamp_part(), timestamp_pl_interval(), timestamp_to_char(), timestamptz_date(), timestamptz_part(), timestamptz_pl_interval(), timestamptz_to_char(), tm2abstime(), tm2timestamp(), to_date(), and ValidateDate().

293 {
294  int julian;
295  int century;
296 
297  if (m > 2)
298  {
299  m += 1;
300  y += 4800;
301  }
302  else
303  {
304  m += 13;
305  y += 4799;
306  }
307 
308  century = y / 100;
309  julian = y * 365 - 32167;
310  julian += y / 4 - century + century / 4;
311  julian += 7834 * m / 256 + d;
312 
313  return julian;
314 } /* date2j() */
static const datetkn * datebsearch ( const char *  key,
const datetkn base,
int  nel 
)
static

Definition at line 3810 of file datetime.c.

References NULL, result, and TOKMAXLEN.

Referenced by DecodeSpecial(), DecodeTimezoneAbbrev(), DecodeUnits(), and ParseDateTime().

3811 {
3812  if (nel > 0)
3813  {
3814  const datetkn *last = base + nel - 1,
3815  *position;
3816  int result;
3817 
3818  while (last >= base)
3819  {
3820  position = base + ((last - base) >> 1);
3821  /* precheck the first character for a bit of extra speed */
3822  result = (int) key[0] - (int) position->token[0];
3823  if (result == 0)
3824  {
3825  /* use strncmp so that we match truncated tokens */
3826  result = strncmp(key, position->token, TOKMAXLEN);
3827  if (result == 0)
3828  return position;
3829  }
3830  if (result < 0)
3831  last = position - 1;
3832  else
3833  base = position + 1;
3834  }
3835  }
3836  return NULL;
3837 }
return result
Definition: formatting.c:1618
#define NULL
Definition: c.h:229
#define TOKMAXLEN
Definition: datetime.h:207
void DateTimeParseError ( int  dterr,
const char *  str,
const char *  datatype 
)

Definition at line 3765 of file datetime.c.

References DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTERR_INTERVAL_OVERFLOW, DTERR_MD_FIELD_OVERFLOW, DTERR_TZDISP_OVERFLOW, ereport, errcode(), errhint(), errmsg(), and ERROR.

Referenced by abstimein(), date_in(), do_to_timestamp(), interval_in(), reltimein(), time_in(), timestamp_in(), timestamptz_in(), and timetz_in().

3766 {
3767  switch (dterr)
3768  {
3769  case DTERR_FIELD_OVERFLOW:
3770  ereport(ERROR,
3771  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3772  errmsg("date/time field value out of range: \"%s\"",
3773  str)));
3774  break;
3776  /* <nanny>same as above, but add hint about DateStyle</nanny> */
3777  ereport(ERROR,
3778  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3779  errmsg("date/time field value out of range: \"%s\"",
3780  str),
3781  errhint("Perhaps you need a different \"datestyle\" setting.")));
3782  break;
3784  ereport(ERROR,
3785  (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
3786  errmsg("interval field value out of range: \"%s\"",
3787  str)));
3788  break;
3789  case DTERR_TZDISP_OVERFLOW:
3790  ereport(ERROR,
3791  (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
3792  errmsg("time zone displacement out of range: \"%s\"",
3793  str)));
3794  break;
3795  case DTERR_BAD_FORMAT:
3796  default:
3797  ereport(ERROR,
3798  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3799  errmsg("invalid input syntax for type %s: \"%s\"",
3800  datatype, str)));
3801  break;
3802  }
3803 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
#define DTERR_INTERVAL_OVERFLOW
Definition: datetime.h:285
#define ereport(elevel, rest)
Definition: elog.h:122
#define DTERR_TZDISP_OVERFLOW
Definition: datetime.h:286
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define DTERR_MD_FIELD_OVERFLOW
Definition: datetime.h:284
static int DecodeDate ( char *  str,
int  fmask,
int *  tmask,
bool is2digits,
struct pg_tm tm 
)
static

Definition at line 2369 of file datetime.c.

References DecodeNumber(), DecodeSpecial(), DOY, DTERR_BAD_FORMAT, DTK_DATE_M, DTK_M, FALSE, i, IGNORE_DTF, MAXDATEFIELDS, MONTH, NULL, pg_tm::tm_mon, TRUE, TZ, and val.

Referenced by DecodeDateTime(), and DecodeTimeOnly().

2371 {
2372  fsec_t fsec;
2373  int nf = 0;
2374  int i,
2375  len;
2376  int dterr;
2377  bool haveTextMonth = FALSE;
2378  int type,
2379  val,
2380  dmask = 0;
2381  char *field[MAXDATEFIELDS];
2382 
2383  *tmask = 0;
2384 
2385  /* parse this string... */
2386  while (*str != '\0' && nf < MAXDATEFIELDS)
2387  {
2388  /* skip field separators */
2389  while (*str != '\0' && !isalnum((unsigned char) *str))
2390  str++;
2391 
2392  if (*str == '\0')
2393  return DTERR_BAD_FORMAT; /* end of string after separator */
2394 
2395  field[nf] = str;
2396  if (isdigit((unsigned char) *str))
2397  {
2398  while (isdigit((unsigned char) *str))
2399  str++;
2400  }
2401  else if (isalpha((unsigned char) *str))
2402  {
2403  while (isalpha((unsigned char) *str))
2404  str++;
2405  }
2406 
2407  /* Just get rid of any non-digit, non-alpha characters... */
2408  if (*str != '\0')
2409  *str++ = '\0';
2410  nf++;
2411  }
2412 
2413  /* look first for text fields, since that will be unambiguous month */
2414  for (i = 0; i < nf; i++)
2415  {
2416  if (isalpha((unsigned char) *field[i]))
2417  {
2418  type = DecodeSpecial(i, field[i], &val);
2419  if (type == IGNORE_DTF)
2420  continue;
2421 
2422  dmask = DTK_M(type);
2423  switch (type)
2424  {
2425  case MONTH:
2426  tm->tm_mon = val;
2427  haveTextMonth = TRUE;
2428  break;
2429 
2430  default:
2431  return DTERR_BAD_FORMAT;
2432  }
2433  if (fmask & dmask)
2434  return DTERR_BAD_FORMAT;
2435 
2436  fmask |= dmask;
2437  *tmask |= dmask;
2438 
2439  /* mark this field as being completed */
2440  field[i] = NULL;
2441  }
2442  }
2443 
2444  /* now pick up remaining numeric fields */
2445  for (i = 0; i < nf; i++)
2446  {
2447  if (field[i] == NULL)
2448  continue;
2449 
2450  if ((len = strlen(field[i])) <= 0)
2451  return DTERR_BAD_FORMAT;
2452 
2453  dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,
2454  &dmask, tm,
2455  &fsec, is2digits);
2456  if (dterr)
2457  return dterr;
2458 
2459  if (fmask & dmask)
2460  return DTERR_BAD_FORMAT;
2461 
2462  fmask |= dmask;
2463  *tmask |= dmask;
2464  }
2465 
2466  if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
2467  return DTERR_BAD_FORMAT;
2468 
2469  /* validation of the field values must wait until ValidateDate() */
2470 
2471  return 0;
2472 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define IGNORE_DTF
Definition: datetime.h:99
#define TZ
Definition: datetime.h:96
#define DTK_DATE_M
Definition: datetime.h:194
#define FALSE
Definition: c.h:221
int tm_mon
Definition: pgtime.h:31
int32 fsec_t
Definition: timestamp.h:41
#define MONTH
Definition: datetime.h:92
#define NULL
Definition: c.h:229
#define MAXDATEFIELDS
Definition: datetime.h:205
static int DecodeNumber(int flen, char *field, bool haveTextMonth, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2634
int DecodeSpecial(int field, char *lowtoken, int *val)
Definition: datetime.c:3039
int i
#define DTK_M(t)
Definition: datetime.h:190
#define TRUE
Definition: c.h:217
#define DOY
Definition: datetime.h:106
long val
Definition: informix.c:689
int DecodeDateTime ( char **  field,
int *  ftype,
int  nf,
int *  dtype,
struct pg_tm tm,
fsec_t fsec,
int *  tzp 
)

Definition at line 783 of file datetime.c.

References ADBC, AM, AMPM, BC, date2j(), DAY, DecodeDate(), DecodeNumber(), DecodeNumberField(), DecodeSpecial(), DecodeTime(), DecodeTimezone(), DecodeTimezoneAbbrev(), DetermineTimeZoneAbbrevOffset(), DetermineTimeZoneOffset(), DOW, dt2time(), DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_ALL_SECS_M, DTK_CURRENT, DTK_DATE, DTK_DATE_M, DTK_DAY, DTK_HOUR, DTK_JULIAN, DTK_M, DTK_MINUTE, DTK_MONTH, DTK_NOW, DTK_NUMBER, DTK_SECOND, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TIME_M, DTK_TODAY, DTK_TOMORROW, DTK_TZ, DTK_YEAR, DTK_YESTERDAY, DTK_ZULU, DTZ, DTZMOD, DYNTZ, ereport, errcode(), errmsg(), ERROR, FALSE, GetCurrentDateTime(), GetCurrentTimeUsec(), HOUR, HOURS_PER_DAY, HR24, i, IGNORE_DTF, INTERVAL_FULL_RANGE, ISOTIME, j2date(), MINUTE, MONTH, NULL, ParseFractionalSecond(), pg_tzset(), PM, RESERV, SECOND, session_timezone, strtoint(), pg_tm::tm_hour, pg_tm::tm_isdst, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_wday, pg_tm::tm_year, TRUE, TZ, UNITS, UNKNOWN_FIELD, USECS_PER_DAY, val, ValidateDate(), and YEAR.

Referenced by abstimein(), date_in(), pg_logdir_ls(), PGTYPESdate_from_asc(), PGTYPEStimestamp_from_asc(), timestamp_in(), and timestamptz_in().

785 {
786  int fmask = 0,
787  tmask,
788  type;
789  int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */
790  int i;
791  int val;
792  int dterr;
793  int mer = HR24;
794  bool haveTextMonth = FALSE;
795  bool isjulian = FALSE;
796  bool is2digits = FALSE;
797  bool bc = FALSE;
798  pg_tz *namedTz = NULL;
799  pg_tz *abbrevTz = NULL;
800  pg_tz *valtz;
801  char *abbrev = NULL;
802  struct pg_tm cur_tm;
803 
804  /*
805  * We'll insist on at least all of the date fields, but initialize the
806  * remaining fields in case they are not set later...
807  */
808  *dtype = DTK_DATE;
809  tm->tm_hour = 0;
810  tm->tm_min = 0;
811  tm->tm_sec = 0;
812  *fsec = 0;
813  /* don't know daylight savings time status apriori */
814  tm->tm_isdst = -1;
815  if (tzp != NULL)
816  *tzp = 0;
817 
818  for (i = 0; i < nf; i++)
819  {
820  switch (ftype[i])
821  {
822  case DTK_DATE:
823 
824  /*
825  * Integral julian day with attached time zone? All other
826  * forms with JD will be separated into distinct fields, so we
827  * handle just this case here.
828  */
829  if (ptype == DTK_JULIAN)
830  {
831  char *cp;
832  int val;
833 
834  if (tzp == NULL)
835  return DTERR_BAD_FORMAT;
836 
837  errno = 0;
838  val = strtoint(field[i], &cp, 10);
839  if (errno == ERANGE || val < 0)
840  return DTERR_FIELD_OVERFLOW;
841 
842  j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
843  isjulian = TRUE;
844 
845  /* Get the time zone from the end of the string */
846  dterr = DecodeTimezone(cp, tzp);
847  if (dterr)
848  return dterr;
849 
850  tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
851  ptype = 0;
852  break;
853  }
854 
855  /*
856  * Already have a date? Then this might be a time zone name
857  * with embedded punctuation (e.g. "America/New_York") or a
858  * run-together time with trailing time zone (e.g. hhmmss-zz).
859  * - thomas 2001-12-25
860  *
861  * We consider it a time zone if we already have month & day.
862  * This is to allow the form "mmm dd hhmmss tz year", which
863  * we've historically accepted.
864  */
865  else if (ptype != 0 ||
866  ((fmask & (DTK_M(MONTH) | DTK_M(DAY))) ==
867  (DTK_M(MONTH) | DTK_M(DAY))))
868  {
869  /* No time zone accepted? Then quit... */
870  if (tzp == NULL)
871  return DTERR_BAD_FORMAT;
872 
873  if (isdigit((unsigned char) *field[i]) || ptype != 0)
874  {
875  char *cp;
876 
877  if (ptype != 0)
878  {
879  /* Sanity check; should not fail this test */
880  if (ptype != DTK_TIME)
881  return DTERR_BAD_FORMAT;
882  ptype = 0;
883  }
884 
885  /*
886  * Starts with a digit but we already have a time
887  * field? Then we are in trouble with a date and time
888  * already...
889  */
890  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
891  return DTERR_BAD_FORMAT;
892 
893  if ((cp = strchr(field[i], '-')) == NULL)
894  return DTERR_BAD_FORMAT;
895 
896  /* Get the time zone from the end of the string */
897  dterr = DecodeTimezone(cp, tzp);
898  if (dterr)
899  return dterr;
900  *cp = '\0';
901 
902  /*
903  * Then read the rest of the field as a concatenated
904  * time
905  */
906  dterr = DecodeNumberField(strlen(field[i]), field[i],
907  fmask,
908  &tmask, tm,
909  fsec, &is2digits);
910  if (dterr < 0)
911  return dterr;
912 
913  /*
914  * modify tmask after returning from
915  * DecodeNumberField()
916  */
917  tmask |= DTK_M(TZ);
918  }
919  else
920  {
921  namedTz = pg_tzset(field[i]);
922  if (!namedTz)
923  {
924  /*
925  * We should return an error code instead of
926  * ereport'ing directly, but then there is no way
927  * to report the bad time zone name.
928  */
929  ereport(ERROR,
930  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
931  errmsg("time zone \"%s\" not recognized",
932  field[i])));
933  }
934  /* we'll apply the zone setting below */
935  tmask = DTK_M(TZ);
936  }
937  }
938  else
939  {
940  dterr = DecodeDate(field[i], fmask,
941  &tmask, &is2digits, tm);
942  if (dterr)
943  return dterr;
944  }
945  break;
946 
947  case DTK_TIME:
948 
949  /*
950  * This might be an ISO time following a "t" field.
951  */
952  if (ptype != 0)
953  {
954  /* Sanity check; should not fail this test */
955  if (ptype != DTK_TIME)
956  return DTERR_BAD_FORMAT;
957  ptype = 0;
958  }
959  dterr = DecodeTime(field[i], fmask, INTERVAL_FULL_RANGE,
960  &tmask, tm, fsec);
961  if (dterr)
962  return dterr;
963 
964  /*
965  * Check upper limit on hours; other limits checked in
966  * DecodeTime()
967  */
968  /* test for > 24:00:00 */
969  if (tm->tm_hour > HOURS_PER_DAY ||
970  (tm->tm_hour == HOURS_PER_DAY &&
971  (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0)))
972  return DTERR_FIELD_OVERFLOW;
973  break;
974 
975  case DTK_TZ:
976  {
977  int tz;
978 
979  if (tzp == NULL)
980  return DTERR_BAD_FORMAT;
981 
982  dterr = DecodeTimezone(field[i], &tz);
983  if (dterr)
984  return dterr;
985  *tzp = tz;
986  tmask = DTK_M(TZ);
987  }
988  break;
989 
990  case DTK_NUMBER:
991 
992  /*
993  * Was this an "ISO date" with embedded field labels? An
994  * example is "y2001m02d04" - thomas 2001-02-04
995  */
996  if (ptype != 0)
997  {
998  char *cp;
999  int val;
1000 
1001  errno = 0;
1002  val = strtoint(field[i], &cp, 10);
1003  if (errno == ERANGE)
1004  return DTERR_FIELD_OVERFLOW;
1005 
1006  /*
1007  * only a few kinds are allowed to have an embedded
1008  * decimal
1009  */
1010  if (*cp == '.')
1011  switch (ptype)
1012  {
1013  case DTK_JULIAN:
1014  case DTK_TIME:
1015  case DTK_SECOND:
1016  break;
1017  default:
1018  return DTERR_BAD_FORMAT;
1019  break;
1020  }
1021  else if (*cp != '\0')
1022  return DTERR_BAD_FORMAT;
1023 
1024  switch (ptype)
1025  {
1026  case DTK_YEAR:
1027  tm->tm_year = val;
1028  tmask = DTK_M(YEAR);
1029  break;
1030 
1031  case DTK_MONTH:
1032 
1033  /*
1034  * already have a month and hour? then assume
1035  * minutes
1036  */
1037  if ((fmask & DTK_M(MONTH)) != 0 &&
1038  (fmask & DTK_M(HOUR)) != 0)
1039  {
1040  tm->tm_min = val;
1041  tmask = DTK_M(MINUTE);
1042  }
1043  else
1044  {
1045  tm->tm_mon = val;
1046  tmask = DTK_M(MONTH);
1047  }
1048  break;
1049 
1050  case DTK_DAY:
1051  tm->tm_mday = val;
1052  tmask = DTK_M(DAY);
1053  break;
1054 
1055  case DTK_HOUR:
1056  tm->tm_hour = val;
1057  tmask = DTK_M(HOUR);
1058  break;
1059 
1060  case DTK_MINUTE:
1061  tm->tm_min = val;
1062  tmask = DTK_M(MINUTE);
1063  break;
1064 
1065  case DTK_SECOND:
1066  tm->tm_sec = val;
1067  tmask = DTK_M(SECOND);
1068  if (*cp == '.')
1069  {
1070  dterr = ParseFractionalSecond(cp, fsec);
1071  if (dterr)
1072  return dterr;
1073  tmask = DTK_ALL_SECS_M;
1074  }
1075  break;
1076 
1077  case DTK_TZ:
1078  tmask = DTK_M(TZ);
1079  dterr = DecodeTimezone(field[i], tzp);
1080  if (dterr)
1081  return dterr;
1082  break;
1083 
1084  case DTK_JULIAN:
1085  /* previous field was a label for "julian date" */
1086  if (val < 0)
1087  return DTERR_FIELD_OVERFLOW;
1088  tmask = DTK_DATE_M;
1089  j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1090  isjulian = TRUE;
1091 
1092  /* fractional Julian Day? */
1093  if (*cp == '.')
1094  {
1095  double time;
1096 
1097  errno = 0;
1098  time = strtod(cp, &cp);
1099  if (*cp != '\0' || errno != 0)
1100  return DTERR_BAD_FORMAT;
1101  time *= USECS_PER_DAY;
1102  dt2time(time,
1103  &tm->tm_hour, &tm->tm_min,
1104  &tm->tm_sec, fsec);
1105  tmask |= DTK_TIME_M;
1106  }
1107  break;
1108 
1109  case DTK_TIME:
1110  /* previous field was "t" for ISO time */
1111  dterr = DecodeNumberField(strlen(field[i]), field[i],
1112  (fmask | DTK_DATE_M),
1113  &tmask, tm,
1114  fsec, &is2digits);
1115  if (dterr < 0)
1116  return dterr;
1117  if (tmask != DTK_TIME_M)
1118  return DTERR_BAD_FORMAT;
1119  break;
1120 
1121  default:
1122  return DTERR_BAD_FORMAT;
1123  break;
1124  }
1125 
1126  ptype = 0;
1127  *dtype = DTK_DATE;
1128  }
1129  else
1130  {
1131  char *cp;
1132  int flen;
1133 
1134  flen = strlen(field[i]);
1135  cp = strchr(field[i], '.');
1136 
1137  /* Embedded decimal and no date yet? */
1138  if (cp != NULL && !(fmask & DTK_DATE_M))
1139  {
1140  dterr = DecodeDate(field[i], fmask,
1141  &tmask, &is2digits, tm);
1142  if (dterr)
1143  return dterr;
1144  }
1145  /* embedded decimal and several digits before? */
1146  else if (cp != NULL && flen - strlen(cp) > 2)
1147  {
1148  /*
1149  * Interpret as a concatenated date or time Set the
1150  * type field to allow decoding other fields later.
1151  * Example: 20011223 or 040506
1152  */
1153  dterr = DecodeNumberField(flen, field[i], fmask,
1154  &tmask, tm,
1155  fsec, &is2digits);
1156  if (dterr < 0)
1157  return dterr;
1158  }
1159 
1160  /*
1161  * Is this a YMD or HMS specification, or a year number?
1162  * YMD and HMS are required to be six digits or more, so
1163  * if it is 5 digits, it is a year. If it is six or more
1164  * more digits, we assume it is YMD or HMS unless no date
1165  * and no time values have been specified. This forces 6+
1166  * digit years to be at the end of the string, or to use
1167  * the ISO date specification.
1168  */
1169  else if (flen >= 6 && (!(fmask & DTK_DATE_M) ||
1170  !(fmask & DTK_TIME_M)))
1171  {
1172  dterr = DecodeNumberField(flen, field[i], fmask,
1173  &tmask, tm,
1174  fsec, &is2digits);
1175  if (dterr < 0)
1176  return dterr;
1177  }
1178  /* otherwise it is a single date/time field... */
1179  else
1180  {
1181  dterr = DecodeNumber(flen, field[i],
1182  haveTextMonth, fmask,
1183  &tmask, tm,
1184  fsec, &is2digits);
1185  if (dterr)
1186  return dterr;
1187  }
1188  }
1189  break;
1190 
1191  case DTK_STRING:
1192  case DTK_SPECIAL:
1193  /* timezone abbrevs take precedence over built-in tokens */
1194  type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
1195  if (type == UNKNOWN_FIELD)
1196  type = DecodeSpecial(i, field[i], &val);
1197  if (type == IGNORE_DTF)
1198  continue;
1199 
1200  tmask = DTK_M(type);
1201  switch (type)
1202  {
1203  case RESERV:
1204  switch (val)
1205  {
1206  case DTK_CURRENT:
1207  ereport(ERROR,
1208  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1209  errmsg("date/time value \"current\" is no longer supported")));
1210 
1211  return DTERR_BAD_FORMAT;
1212  break;
1213 
1214  case DTK_NOW:
1215  tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
1216  *dtype = DTK_DATE;
1217  GetCurrentTimeUsec(tm, fsec, tzp);
1218  break;
1219 
1220  case DTK_YESTERDAY:
1221  tmask = DTK_DATE_M;
1222  *dtype = DTK_DATE;
1223  GetCurrentDateTime(&cur_tm);
1224  j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) - 1,
1225  &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1226  break;
1227 
1228  case DTK_TODAY:
1229  tmask = DTK_DATE_M;
1230  *dtype = DTK_DATE;
1231  GetCurrentDateTime(&cur_tm);
1232  tm->tm_year = cur_tm.tm_year;
1233  tm->tm_mon = cur_tm.tm_mon;
1234  tm->tm_mday = cur_tm.tm_mday;
1235  break;
1236 
1237  case DTK_TOMORROW:
1238  tmask = DTK_DATE_M;
1239  *dtype = DTK_DATE;
1240  GetCurrentDateTime(&cur_tm);
1241  j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) + 1,
1242  &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1243  break;
1244 
1245  case DTK_ZULU:
1246  tmask = (DTK_TIME_M | DTK_M(TZ));
1247  *dtype = DTK_DATE;
1248  tm->tm_hour = 0;
1249  tm->tm_min = 0;
1250  tm->tm_sec = 0;
1251  if (tzp != NULL)
1252  *tzp = 0;
1253  break;
1254 
1255  default:
1256  *dtype = val;
1257  }
1258 
1259  break;
1260 
1261  case MONTH:
1262 
1263  /*
1264  * already have a (numeric) month? then see if we can
1265  * substitute...
1266  */
1267  if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
1268  !(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 &&
1269  tm->tm_mon <= 31)
1270  {
1271  tm->tm_mday = tm->tm_mon;
1272  tmask = DTK_M(DAY);
1273  }
1274  haveTextMonth = TRUE;
1275  tm->tm_mon = val;
1276  break;
1277 
1278  case DTZMOD:
1279 
1280  /*
1281  * daylight savings time modifier (solves "MET DST"
1282  * syntax)
1283  */
1284  tmask |= DTK_M(DTZ);
1285  tm->tm_isdst = 1;
1286  if (tzp == NULL)
1287  return DTERR_BAD_FORMAT;
1288  *tzp -= val;
1289  break;
1290 
1291  case DTZ:
1292 
1293  /*
1294  * set mask for TZ here _or_ check for DTZ later when
1295  * getting default timezone
1296  */
1297  tmask |= DTK_M(TZ);
1298  tm->tm_isdst = 1;
1299  if (tzp == NULL)
1300  return DTERR_BAD_FORMAT;
1301  *tzp = -val;
1302  break;
1303 
1304  case TZ:
1305  tm->tm_isdst = 0;
1306  if (tzp == NULL)
1307  return DTERR_BAD_FORMAT;
1308  *tzp = -val;
1309  break;
1310 
1311  case DYNTZ:
1312  tmask |= DTK_M(TZ);
1313  if (tzp == NULL)
1314  return DTERR_BAD_FORMAT;
1315  /* we'll determine the actual offset later */
1316  abbrevTz = valtz;
1317  abbrev = field[i];
1318  break;
1319 
1320  case AMPM:
1321  mer = val;
1322  break;
1323 
1324  case ADBC:
1325  bc = (val == BC);
1326  break;
1327 
1328  case DOW:
1329  tm->tm_wday = val;
1330  break;
1331 
1332  case UNITS:
1333  tmask = 0;
1334  ptype = val;
1335  break;
1336 
1337  case ISOTIME:
1338 
1339  /*
1340  * This is a filler field "t" indicating that the next
1341  * field is time. Try to verify that this is sensible.
1342  */
1343  tmask = 0;
1344 
1345  /* No preceding date? Then quit... */
1346  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1347  return DTERR_BAD_FORMAT;
1348 
1349  /***
1350  * We will need one of the following fields:
1351  * DTK_NUMBER should be hhmmss.fff
1352  * DTK_TIME should be hh:mm:ss.fff
1353  * DTK_DATE should be hhmmss-zz
1354  ***/
1355  if (i >= nf - 1 ||
1356  (ftype[i + 1] != DTK_NUMBER &&
1357  ftype[i + 1] != DTK_TIME &&
1358  ftype[i + 1] != DTK_DATE))
1359  return DTERR_BAD_FORMAT;
1360 
1361  ptype = val;
1362  break;
1363 
1364  case UNKNOWN_FIELD:
1365 
1366  /*
1367  * Before giving up and declaring error, check to see
1368  * if it is an all-alpha timezone name.
1369  */
1370  namedTz = pg_tzset(field[i]);
1371  if (!namedTz)
1372  return DTERR_BAD_FORMAT;
1373  /* we'll apply the zone setting below */
1374  tmask = DTK_M(TZ);
1375  break;
1376 
1377  default:
1378  return DTERR_BAD_FORMAT;
1379  }
1380  break;
1381 
1382  default:
1383  return DTERR_BAD_FORMAT;
1384  }
1385 
1386  if (tmask & fmask)
1387  return DTERR_BAD_FORMAT;
1388  fmask |= tmask;
1389  } /* end loop over fields */
1390 
1391  /* do final checking/adjustment of Y/M/D fields */
1392  dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
1393  if (dterr)
1394  return dterr;
1395 
1396  /* handle AM/PM */
1397  if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
1398  return DTERR_FIELD_OVERFLOW;
1399  if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
1400  tm->tm_hour = 0;
1401  else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
1402  tm->tm_hour += HOURS_PER_DAY / 2;
1403 
1404  /* do additional checking for full date specs... */
1405  if (*dtype == DTK_DATE)
1406  {
1407  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1408  {
1409  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1410  return 1;
1411  return DTERR_BAD_FORMAT;
1412  }
1413 
1414  /*
1415  * If we had a full timezone spec, compute the offset (we could not do
1416  * it before, because we need the date to resolve DST status).
1417  */
1418  if (namedTz != NULL)
1419  {
1420  /* daylight savings time modifier disallowed with full TZ */
1421  if (fmask & DTK_M(DTZMOD))
1422  return DTERR_BAD_FORMAT;
1423 
1424  *tzp = DetermineTimeZoneOffset(tm, namedTz);
1425  }
1426 
1427  /*
1428  * Likewise, if we had a dynamic timezone abbreviation, resolve it
1429  * now.
1430  */
1431  if (abbrevTz != NULL)
1432  {
1433  /* daylight savings time modifier disallowed with dynamic TZ */
1434  if (fmask & DTK_M(DTZMOD))
1435  return DTERR_BAD_FORMAT;
1436 
1437  *tzp = DetermineTimeZoneAbbrevOffset(tm, abbrev, abbrevTz);
1438  }
1439 
1440  /* timezone not specified? then use session timezone */
1441  if (tzp != NULL && !(fmask & DTK_M(TZ)))
1442  {
1443  /*
1444  * daylight savings time modifier but no standard timezone? then
1445  * error
1446  */
1447  if (fmask & DTK_M(DTZMOD))
1448  return DTERR_BAD_FORMAT;
1449 
1451  }
1452  }
1453 
1454  return 0;
1455 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
void GetCurrentDateTime(struct pg_tm *tm)
Definition: datetime.c:370
#define PM
Definition: datetime.h:73
#define DAY
Definition: datetime.h:94
#define UNITS
Definition: datetime.h:108
#define IGNORE_DTF
Definition: datetime.h:99
int tm_wday
Definition: pgtime.h:33
#define DTK_JULIAN
Definition: datetime.h:176
#define DTK_YEAR
Definition: datetime.h:170
int tm_isdst
Definition: pgtime.h:35
#define YEAR
Definition: datetime.h:93
int tm_hour
Definition: pgtime.h:29
#define DTK_TIME_M
Definition: datetime.h:195
int errcode(int sqlerrcode)
Definition: elog.c:575
#define TZ
Definition: datetime.h:96
#define UNKNOWN_FIELD
Definition: datetime.h:125
#define SECOND
Definition: datetime.h:103
static int DecodeNumberField(int len, char *str, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2819
#define DTK_TODAY
Definition: datetime.h:158
#define DTK_TOMORROW
Definition: datetime.h:159
#define ADBC
Definition: datetime.h:109
Definition: pgtime.h:25
#define DTK_CURRENT
Definition: datetime.h:152
#define INTERVAL_FULL_RANGE
Definition: timestamp.h:48
#define DTK_DATE_M
Definition: datetime.h:194
pg_tz * pg_tzset(const char *tzname)
Definition: pgtz.c:218
#define DTK_MONTH
Definition: datetime.h:168
#define DTK_TZ
Definition: datetime.h:147
#define DTK_HOUR
Definition: datetime.h:165
#define ERROR
Definition: elog.h:43
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
#define DOW
Definition: datetime.h:107
#define AM
Definition: datetime.h:72
int DecodeTimezoneAbbrev(int field, char *lowtoken, int *offset, pg_tz **tz)
Definition: datetime.c:2984
#define FALSE
Definition: c.h:221
#define DTK_SECOND
Definition: datetime.h:163
int DecodeTimezone(char *str, int *tzp)
Definition: datetime.c:2906
int tm_mday
Definition: pgtime.h:30
#define HOURS_PER_DAY
Definition: timestamp.h:78
int tm_mon
Definition: pgtime.h:31
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1471
static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits, struct pg_tm *tm)
Definition: datetime.c:2369
void GetCurrentTimeUsec(struct pg_tm *tm, fsec_t *fsec, int *tzp)
Definition: datetime.c:387
#define DTK_YESTERDAY
Definition: datetime.h:157
#define DTK_NUMBER
Definition: datetime.h:142
#define MINUTE
Definition: datetime.h:102
#define USECS_PER_DAY
Definition: timestamp.h:91
#define ereport(elevel, rest)
Definition: elog.h:122
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:317
#define MONTH
Definition: datetime.h:92
#define DTK_MINUTE
Definition: datetime.h:164
static int ParseFractionalSecond(char *cp, fsec_t *fsec)
Definition: datetime.c:514
#define BC
Definition: datetime.h:77
char * abbrev
Definition: tzparser.h:26
Definition: pgtz.h:59
#define ISOTIME
Definition: datetime.h:116
#define DTK_TIME
Definition: datetime.h:146
int date2j(int y, int m, int d)
Definition: datetime.c:292
static int DecodeTime(char *str, int fmask, int range, int *tmask, struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:2558
void dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
Definition: timestamp.c:1730
static int strtoint(const char *nptr, char **endptr, int base)
Definition: datetime.c:258
#define NULL
Definition: c.h:229
#define AMPM
Definition: datetime.h:100
#define DTK_STRING
Definition: datetime.h:143
#define DTK_DAY
Definition: datetime.h:166
static int DecodeNumber(int flen, char *field, bool haveTextMonth, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2634
#define RESERV
Definition: datetime.h:91
int DecodeSpecial(int field, char *lowtoken, int *val)
Definition: datetime.c:3039
#define DTK_ALL_SECS_M
Definition: datetime.h:193
#define DTZ
Definition: datetime.h:97
int tm_year
Definition: pgtime.h:32
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define DYNTZ
Definition: datetime.h:98
#define DTK_NOW
Definition: datetime.h:156
int i
#define DTK_M(t)
Definition: datetime.h:190
pg_tz * session_timezone
Definition: pgtz.c:27
#define TRUE
Definition: c.h:217
#define HOUR
Definition: datetime.h:101
#define DTK_ZULU
Definition: datetime.h:160
int tm_sec
Definition: pgtime.h:27
#define DTZMOD
Definition: datetime.h:123
int tm_min
Definition: pgtime.h:28
int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp)
Definition: datetime.c:1629
long val
Definition: informix.c:689
#define DTK_DATE
Definition: datetime.h:145
#define HR24
Definition: datetime.h:74
#define DTK_SPECIAL
Definition: datetime.h:150
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2479
int DecodeInterval ( char **  field,
int *  ftype,
int  nf,
int  range,
int *  dtype,
struct pg_tm tm,
fsec_t fsec 
)

Definition at line 3095 of file datetime.c.

References AdjustFractDays(), AdjustFractSeconds(), AGO, Assert, CENTURY, ClearPgTm(), DAY, DAYS_PER_MONTH, DECADE, DecodeTime(), DecodeUnits(), DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_ALL_SECS_M, DTK_CENTURY, DTK_DATE, DTK_DATE_M, DTK_DAY, DTK_DECADE, DTK_DELTA, DTK_HOUR, DTK_M, DTK_MICROSEC, DTK_MILLENNIUM, DTK_MILLISEC, DTK_MINUTE, DTK_MONTH, DTK_NUMBER, DTK_SECOND, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TIME_M, DTK_TZ, DTK_WEEK, DTK_YEAR, FALSE, HOUR, i, IGNORE_DTF, INTERVAL_MASK, IntervalStyle, INTSTYLE_SQL_STANDARD, MICROSECOND, MILLENNIUM, MILLISECOND, MINUTE, MONTH, MONTHS_PER_YEAR, NULL, RESERV, rint(), SECOND, SECS_PER_DAY, SECS_PER_HOUR, SECS_PER_MINUTE, strtoint(), pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_year, TRUE, UNITS, USECS_PER_SEC, val, WEEK, and YEAR.

Referenced by interval_in(), and reltimein().

3097 {
3098  bool is_before = FALSE;
3099  char *cp;
3100  int fmask = 0,
3101  tmask,
3102  type;
3103  int i;
3104  int dterr;
3105  int val;
3106  double fval;
3107 
3108  *dtype = DTK_DELTA;
3109  type = IGNORE_DTF;
3110  ClearPgTm(tm, fsec);
3111 
3112  /* read through list backwards to pick up units before values */
3113  for (i = nf - 1; i >= 0; i--)
3114  {
3115  switch (ftype[i])
3116  {
3117  case DTK_TIME:
3118  dterr = DecodeTime(field[i], fmask, range,
3119  &tmask, tm, fsec);
3120  if (dterr)
3121  return dterr;
3122  type = DTK_DAY;
3123  break;
3124 
3125  case DTK_TZ:
3126 
3127  /*
3128  * Timezone means a token with a leading sign character and at
3129  * least one digit; there could be ':', '.', '-' embedded in
3130  * it as well.
3131  */
3132  Assert(*field[i] == '-' || *field[i] == '+');
3133 
3134  /*
3135  * Check for signed hh:mm or hh:mm:ss. If so, process exactly
3136  * like DTK_TIME case above, plus handling the sign.
3137  */
3138  if (strchr(field[i] + 1, ':') != NULL &&
3139  DecodeTime(field[i] + 1, fmask, range,
3140  &tmask, tm, fsec) == 0)
3141  {
3142  if (*field[i] == '-')
3143  {
3144  /* flip the sign on all fields */
3145  tm->tm_hour = -tm->tm_hour;
3146  tm->tm_min = -tm->tm_min;
3147  tm->tm_sec = -tm->tm_sec;
3148  *fsec = -(*fsec);
3149  }
3150 
3151  /*
3152  * Set the next type to be a day, if units are not
3153  * specified. This handles the case of '1 +02:03' since we
3154  * are reading right to left.
3155  */
3156  type = DTK_DAY;
3157  break;
3158  }
3159 
3160  /*
3161  * Otherwise, fall through to DTK_NUMBER case, which can
3162  * handle signed float numbers and signed year-month values.
3163  */
3164 
3165  /* FALL THROUGH */
3166 
3167  case DTK_DATE:
3168  case DTK_NUMBER:
3169  if (type == IGNORE_DTF)
3170  {
3171  /* use typmod to decide what rightmost field is */
3172  switch (range)
3173  {
3174  case INTERVAL_MASK(YEAR):
3175  type = DTK_YEAR;
3176  break;
3177  case INTERVAL_MASK(MONTH):
3179  type = DTK_MONTH;
3180  break;
3181  case INTERVAL_MASK(DAY):
3182  type = DTK_DAY;
3183  break;
3184  case INTERVAL_MASK(HOUR):
3186  type = DTK_HOUR;
3187  break;
3188  case INTERVAL_MASK(MINUTE):
3191  type = DTK_MINUTE;
3192  break;
3193  case INTERVAL_MASK(SECOND):
3197  type = DTK_SECOND;
3198  break;
3199  default:
3200  type = DTK_SECOND;
3201  break;
3202  }
3203  }
3204 
3205  errno = 0;
3206  val = strtoint(field[i], &cp, 10);
3207  if (errno == ERANGE)
3208  return DTERR_FIELD_OVERFLOW;
3209 
3210  if (*cp == '-')
3211  {
3212  /* SQL "years-months" syntax */
3213  int val2;
3214 
3215  val2 = strtoint(cp + 1, &cp, 10);
3216  if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
3217  return DTERR_FIELD_OVERFLOW;
3218  if (*cp != '\0')
3219  return DTERR_BAD_FORMAT;
3220  type = DTK_MONTH;
3221  if (*field[i] == '-')
3222  val2 = -val2;
3223  if (((double) val * MONTHS_PER_YEAR + val2) > INT_MAX ||
3224  ((double) val * MONTHS_PER_YEAR + val2) < INT_MIN)
3225  return DTERR_FIELD_OVERFLOW;
3226  val = val * MONTHS_PER_YEAR + val2;
3227  fval = 0;
3228  }
3229  else if (*cp == '.')
3230  {
3231  errno = 0;
3232  fval = strtod(cp, &cp);
3233  if (*cp != '\0' || errno != 0)
3234  return DTERR_BAD_FORMAT;
3235 
3236  if (*field[i] == '-')
3237  fval = -fval;
3238  }
3239  else if (*cp == '\0')
3240  fval = 0;
3241  else
3242  return DTERR_BAD_FORMAT;
3243 
3244  tmask = 0; /* DTK_M(type); */
3245 
3246  switch (type)
3247  {
3248  case DTK_MICROSEC:
3249  *fsec += rint(val + fval);
3250  tmask = DTK_M(MICROSECOND);
3251  break;
3252 
3253  case DTK_MILLISEC:
3254  /* avoid overflowing the fsec field */
3255  tm->tm_sec += val / 1000;
3256  val -= (val / 1000) * 1000;
3257  *fsec += rint((val + fval) * 1000);
3258  tmask = DTK_M(MILLISECOND);
3259  break;
3260 
3261  case DTK_SECOND:
3262  tm->tm_sec += val;
3263  *fsec += rint(fval * 1000000);
3264 
3265  /*
3266  * If any subseconds were specified, consider this
3267  * microsecond and millisecond input as well.
3268  */
3269  if (fval == 0)
3270  tmask = DTK_M(SECOND);
3271  else
3272  tmask = DTK_ALL_SECS_M;
3273  break;
3274 
3275  case DTK_MINUTE:
3276  tm->tm_min += val;
3277  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3278  tmask = DTK_M(MINUTE);
3279  break;
3280 
3281  case DTK_HOUR:
3282  tm->tm_hour += val;
3283  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3284  tmask = DTK_M(HOUR);
3285  type = DTK_DAY; /* set for next field */
3286  break;
3287 
3288  case DTK_DAY:
3289  tm->tm_mday += val;
3290  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3291  tmask = DTK_M(DAY);
3292  break;
3293 
3294  case DTK_WEEK:
3295  tm->tm_mday += val * 7;
3296  AdjustFractDays(fval, tm, fsec, 7);
3297  tmask = DTK_M(WEEK);
3298  break;
3299 
3300  case DTK_MONTH:
3301  tm->tm_mon += val;
3302  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3303  tmask = DTK_M(MONTH);
3304  break;
3305 
3306  case DTK_YEAR:
3307  tm->tm_year += val;
3308  if (fval != 0)
3309  tm->tm_mon += fval * MONTHS_PER_YEAR;
3310  tmask = DTK_M(YEAR);
3311  break;
3312 
3313  case DTK_DECADE:
3314  tm->tm_year += val * 10;
3315  if (fval != 0)
3316  tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
3317  tmask = DTK_M(DECADE);
3318  break;
3319 
3320  case DTK_CENTURY:
3321  tm->tm_year += val * 100;
3322  if (fval != 0)
3323  tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
3324  tmask = DTK_M(CENTURY);
3325  break;
3326 
3327  case DTK_MILLENNIUM:
3328  tm->tm_year += val * 1000;
3329  if (fval != 0)
3330  tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
3331  tmask = DTK_M(MILLENNIUM);
3332  break;
3333 
3334  default:
3335  return DTERR_BAD_FORMAT;
3336  }
3337  break;
3338 
3339  case DTK_STRING:
3340  case DTK_SPECIAL:
3341  type = DecodeUnits(i, field[i], &val);
3342  if (type == IGNORE_DTF)
3343  continue;
3344 
3345  tmask = 0; /* DTK_M(type); */
3346  switch (type)
3347  {
3348  case UNITS:
3349  type = val;
3350  break;
3351 
3352  case AGO:
3353  is_before = TRUE;
3354  type = val;
3355  break;
3356 
3357  case RESERV:
3358  tmask = (DTK_DATE_M | DTK_TIME_M);
3359  *dtype = val;
3360  break;
3361 
3362  default:
3363  return DTERR_BAD_FORMAT;
3364  }
3365  break;
3366 
3367  default:
3368  return DTERR_BAD_FORMAT;
3369  }
3370 
3371  if (tmask & fmask)
3372  return DTERR_BAD_FORMAT;
3373  fmask |= tmask;
3374  }
3375 
3376  /* ensure that at least one time field has been found */
3377  if (fmask == 0)
3378  return DTERR_BAD_FORMAT;
3379 
3380  /* ensure fractional seconds are fractional */
3381  if (*fsec != 0)
3382  {
3383  int sec;
3384 
3385  sec = *fsec / USECS_PER_SEC;
3386  *fsec -= sec * USECS_PER_SEC;
3387  tm->tm_sec += sec;
3388  }
3389 
3390  /*----------
3391  * The SQL standard defines the interval literal
3392  * '-1 1:00:00'
3393  * to mean "negative 1 days and negative 1 hours", while Postgres
3394  * traditionally treats this as meaning "negative 1 days and positive
3395  * 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign
3396  * to all fields if there are no other explicit signs.
3397  *
3398  * We leave the signs alone if there are additional explicit signs.
3399  * This protects us against misinterpreting postgres-style dump output,
3400  * since the postgres-style output code has always put an explicit sign on
3401  * all fields following a negative field. But note that SQL-spec output
3402  * is ambiguous and can be misinterpreted on load! (So it's best practice
3403  * to dump in postgres style, not SQL style.)
3404  *----------
3405  */
3406  if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
3407  {
3408  /* Check for additional explicit signs */
3409  bool more_signs = false;
3410 
3411  for (i = 1; i < nf; i++)
3412  {
3413  if (*field[i] == '-' || *field[i] == '+')
3414  {
3415  more_signs = true;
3416  break;
3417  }
3418  }
3419 
3420  if (!more_signs)
3421  {
3422  /*
3423  * Rather than re-determining which field was field[0], just force
3424  * 'em all negative.
3425  */
3426  if (*fsec > 0)
3427  *fsec = -(*fsec);
3428  if (tm->tm_sec > 0)
3429  tm->tm_sec = -tm->tm_sec;
3430  if (tm->tm_min > 0)
3431  tm->tm_min = -tm->tm_min;
3432  if (tm->tm_hour > 0)
3433  tm->tm_hour = -tm->tm_hour;
3434  if (tm->tm_mday > 0)
3435  tm->tm_mday = -tm->tm_mday;
3436  if (tm->tm_mon > 0)
3437  tm->tm_mon = -tm->tm_mon;
3438  if (tm->tm_year > 0)
3439  tm->tm_year = -tm->tm_year;
3440  }
3441  }
3442 
3443  /* finally, AGO negates everything */
3444  if (is_before)
3445  {
3446  *fsec = -(*fsec);
3447  tm->tm_sec = -tm->tm_sec;
3448  tm->tm_min = -tm->tm_min;
3449  tm->tm_hour = -tm->tm_hour;
3450  tm->tm_mday = -tm->tm_mday;
3451  tm->tm_mon = -tm->tm_mon;
3452  tm->tm_year = -tm->tm_year;
3453  }
3454 
3455  return 0;
3456 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define DTK_CENTURY
Definition: datetime.h:172
#define DAY
Definition: datetime.h:94
#define UNITS
Definition: datetime.h:108
#define IGNORE_DTF
Definition: datetime.h:99
#define DTK_WEEK
Definition: datetime.h:167
#define DTK_YEAR
Definition: datetime.h:170
#define MILLENNIUM
Definition: datetime.h:121
#define USECS_PER_SEC
Definition: timestamp.h:94
#define YEAR
Definition: datetime.h:93
#define CENTURY
Definition: datetime.h:120
#define DTK_DELTA
Definition: datetime.h:162
int tm_hour
Definition: pgtime.h:29
#define DECADE
Definition: datetime.h:119
#define AGO
Definition: datetime.h:111
#define DTK_TIME_M
Definition: datetime.h:195
#define DTK_MILLENNIUM
Definition: datetime.h:173
int IntervalStyle
Definition: globals.c:108
#define SECOND
Definition: datetime.h:103
int DecodeUnits(int field, char *lowtoken, int *val)
Definition: datetime.c:3728
static void AdjustFractSeconds(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:484
#define DTK_DATE_M
Definition: datetime.h:194
#define DTK_MONTH
Definition: datetime.h:168
#define DTK_MILLISEC
Definition: datetime.h:174
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
#define DTK_DECADE
Definition: datetime.h:171
#define DTK_TZ
Definition: datetime.h:147
#define DTK_HOUR
Definition: datetime.h:165
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
#define MILLISECOND
Definition: datetime.h:104
#define SECS_PER_DAY
Definition: timestamp.h:86
#define FALSE
Definition: c.h:221
#define DTK_SECOND
Definition: datetime.h:163
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:88
#define DTK_NUMBER
Definition: datetime.h:142
#define MINUTE
Definition: datetime.h:102
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:416
double rint(double x)
Definition: rint.c:22
#define SECS_PER_HOUR
Definition: timestamp.h:87
#define MONTH
Definition: datetime.h:92
#define DTK_MINUTE
Definition: datetime.h:164
#define DTK_MICROSEC
Definition: datetime.h:175
#define DAYS_PER_MONTH
Definition: timestamp.h:77
static void AdjustFractDays(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:499
#define WEEK
Definition: datetime.h:118
#define DTK_TIME
Definition: datetime.h:146
static int DecodeTime(char *str, int fmask, int range, int *tmask, struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:2558
static void ClearPgTm(struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:3071
static int strtoint(const char *nptr, char **endptr, int base)
Definition: datetime.c:258
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define DTK_STRING
Definition: datetime.h:143
#define DTK_DAY
Definition: datetime.h:166
#define RESERV
Definition: datetime.h:91
#define DTK_ALL_SECS_M
Definition: datetime.h:193
#define INTERVAL_MASK(b)
Definition: timestamp.h:45
#define INTSTYLE_SQL_STANDARD
Definition: miscadmin.h:232
int tm_year
Definition: pgtime.h:32
int i
#define DTK_M(t)
Definition: datetime.h:190
#define TRUE
Definition: c.h:217
#define HOUR
Definition: datetime.h:101
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
long val
Definition: informix.c:689
#define DTK_DATE
Definition: datetime.h:145
#define DTK_SPECIAL
Definition: datetime.h:150
#define MICROSECOND
Definition: datetime.h:105
int DecodeISO8601Interval ( char *  str,
int *  dtype,
struct pg_tm tm,
fsec_t fsec 
)

Definition at line 3521 of file datetime.c.

References AdjustFractDays(), AdjustFractSeconds(), ClearPgTm(), DAYS_PER_MONTH, DTERR_BAD_FORMAT, DTK_DELTA, ISO8601IntegerWidth(), MONTHS_PER_YEAR, ParseISO8601Number(), SECS_PER_DAY, SECS_PER_HOUR, SECS_PER_MINUTE, pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_year, and val.

Referenced by interval_in(), and reltimein().

3523 {
3524  bool datepart = true;
3525  bool havefield = false;
3526 
3527  *dtype = DTK_DELTA;
3528  ClearPgTm(tm, fsec);
3529 
3530  if (strlen(str) < 2 || str[0] != 'P')
3531  return DTERR_BAD_FORMAT;
3532 
3533  str++;
3534  while (*str)
3535  {
3536  char *fieldstart;
3537  int val;
3538  double fval;
3539  char unit;
3540  int dterr;
3541 
3542  if (*str == 'T') /* T indicates the beginning of the time part */
3543  {
3544  datepart = false;
3545  havefield = false;
3546  str++;
3547  continue;
3548  }
3549 
3550  fieldstart = str;
3551  dterr = ParseISO8601Number(str, &str, &val, &fval);
3552  if (dterr)
3553  return dterr;
3554 
3555  /*
3556  * Note: we could step off the end of the string here. Code below
3557  * *must* exit the loop if unit == '\0'.
3558  */
3559  unit = *str++;
3560 
3561  if (datepart)
3562  {
3563  switch (unit) /* before T: Y M W D */
3564  {
3565  case 'Y':
3566  tm->tm_year += val;
3567  tm->tm_mon += (fval * MONTHS_PER_YEAR);
3568  break;
3569  case 'M':
3570  tm->tm_mon += val;
3571  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3572  break;
3573  case 'W':
3574  tm->tm_mday += val * 7;
3575  AdjustFractDays(fval, tm, fsec, 7);
3576  break;
3577  case 'D':
3578  tm->tm_mday += val;
3579  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3580  break;
3581  case 'T': /* ISO 8601 4.4.3.3 Alternative Format / Basic */
3582  case '\0':
3583  if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
3584  {
3585  tm->tm_year += val / 10000;
3586  tm->tm_mon += (val / 100) % 100;
3587  tm->tm_mday += val % 100;
3588  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3589  if (unit == '\0')
3590  return 0;
3591  datepart = false;
3592  havefield = false;
3593  continue;
3594  }
3595  /* Else fall through to extended alternative format */
3596  case '-': /* ISO 8601 4.4.3.3 Alternative Format,
3597  * Extended */
3598  if (havefield)
3599  return DTERR_BAD_FORMAT;
3600 
3601  tm->tm_year += val;
3602  tm->tm_mon += (fval * MONTHS_PER_YEAR);
3603  if (unit == '\0')
3604  return 0;
3605  if (unit == 'T')
3606  {
3607  datepart = false;
3608  havefield = false;
3609  continue;
3610  }
3611 
3612  dterr = ParseISO8601Number(str, &str, &val, &fval);
3613  if (dterr)
3614  return dterr;
3615  tm->tm_mon += val;
3616  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3617  if (*str == '\0')
3618  return 0;
3619  if (*str == 'T')
3620  {
3621  datepart = false;
3622  havefield = false;
3623  continue;
3624  }
3625  if (*str != '-')
3626  return DTERR_BAD_FORMAT;
3627  str++;
3628 
3629  dterr = ParseISO8601Number(str, &str, &val, &fval);
3630  if (dterr)
3631  return dterr;
3632  tm->tm_mday += val;
3633  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3634  if (*str == '\0')
3635  return 0;
3636  if (*str == 'T')
3637  {
3638  datepart = false;
3639  havefield = false;
3640  continue;
3641  }
3642  return DTERR_BAD_FORMAT;
3643  default:
3644  /* not a valid date unit suffix */
3645  return DTERR_BAD_FORMAT;
3646  }
3647  }
3648  else
3649  {
3650  switch (unit) /* after T: H M S */
3651  {
3652  case 'H':
3653  tm->tm_hour += val;
3654  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3655  break;
3656  case 'M':
3657  tm->tm_min += val;
3658  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3659  break;
3660  case 'S':
3661  tm->tm_sec += val;
3662  AdjustFractSeconds(fval, tm, fsec, 1);
3663  break;
3664  case '\0': /* ISO 8601 4.4.3.3 Alternative Format */
3665  if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
3666  {
3667  tm->tm_hour += val / 10000;
3668  tm->tm_min += (val / 100) % 100;
3669  tm->tm_sec += val % 100;
3670  AdjustFractSeconds(fval, tm, fsec, 1);
3671  return 0;
3672  }
3673  /* Else fall through to extended alternative format */
3674  case ':': /* ISO 8601 4.4.3.3 Alternative Format,
3675  * Extended */
3676  if (havefield)
3677  return DTERR_BAD_FORMAT;
3678 
3679  tm->tm_hour += val;
3680  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3681  if (unit == '\0')
3682  return 0;
3683 
3684  dterr = ParseISO8601Number(str, &str, &val, &fval);
3685  if (dterr)
3686  return dterr;
3687  tm->tm_min += val;
3688  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3689  if (*str == '\0')
3690  return 0;
3691  if (*str != ':')
3692  return DTERR_BAD_FORMAT;
3693  str++;
3694 
3695  dterr = ParseISO8601Number(str, &str, &val, &fval);
3696  if (dterr)
3697  return dterr;
3698  tm->tm_sec += val;
3699  AdjustFractSeconds(fval, tm, fsec, 1);
3700  if (*str == '\0')
3701  return 0;
3702  return DTERR_BAD_FORMAT;
3703 
3704  default:
3705  /* not a valid time unit suffix */
3706  return DTERR_BAD_FORMAT;
3707  }
3708  }
3709 
3710  havefield = true;
3711  }
3712 
3713  return 0;
3714 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define DTK_DELTA
Definition: datetime.h:162
int tm_hour
Definition: pgtime.h:29
static void AdjustFractSeconds(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:484
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
#define SECS_PER_DAY
Definition: timestamp.h:86
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:88
#define SECS_PER_HOUR
Definition: timestamp.h:87
#define DAYS_PER_MONTH
Definition: timestamp.h:77
static void AdjustFractDays(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:499
static void ClearPgTm(struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:3071
static int ISO8601IntegerWidth(char *fieldstart)
Definition: datetime.c:3494
int tm_year
Definition: pgtime.h:32
static int ParseISO8601Number(char *str, char **endptr, int *ipart, double *fpart)
Definition: datetime.c:3466
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
long val
Definition: informix.c:689
static int DecodeNumber ( int  flen,
char *  field,
bool  haveTextMonth,
int  fmask,
int *  tmask,
struct pg_tm tm,
fsec_t fsec,
bool is2digits 
)
static

Definition at line 2634 of file datetime.c.

References DateOrder, DATEORDER_DMY, DATEORDER_YMD, DAY, DecodeNumberField(), DOY, DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_DATE_M, DTK_M, FALSE, MONTH, ParseFractionalSecond(), strtoint(), pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_yday, pg_tm::tm_year, val, and YEAR.

Referenced by DecodeDate(), DecodeDateTime(), and DecodeTimeOnly().

2636 {
2637  int val;
2638  char *cp;
2639  int dterr;
2640 
2641  *tmask = 0;
2642 
2643  errno = 0;
2644  val = strtoint(str, &cp, 10);
2645  if (errno == ERANGE)
2646  return DTERR_FIELD_OVERFLOW;
2647  if (cp == str)
2648  return DTERR_BAD_FORMAT;
2649 
2650  if (*cp == '.')
2651  {
2652  /*
2653  * More than two digits before decimal point? Then could be a date or
2654  * a run-together time: 2001.360 20011225 040506.789
2655  */
2656  if (cp - str > 2)
2657  {
2658  dterr = DecodeNumberField(flen, str,
2659  (fmask | DTK_DATE_M),
2660  tmask, tm,
2661  fsec, is2digits);
2662  if (dterr < 0)
2663  return dterr;
2664  return 0;
2665  }
2666 
2667  dterr = ParseFractionalSecond(cp, fsec);
2668  if (dterr)
2669  return dterr;
2670  }
2671  else if (*cp != '\0')
2672  return DTERR_BAD_FORMAT;
2673 
2674  /* Special case for day of year */
2675  if (flen == 3 && (fmask & DTK_DATE_M) == DTK_M(YEAR) && val >= 1 &&
2676  val <= 366)
2677  {
2678  *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
2679  tm->tm_yday = val;
2680  /* tm_mon and tm_mday can't actually be set yet ... */
2681  return 0;
2682  }
2683 
2684  /* Switch based on what we have so far */
2685  switch (fmask & DTK_DATE_M)
2686  {
2687  case 0:
2688 
2689  /*
2690  * Nothing so far; make a decision about what we think the input
2691  * is. There used to be lots of heuristics here, but the
2692  * consensus now is to be paranoid. It *must* be either
2693  * YYYY-MM-DD (with a more-than-two-digit year field), or the
2694  * field order defined by DateOrder.
2695  */
2696  if (flen >= 3 || DateOrder == DATEORDER_YMD)
2697  {
2698  *tmask = DTK_M(YEAR);
2699  tm->tm_year = val;
2700  }
2701  else if (DateOrder == DATEORDER_DMY)
2702  {
2703  *tmask = DTK_M(DAY);
2704  tm->tm_mday = val;
2705  }
2706  else
2707  {
2708  *tmask = DTK_M(MONTH);
2709  tm->tm_mon = val;
2710  }
2711  break;
2712 
2713  case (DTK_M(YEAR)):
2714  /* Must be at second field of YY-MM-DD */
2715  *tmask = DTK_M(MONTH);
2716  tm->tm_mon = val;
2717  break;
2718 
2719  case (DTK_M(MONTH)):
2720  if (haveTextMonth)
2721  {
2722  /*
2723  * We are at the first numeric field of a date that included a
2724  * textual month name. We want to support the variants
2725  * MON-DD-YYYY, DD-MON-YYYY, and YYYY-MON-DD as unambiguous
2726  * inputs. We will also accept MON-DD-YY or DD-MON-YY in
2727  * either DMY or MDY modes, as well as YY-MON-DD in YMD mode.
2728  */
2729  if (flen >= 3 || DateOrder == DATEORDER_YMD)
2730  {
2731  *tmask = DTK_M(YEAR);
2732  tm->tm_year = val;
2733  }
2734  else
2735  {
2736  *tmask = DTK_M(DAY);
2737  tm->tm_mday = val;
2738  }
2739  }
2740  else
2741  {
2742  /* Must be at second field of MM-DD-YY */
2743  *tmask = DTK_M(DAY);
2744  tm->tm_mday = val;
2745  }
2746  break;
2747 
2748  case (DTK_M(YEAR) | DTK_M(MONTH)):
2749  if (haveTextMonth)
2750  {
2751  /* Need to accept DD-MON-YYYY even in YMD mode */
2752  if (flen >= 3 && *is2digits)
2753  {
2754  /* Guess that first numeric field is day was wrong */
2755  *tmask = DTK_M(DAY); /* YEAR is already set */
2756  tm->tm_mday = tm->tm_year;
2757  tm->tm_year = val;
2758  *is2digits = FALSE;
2759  }
2760  else
2761  {
2762  *tmask = DTK_M(DAY);
2763  tm->tm_mday = val;
2764  }
2765  }
2766  else
2767  {
2768  /* Must be at third field of YY-MM-DD */
2769  *tmask = DTK_M(DAY);
2770  tm->tm_mday = val;
2771  }
2772  break;
2773 
2774  case (DTK_M(DAY)):
2775  /* Must be at second field of DD-MM-YY */
2776  *tmask = DTK_M(MONTH);
2777  tm->tm_mon = val;
2778  break;
2779 
2780  case (DTK_M(MONTH) | DTK_M(DAY)):
2781  /* Must be at third field of DD-MM-YY or MM-DD-YY */
2782  *tmask = DTK_M(YEAR);
2783  tm->tm_year = val;
2784  break;
2785 
2786  case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)):
2787  /* we have all the date, so it must be a time field */
2788  dterr = DecodeNumberField(flen, str, fmask,
2789  tmask, tm,
2790  fsec, is2digits);
2791  if (dterr < 0)
2792  return dterr;
2793  return 0;
2794 
2795  default:
2796  /* Anything else is bogus input */
2797  return DTERR_BAD_FORMAT;
2798  }
2799 
2800  /*
2801  * When processing a year field, mark it for adjustment if it's only one
2802  * or two digits.
2803  */
2804  if (*tmask == DTK_M(YEAR))
2805  *is2digits = (flen <= 2);
2806 
2807  return 0;
2808 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define DAY
Definition: datetime.h:94
#define YEAR
Definition: datetime.h:93
static int DecodeNumberField(int len, char *str, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2819
#define DTK_DATE_M
Definition: datetime.h:194
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
#define FALSE
Definition: c.h:221
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
int DateOrder
Definition: globals.c:107
#define MONTH
Definition: datetime.h:92
#define DATEORDER_YMD
Definition: miscadmin.h:216
static int ParseFractionalSecond(char *cp, fsec_t *fsec)
Definition: datetime.c:514
#define DATEORDER_DMY
Definition: miscadmin.h:217
static int strtoint(const char *nptr, char **endptr, int base)
Definition: datetime.c:258
int tm_year
Definition: pgtime.h:32
#define DTK_M(t)
Definition: datetime.h:190
int tm_yday
Definition: pgtime.h:34
#define DOY
Definition: datetime.h:106
long val
Definition: informix.c:689
static int DecodeNumberField ( int  len,
char *  str,
int  fmask,
int *  tmask,
struct pg_tm tm,
fsec_t fsec,
bool is2digits 
)
static

Definition at line 2819 of file datetime.c.

References DTERR_BAD_FORMAT, DTK_DATE, DTK_DATE_M, DTK_TIME, DTK_TIME_M, NULL, rint(), pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_year, and TRUE.

Referenced by DecodeDateTime(), DecodeNumber(), and DecodeTimeOnly().

2821 {
2822  char *cp;
2823 
2824  /*
2825  * Have a decimal point? Then this is a date or something with a seconds
2826  * field...
2827  */
2828  if ((cp = strchr(str, '.')) != NULL)
2829  {
2830  /*
2831  * Can we use ParseFractionalSecond here? Not clear whether trailing
2832  * junk should be rejected ...
2833  */
2834  double frac;
2835 
2836  errno = 0;
2837  frac = strtod(cp, NULL);
2838  if (errno != 0)
2839  return DTERR_BAD_FORMAT;
2840  *fsec = rint(frac * 1000000);
2841  /* Now truncate off the fraction for further processing */
2842  *cp = '\0';
2843  len = strlen(str);
2844  }
2845  /* No decimal point and no complete date yet? */
2846  else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2847  {
2848  if (len >= 6)
2849  {
2850  *tmask = DTK_DATE_M;
2851 
2852  /*
2853  * Start from end and consider first 2 as Day, next 2 as Month,
2854  * and the rest as Year.
2855  */
2856  tm->tm_mday = atoi(str + (len - 2));
2857  *(str + (len - 2)) = '\0';
2858  tm->tm_mon = atoi(str + (len - 4));
2859  *(str + (len - 4)) = '\0';
2860  tm->tm_year = atoi(str);
2861  if ((len - 4) == 2)
2862  *is2digits = TRUE;
2863 
2864  return DTK_DATE;
2865  }
2866  }
2867 
2868  /* not all time fields are specified? */
2869  if ((fmask & DTK_TIME_M) != DTK_TIME_M)
2870  {
2871  /* hhmmss */
2872  if (len == 6)
2873  {
2874  *tmask = DTK_TIME_M;
2875  tm->tm_sec = atoi(str + 4);
2876  *(str + 4) = '\0';
2877  tm->tm_min = atoi(str + 2);
2878  *(str + 2) = '\0';
2879  tm->tm_hour = atoi(str);
2880 
2881  return DTK_TIME;
2882  }
2883  /* hhmm? */
2884  else if (len == 4)
2885  {
2886  *tmask = DTK_TIME_M;
2887  tm->tm_sec = 0;
2888  tm->tm_min = atoi(str + 2);
2889  *(str + 2) = '\0';
2890  tm->tm_hour = atoi(str);
2891 
2892  return DTK_TIME;
2893  }
2894  }
2895 
2896  return DTERR_BAD_FORMAT;
2897 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
int tm_hour
Definition: pgtime.h:29
#define DTK_TIME_M
Definition: datetime.h:195
#define DTK_DATE_M
Definition: datetime.h:194
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
double rint(double x)
Definition: rint.c:22
#define DTK_TIME
Definition: datetime.h:146
#define NULL
Definition: c.h:229
int tm_year
Definition: pgtime.h:32
#define TRUE
Definition: c.h:217
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
#define DTK_DATE
Definition: datetime.h:145
int DecodeSpecial ( int  field,
char *  lowtoken,
int *  val 
)

Definition at line 3039 of file datetime.c.

References datebsearch(), NULL, szdatetktbl, datetkn::token, TOKMAXLEN, datetkn::type, UNKNOWN_FIELD, and datetkn::value.

Referenced by DecodeDate(), DecodeDateTime(), DecodeTimeOnly(), interval_part(), time_part(), timestamp_part(), timestamptz_part(), and timetz_part().

3040 {
3041  int type;
3042  const datetkn *tp;
3043 
3044  tp = datecache[field];
3045  /* use strncmp so that we match truncated tokens */
3046  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3047  {
3048  tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
3049  }
3050  if (tp == NULL)
3051  {
3052  type = UNKNOWN_FIELD;
3053  *val = 0;
3054  }
3055  else
3056  {
3057  datecache[field] = tp;
3058  type = tp->type;
3059  *val = tp->value;
3060  }
3061 
3062  return type;
3063 }
static const datetkn datetktbl[]
Definition: datetime.c:90
#define UNKNOWN_FIELD
Definition: datetime.h:125
int32 value
Definition: datetime.h:214
static int szdatetktbl
Definition: datetime.c:168
char token[TOKMAXLEN+1]
Definition: datetime.h:212
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:3810
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:229
static const datetkn * datecache[MAXDATEFIELDS]
Definition: datetime.c:247
#define TOKMAXLEN
Definition: datetime.h:207
long val
Definition: informix.c:689
static int DecodeTime ( char *  str,
int  fmask,
int  range,
int *  tmask,
struct pg_tm tm,
fsec_t fsec 
)
static

Definition at line 2558 of file datetime.c.

References DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_TIME_M, INT64CONST, INTERVAL_MASK, MINS_PER_HOUR, MINUTE, ParseFractionalSecond(), SECOND, SECS_PER_MINUTE, strtoint(), pg_tm::tm_hour, pg_tm::tm_min, pg_tm::tm_sec, and USECS_PER_SEC.

Referenced by DecodeDateTime(), DecodeInterval(), and DecodeTimeOnly().

2560 {
2561  char *cp;
2562  int dterr;
2563 
2564  *tmask = DTK_TIME_M;
2565 
2566  errno = 0;
2567  tm->tm_hour = strtoint(str, &cp, 10);
2568  if (errno == ERANGE)
2569  return DTERR_FIELD_OVERFLOW;
2570  if (*cp != ':')
2571  return DTERR_BAD_FORMAT;
2572  errno = 0;
2573  tm->tm_min = strtoint(cp + 1, &cp, 10);
2574  if (errno == ERANGE)
2575  return DTERR_FIELD_OVERFLOW;
2576  if (*cp == '\0')
2577  {
2578  tm->tm_sec = 0;
2579  *fsec = 0;
2580  /* If it's a MINUTE TO SECOND interval, take 2 fields as being mm:ss */
2582  {
2583  tm->tm_sec = tm->tm_min;
2584  tm->tm_min = tm->tm_hour;
2585  tm->tm_hour = 0;
2586  }
2587  }
2588  else if (*cp == '.')
2589  {
2590  /* always assume mm:ss.sss is MINUTE TO SECOND */
2591  dterr = ParseFractionalSecond(cp, fsec);
2592  if (dterr)
2593  return dterr;
2594  tm->tm_sec = tm->tm_min;
2595  tm->tm_min = tm->tm_hour;
2596  tm->tm_hour = 0;
2597  }
2598  else if (*cp == ':')
2599  {
2600  errno = 0;
2601  tm->tm_sec = strtoint(cp + 1, &cp, 10);
2602  if (errno == ERANGE)
2603  return DTERR_FIELD_OVERFLOW;
2604  if (*cp == '\0')
2605  *fsec = 0;
2606  else if (*cp == '.')
2607  {
2608  dterr = ParseFractionalSecond(cp, fsec);
2609  if (dterr)
2610  return dterr;
2611  }
2612  else
2613  return DTERR_BAD_FORMAT;
2614  }
2615  else
2616  return DTERR_BAD_FORMAT;
2617 
2618  /* do a sanity check */
2619  if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
2620  tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
2621  *fsec < INT64CONST(0) ||
2622  *fsec > USECS_PER_SEC)
2623  return DTERR_FIELD_OVERFLOW;
2624 
2625  return 0;
2626 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define USECS_PER_SEC
Definition: timestamp.h:94
int tm_hour
Definition: pgtime.h:29
#define DTK_TIME_M
Definition: datetime.h:195
#define SECOND
Definition: datetime.h:103
#define MINS_PER_HOUR
Definition: timestamp.h:89
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
#define SECS_PER_MINUTE
Definition: timestamp.h:88
#define MINUTE
Definition: datetime.h:102
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:416
static int ParseFractionalSecond(char *cp, fsec_t *fsec)
Definition: datetime.c:514
static int strtoint(const char *nptr, char **endptr, int base)
Definition: datetime.c:258
#define INT64CONST(x)
Definition: c.h:310
#define INTERVAL_MASK(b)
Definition: timestamp.h:45
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
int DecodeTimeOnly ( char **  field,
int *  ftype,
int  nf,
int *  dtype,
struct pg_tm tm,
fsec_t fsec,
int *  tzp 
)

Definition at line 1744 of file datetime.c.

References ADBC, AM, AMPM, BC, DAY, DecodeDate(), DecodeNumber(), DecodeNumberField(), DecodeSpecial(), DecodeTime(), DecodeTimezone(), DecodeTimezoneAbbrev(), DetermineTimeZoneAbbrevOffset(), DetermineTimeZoneOffset(), dt2time(), DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_ALL_SECS_M, DTK_CURRENT, DTK_DATE, DTK_DATE_M, DTK_DAY, DTK_HOUR, DTK_JULIAN, DTK_M, DTK_MINUTE, DTK_MONTH, DTK_NOW, DTK_NUMBER, DTK_SECOND, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TIME_M, DTK_TZ, DTK_YEAR, DTK_ZULU, DTZ, DTZMOD, DYNTZ, ereport, errcode(), errmsg(), ERROR, FALSE, GetCurrentDateTime(), GetCurrentTimeUsec(), HOUR, HOURS_PER_DAY, HR24, i, IGNORE_DTF, INT64CONST, INTERVAL_FULL_RANGE, ISOTIME, j2date(), MINS_PER_HOUR, MINUTE, MONTH, NULL, ParseFractionalSecond(), pg_get_timezone_offset(), pg_tzset(), PM, RESERV, SECOND, SECS_PER_MINUTE, session_timezone, strtoint(), pg_tm::tm_hour, pg_tm::tm_isdst, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_year, TRUE, TZ, UNITS, UNKNOWN_FIELD, USECS_PER_DAY, USECS_PER_SEC, val, ValidateDate(), and YEAR.

Referenced by time_in(), and timetz_in().

1746 {
1747  int fmask = 0,
1748  tmask,
1749  type;
1750  int ptype = 0; /* "prefix type" for ISO h04mm05s06 format */
1751  int i;
1752  int val;
1753  int dterr;
1754  bool isjulian = FALSE;
1755  bool is2digits = FALSE;
1756  bool bc = FALSE;
1757  int mer = HR24;
1758  pg_tz *namedTz = NULL;
1759  pg_tz *abbrevTz = NULL;
1760  char *abbrev = NULL;
1761  pg_tz *valtz;
1762 
1763  *dtype = DTK_TIME;
1764  tm->tm_hour = 0;
1765  tm->tm_min = 0;
1766  tm->tm_sec = 0;
1767  *fsec = 0;
1768  /* don't know daylight savings time status apriori */
1769  tm->tm_isdst = -1;
1770 
1771  if (tzp != NULL)
1772  *tzp = 0;
1773 
1774  for (i = 0; i < nf; i++)
1775  {
1776  switch (ftype[i])
1777  {
1778  case DTK_DATE:
1779 
1780  /*
1781  * Time zone not allowed? Then should not accept dates or time
1782  * zones no matter what else!
1783  */
1784  if (tzp == NULL)
1785  return DTERR_BAD_FORMAT;
1786 
1787  /* Under limited circumstances, we will accept a date... */
1788  if (i == 0 && nf >= 2 &&
1789  (ftype[nf - 1] == DTK_DATE || ftype[1] == DTK_TIME))
1790  {
1791  dterr = DecodeDate(field[i], fmask,
1792  &tmask, &is2digits, tm);
1793  if (dterr)
1794  return dterr;
1795  }
1796  /* otherwise, this is a time and/or time zone */
1797  else
1798  {
1799  if (isdigit((unsigned char) *field[i]))
1800  {
1801  char *cp;
1802 
1803  /*
1804  * Starts with a digit but we already have a time
1805  * field? Then we are in trouble with time already...
1806  */
1807  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1808  return DTERR_BAD_FORMAT;
1809 
1810  /*
1811  * Should not get here and fail. Sanity check only...
1812  */
1813  if ((cp = strchr(field[i], '-')) == NULL)
1814  return DTERR_BAD_FORMAT;
1815 
1816  /* Get the time zone from the end of the string */
1817  dterr = DecodeTimezone(cp, tzp);
1818  if (dterr)
1819  return dterr;
1820  *cp = '\0';
1821 
1822  /*
1823  * Then read the rest of the field as a concatenated
1824  * time
1825  */
1826  dterr = DecodeNumberField(strlen(field[i]), field[i],
1827  (fmask | DTK_DATE_M),
1828  &tmask, tm,
1829  fsec, &is2digits);
1830  if (dterr < 0)
1831  return dterr;
1832  ftype[i] = dterr;
1833 
1834  tmask |= DTK_M(TZ);
1835  }
1836  else
1837  {
1838  namedTz = pg_tzset(field[i]);
1839  if (!namedTz)
1840  {
1841  /*
1842  * We should return an error code instead of
1843  * ereport'ing directly, but then there is no way
1844  * to report the bad time zone name.
1845  */
1846  ereport(ERROR,
1847  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1848  errmsg("time zone \"%s\" not recognized",
1849  field[i])));
1850  }
1851  /* we'll apply the zone setting below */
1852  ftype[i] = DTK_TZ;
1853  tmask = DTK_M(TZ);
1854  }
1855  }
1856  break;
1857 
1858  case DTK_TIME:
1859  dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
1861  &tmask, tm, fsec);
1862  if (dterr)
1863  return dterr;
1864  break;
1865 
1866  case DTK_TZ:
1867  {
1868  int tz;
1869 
1870  if (tzp == NULL)
1871  return DTERR_BAD_FORMAT;
1872 
1873  dterr = DecodeTimezone(field[i], &tz);
1874  if (dterr)
1875  return dterr;
1876  *tzp = tz;
1877  tmask = DTK_M(TZ);
1878  }
1879  break;
1880 
1881  case DTK_NUMBER:
1882 
1883  /*
1884  * Was this an "ISO time" with embedded field labels? An
1885  * example is "h04m05s06" - thomas 2001-02-04
1886  */
1887  if (ptype != 0)
1888  {
1889  char *cp;
1890  int val;
1891 
1892  /* Only accept a date under limited circumstances */
1893  switch (ptype)
1894  {
1895  case DTK_JULIAN:
1896  case DTK_YEAR:
1897  case DTK_MONTH:
1898  case DTK_DAY:
1899  if (tzp == NULL)
1900  return DTERR_BAD_FORMAT;
1901  default:
1902  break;
1903  }
1904 
1905  errno = 0;
1906  val = strtoint(field[i], &cp, 10);
1907  if (errno == ERANGE)
1908  return DTERR_FIELD_OVERFLOW;
1909 
1910  /*
1911  * only a few kinds are allowed to have an embedded
1912  * decimal
1913  */
1914  if (*cp == '.')
1915  switch (ptype)
1916  {
1917  case DTK_JULIAN:
1918  case DTK_TIME:
1919  case DTK_SECOND:
1920  break;
1921  default:
1922  return DTERR_BAD_FORMAT;
1923  break;
1924  }
1925  else if (*cp != '\0')
1926  return DTERR_BAD_FORMAT;
1927 
1928  switch (ptype)
1929  {
1930  case DTK_YEAR:
1931  tm->tm_year = val;
1932  tmask = DTK_M(YEAR);
1933  break;
1934 
1935  case DTK_MONTH:
1936 
1937  /*
1938  * already have a month and hour? then assume
1939  * minutes
1940  */
1941  if ((fmask & DTK_M(MONTH)) != 0 &&
1942  (fmask & DTK_M(HOUR)) != 0)
1943  {
1944  tm->tm_min = val;
1945  tmask = DTK_M(MINUTE);
1946  }
1947  else
1948  {
1949  tm->tm_mon = val;
1950  tmask = DTK_M(MONTH);
1951  }
1952  break;
1953 
1954  case DTK_DAY:
1955  tm->tm_mday = val;
1956  tmask = DTK_M(DAY);
1957  break;
1958 
1959  case DTK_HOUR:
1960  tm->tm_hour = val;
1961  tmask = DTK_M(HOUR);
1962  break;
1963 
1964  case DTK_MINUTE:
1965  tm->tm_min = val;
1966  tmask = DTK_M(MINUTE);
1967  break;
1968 
1969  case DTK_SECOND:
1970  tm->tm_sec = val;
1971  tmask = DTK_M(SECOND);
1972  if (*cp == '.')
1973  {
1974  dterr = ParseFractionalSecond(cp, fsec);
1975  if (dterr)
1976  return dterr;
1977  tmask = DTK_ALL_SECS_M;
1978  }
1979  break;
1980 
1981  case DTK_TZ:
1982  tmask = DTK_M(TZ);
1983  dterr = DecodeTimezone(field[i], tzp);
1984  if (dterr)
1985  return dterr;
1986  break;
1987 
1988  case DTK_JULIAN:
1989  /* previous field was a label for "julian date" */
1990  if (val < 0)
1991  return DTERR_FIELD_OVERFLOW;
1992  tmask = DTK_DATE_M;
1993  j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1994  isjulian = TRUE;
1995 
1996  if (*cp == '.')
1997  {
1998  double time;
1999 
2000  errno = 0;
2001  time = strtod(cp, &cp);
2002  if (*cp != '\0' || errno != 0)
2003  return DTERR_BAD_FORMAT;
2004  time *= USECS_PER_DAY;
2005  dt2time(time,
2006  &tm->tm_hour, &tm->tm_min,
2007  &tm->tm_sec, fsec);
2008  tmask |= DTK_TIME_M;
2009  }
2010  break;
2011 
2012  case DTK_TIME:
2013  /* previous field was "t" for ISO time */
2014  dterr = DecodeNumberField(strlen(field[i]), field[i],
2015  (fmask | DTK_DATE_M),
2016  &tmask, tm,
2017  fsec, &is2digits);
2018  if (dterr < 0)
2019  return dterr;
2020  ftype[i] = dterr;
2021 
2022  if (tmask != DTK_TIME_M)
2023  return DTERR_BAD_FORMAT;
2024  break;
2025 
2026  default:
2027  return DTERR_BAD_FORMAT;
2028  break;
2029  }
2030 
2031  ptype = 0;
2032  *dtype = DTK_DATE;
2033  }
2034  else
2035  {
2036  char *cp;
2037  int flen;
2038 
2039  flen = strlen(field[i]);
2040  cp = strchr(field[i], '.');
2041 
2042  /* Embedded decimal? */
2043  if (cp != NULL)
2044  {
2045  /*
2046  * Under limited circumstances, we will accept a
2047  * date...
2048  */
2049  if (i == 0 && nf >= 2 && ftype[nf - 1] == DTK_DATE)
2050  {
2051  dterr = DecodeDate(field[i], fmask,
2052  &tmask, &is2digits, tm);
2053  if (dterr)
2054  return dterr;
2055  }
2056  /* embedded decimal and several digits before? */
2057  else if (flen - strlen(cp) > 2)
2058  {
2059  /*
2060  * Interpret as a concatenated date or time Set
2061  * the type field to allow decoding other fields
2062  * later. Example: 20011223 or 040506
2063  */
2064  dterr = DecodeNumberField(flen, field[i],
2065  (fmask | DTK_DATE_M),
2066  &tmask, tm,
2067  fsec, &is2digits);
2068  if (dterr < 0)
2069  return dterr;
2070  ftype[i] = dterr;
2071  }
2072  else
2073  return DTERR_BAD_FORMAT;
2074  }
2075  else if (flen > 4)
2076  {
2077  dterr = DecodeNumberField(flen, field[i],
2078  (fmask | DTK_DATE_M),
2079  &tmask, tm,
2080  fsec, &is2digits);
2081  if (dterr < 0)
2082  return dterr;
2083  ftype[i] = dterr;
2084  }
2085  /* otherwise it is a single date/time field... */
2086  else
2087  {
2088  dterr = DecodeNumber(flen, field[i],
2089  FALSE,
2090  (fmask | DTK_DATE_M),
2091  &tmask, tm,
2092  fsec, &is2digits);
2093  if (dterr)
2094  return dterr;
2095  }
2096  }
2097  break;
2098 
2099  case DTK_STRING:
2100  case DTK_SPECIAL:
2101  /* timezone abbrevs take precedence over built-in tokens */
2102  type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
2103  if (type == UNKNOWN_FIELD)
2104  type = DecodeSpecial(i, field[i], &val);
2105  if (type == IGNORE_DTF)
2106  continue;
2107 
2108  tmask = DTK_M(type);
2109  switch (type)
2110  {
2111  case RESERV:
2112  switch (val)
2113  {
2114  case DTK_CURRENT:
2115  ereport(ERROR,
2116  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2117  errmsg("date/time value \"current\" is no longer supported")));
2118  return DTERR_BAD_FORMAT;
2119  break;
2120 
2121  case DTK_NOW:
2122  tmask = DTK_TIME_M;
2123  *dtype = DTK_TIME;
2124  GetCurrentTimeUsec(tm, fsec, NULL);
2125  break;
2126 
2127  case DTK_ZULU:
2128  tmask = (DTK_TIME_M | DTK_M(TZ));
2129  *dtype = DTK_TIME;
2130  tm->tm_hour = 0;
2131  tm->tm_min = 0;
2132  tm->tm_sec = 0;
2133  tm->tm_isdst = 0;
2134  break;
2135 
2136  default:
2137  return DTERR_BAD_FORMAT;
2138  }
2139 
2140  break;
2141 
2142  case DTZMOD:
2143 
2144  /*
2145  * daylight savings time modifier (solves "MET DST"
2146  * syntax)
2147  */
2148  tmask |= DTK_M(DTZ);
2149  tm->tm_isdst = 1;
2150  if (tzp == NULL)
2151  return DTERR_BAD_FORMAT;
2152  *tzp -= val;
2153  break;
2154 
2155  case DTZ:
2156 
2157  /*
2158  * set mask for TZ here _or_ check for DTZ later when
2159  * getting default timezone
2160  */
2161  tmask |= DTK_M(TZ);
2162  tm->tm_isdst = 1;
2163  if (tzp == NULL)
2164  return DTERR_BAD_FORMAT;
2165  *tzp = -val;
2166  ftype[i] = DTK_TZ;
2167  break;
2168 
2169  case TZ:
2170  tm->tm_isdst = 0;
2171  if (tzp == NULL)
2172  return DTERR_BAD_FORMAT;
2173  *tzp = -val;
2174  ftype[i] = DTK_TZ;
2175  break;
2176 
2177  case DYNTZ:
2178  tmask |= DTK_M(TZ);
2179  if (tzp == NULL)
2180  return DTERR_BAD_FORMAT;
2181  /* we'll determine the actual offset later */
2182  abbrevTz = valtz;
2183  abbrev = field[i];
2184  ftype[i] = DTK_TZ;
2185  break;
2186 
2187  case AMPM:
2188  mer = val;
2189  break;
2190 
2191  case ADBC:
2192  bc = (val == BC);
2193  break;
2194 
2195  case UNITS:
2196  tmask = 0;
2197  ptype = val;
2198  break;
2199 
2200  case ISOTIME:
2201  tmask = 0;
2202 
2203  /***
2204  * We will need one of the following fields:
2205  * DTK_NUMBER should be hhmmss.fff
2206  * DTK_TIME should be hh:mm:ss.fff
2207  * DTK_DATE should be hhmmss-zz
2208  ***/
2209  if (i >= nf - 1 ||
2210  (ftype[i + 1] != DTK_NUMBER &&
2211  ftype[i + 1] != DTK_TIME &&
2212  ftype[i + 1] != DTK_DATE))
2213  return DTERR_BAD_FORMAT;
2214 
2215  ptype = val;
2216  break;
2217 
2218  case UNKNOWN_FIELD:
2219 
2220  /*
2221  * Before giving up and declaring error, check to see
2222  * if it is an all-alpha timezone name.
2223  */
2224  namedTz = pg_tzset(field[i]);
2225  if (!namedTz)
2226  return DTERR_BAD_FORMAT;
2227  /* we'll apply the zone setting below */
2228  tmask = DTK_M(TZ);
2229  break;
2230 
2231  default:
2232  return DTERR_BAD_FORMAT;
2233  }
2234  break;
2235 
2236  default:
2237  return DTERR_BAD_FORMAT;
2238  }
2239 
2240  if (tmask & fmask)
2241  return DTERR_BAD_FORMAT;
2242  fmask |= tmask;
2243  } /* end loop over fields */
2244 
2245  /* do final checking/adjustment of Y/M/D fields */
2246  dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
2247  if (dterr)
2248  return dterr;
2249 
2250  /* handle AM/PM */
2251  if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
2252  return DTERR_FIELD_OVERFLOW;
2253  if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
2254  tm->tm_hour = 0;
2255  else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
2256  tm->tm_hour += HOURS_PER_DAY / 2;
2257 
2258  /*
2259  * This should match the checks in make_timestamp_internal
2260  */
2261  if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
2262  tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
2263  tm->tm_hour > HOURS_PER_DAY ||
2264  /* test for > 24:00:00 */
2265  (tm->tm_hour == HOURS_PER_DAY &&
2266  (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0)) ||
2267  *fsec < INT64CONST(0) || *fsec > USECS_PER_SEC)
2268  return DTERR_FIELD_OVERFLOW;
2269 
2270  if ((fmask & DTK_TIME_M) != DTK_TIME_M)
2271  return DTERR_BAD_FORMAT;
2272 
2273  /*
2274  * If we had a full timezone spec, compute the offset (we could not do it
2275  * before, because we may need the date to resolve DST status).
2276  */
2277  if (namedTz != NULL)
2278  {
2279  long int gmtoff;
2280 
2281  /* daylight savings time modifier disallowed with full TZ */
2282  if (fmask & DTK_M(DTZMOD))
2283  return DTERR_BAD_FORMAT;
2284 
2285  /* if non-DST zone, we do not need to know the date */
2286  if (pg_get_timezone_offset(namedTz, &gmtoff))
2287  {
2288  *tzp = -(int) gmtoff;
2289  }
2290  else
2291  {
2292  /* a date has to be specified */
2293  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2294  return DTERR_BAD_FORMAT;
2295  *tzp = DetermineTimeZoneOffset(tm, namedTz);
2296  }
2297  }
2298 
2299  /*
2300  * Likewise, if we had a dynamic timezone abbreviation, resolve it now.
2301  */
2302  if (abbrevTz != NULL)
2303  {
2304  struct pg_tm tt,
2305  *tmp = &tt;
2306 
2307  /*
2308  * daylight savings time modifier but no standard timezone? then error
2309  */
2310  if (fmask & DTK_M(DTZMOD))
2311  return DTERR_BAD_FORMAT;
2312 
2313  if ((fmask & DTK_DATE_M) == 0)
2314  GetCurrentDateTime(tmp);
2315  else
2316  {
2317  tmp->tm_year = tm->tm_year;
2318  tmp->tm_mon = tm->tm_mon;
2319  tmp->tm_mday = tm->tm_mday;
2320  }
2321  tmp->tm_hour = tm->tm_hour;
2322  tmp->tm_min = tm->tm_min;
2323  tmp->tm_sec = tm->tm_sec;
2324  *tzp = DetermineTimeZoneAbbrevOffset(tmp, abbrev, abbrevTz);
2325  tm->tm_isdst = tmp->tm_isdst;
2326  }
2327 
2328  /* timezone not specified? then use session timezone */
2329  if (tzp != NULL && !(fmask & DTK_M(TZ)))
2330  {
2331  struct pg_tm tt,
2332  *tmp = &tt;
2333 
2334  /*
2335  * daylight savings time modifier but no standard timezone? then error
2336  */
2337  if (fmask & DTK_M(DTZMOD))
2338  return DTERR_BAD_FORMAT;
2339 
2340  if ((fmask & DTK_DATE_M) == 0)
2341  GetCurrentDateTime(tmp);
2342  else
2343  {
2344  tmp->tm_year = tm->tm_year;
2345  tmp->tm_mon = tm->tm_mon;
2346  tmp->tm_mday = tm->tm_mday;
2347  }
2348  tmp->tm_hour = tm->tm_hour;
2349  tmp->tm_min = tm->tm_min;
2350  tmp->tm_sec = tm->tm_sec;
2352  tm->tm_isdst = tmp->tm_isdst;
2353  }
2354 
2355  return 0;
2356 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
void GetCurrentDateTime(struct pg_tm *tm)
Definition: datetime.c:370
#define PM
Definition: datetime.h:73
#define DAY
Definition: datetime.h:94
#define UNITS
Definition: datetime.h:108
#define IGNORE_DTF
Definition: datetime.h:99
#define DTK_JULIAN
Definition: datetime.h:176
#define DTK_YEAR
Definition: datetime.h:170
int tm_isdst
Definition: pgtime.h:35
#define USECS_PER_SEC
Definition: timestamp.h:94
#define YEAR
Definition: datetime.h:93
int tm_hour
Definition: pgtime.h:29
#define DTK_TIME_M
Definition: datetime.h:195
int errcode(int sqlerrcode)
Definition: elog.c:575
#define TZ
Definition: datetime.h:96
#define UNKNOWN_FIELD
Definition: datetime.h:125
#define SECOND
Definition: datetime.h:103
static int DecodeNumberField(int len, char *str, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2819
#define ADBC
Definition: datetime.h:109
Definition: pgtime.h:25
#define DTK_CURRENT
Definition: datetime.h:152
#define INTERVAL_FULL_RANGE
Definition: timestamp.h:48
#define DTK_DATE_M
Definition: datetime.h:194
#define MINS_PER_HOUR
Definition: timestamp.h:89
pg_tz * pg_tzset(const char *tzname)
Definition: pgtz.c:218
#define DTK_MONTH
Definition: datetime.h:168
#define DTK_TZ
Definition: datetime.h:147
#define DTK_HOUR
Definition: datetime.h:165
#define ERROR
Definition: elog.h:43
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
#define AM
Definition: datetime.h:72
int DecodeTimezoneAbbrev(int field, char *lowtoken, int *offset, pg_tz **tz)
Definition: datetime.c:2984
#define FALSE
Definition: c.h:221
#define DTK_SECOND
Definition: datetime.h:163
int DecodeTimezone(char *str, int *tzp)
Definition: datetime.c:2906
int tm_mday
Definition: pgtime.h:30
#define HOURS_PER_DAY
Definition: timestamp.h:78
int tm_mon
Definition: pgtime.h:31
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1471
#define SECS_PER_MINUTE
Definition: timestamp.h:88
static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits, struct pg_tm *tm)
Definition: datetime.c:2369
void GetCurrentTimeUsec(struct pg_tm *tm, fsec_t *fsec, int *tzp)
Definition: datetime.c:387
#define DTK_NUMBER
Definition: datetime.h:142
#define MINUTE
Definition: datetime.h:102
#define USECS_PER_DAY
Definition: timestamp.h:91
#define ereport(elevel, rest)
Definition: elog.h:122
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:317
#define MONTH
Definition: datetime.h:92
#define DTK_MINUTE
Definition: datetime.h:164
static int ParseFractionalSecond(char *cp, fsec_t *fsec)
Definition: datetime.c:514
#define BC
Definition: datetime.h:77
Definition: pgtz.h:59
#define ISOTIME
Definition: datetime.h:116
#define DTK_TIME
Definition: datetime.h:146
static int DecodeTime(char *str, int fmask, int range, int *tmask, struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:2558
void dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
Definition: timestamp.c:1730
static int strtoint(const char *nptr, char **endptr, int base)
Definition: datetime.c:258
#define NULL
Definition: c.h:229
#define AMPM
Definition: datetime.h:100
#define INT64CONST(x)
Definition: c.h:310
#define DTK_STRING
Definition: datetime.h:143
#define DTK_DAY
Definition: datetime.h:166
static int DecodeNumber(int flen, char *field, bool haveTextMonth, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2634
#define RESERV
Definition: datetime.h:91
int DecodeSpecial(int field, char *lowtoken, int *val)
Definition: datetime.c:3039
#define DTK_ALL_SECS_M
Definition: datetime.h:193
#define DTZ
Definition: datetime.h:97
int tm_year
Definition: pgtime.h:32
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define DYNTZ
Definition: datetime.h:98
#define DTK_NOW
Definition: datetime.h:156
int i
#define DTK_M(t)
Definition: datetime.h:190
pg_tz * session_timezone
Definition: pgtz.c:27
#define TRUE
Definition: c.h:217
#define HOUR
Definition: datetime.h:101
bool pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff)
Definition: localtime.c:1746
#define DTK_ZULU
Definition: datetime.h:160
int tm_sec
Definition: pgtime.h:27
#define DTZMOD
Definition: datetime.h:123
int tm_min
Definition: pgtime.h:28
int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp)
Definition: datetime.c:1629
long val
Definition: informix.c:689
#define DTK_DATE
Definition: datetime.h:145
#define HR24
Definition: datetime.h:74
#define DTK_SPECIAL
Definition: datetime.h:150
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2479
int DecodeTimezone ( char *  str,
int *  tzp 
)

Definition at line 2906 of file datetime.c.

References DTERR_BAD_FORMAT, DTERR_TZDISP_OVERFLOW, MAX_TZDISP_HOUR, MINS_PER_HOUR, SECS_PER_MINUTE, and strtoint().

Referenced by DecodeDateTime(), DecodeTimeOnly(), and parse_sane_timezone().

2907 {
2908  int tz;
2909  int hr,
2910  min,
2911  sec = 0;
2912  char *cp;
2913 
2914  /* leading character must be "+" or "-" */
2915  if (*str != '+' && *str != '-')
2916  return DTERR_BAD_FORMAT;
2917 
2918  errno = 0;
2919  hr = strtoint(str + 1, &cp, 10);
2920  if (errno == ERANGE)
2921  return DTERR_TZDISP_OVERFLOW;
2922 
2923  /* explicit delimiter? */
2924  if (*cp == ':')
2925  {
2926  errno = 0;
2927  min = strtoint(cp + 1, &cp, 10);
2928  if (errno == ERANGE)
2929  return DTERR_TZDISP_OVERFLOW;
2930  if (*cp == ':')
2931  {
2932  errno = 0;
2933  sec = strtoint(cp + 1, &cp, 10);
2934  if (errno == ERANGE)
2935  return DTERR_TZDISP_OVERFLOW;
2936  }
2937  }
2938  /* otherwise, might have run things together... */
2939  else if (*cp == '\0' && strlen(str) > 3)
2940  {
2941  min = hr % 100;
2942  hr = hr / 100;
2943  /* we could, but don't, support a run-together hhmmss format */
2944  }
2945  else
2946  min = 0;
2947 
2948  /* Range-check the values; see notes in datatype/timestamp.h */
2949  if (hr < 0 || hr > MAX_TZDISP_HOUR)
2950  return DTERR_TZDISP_OVERFLOW;
2951  if (min < 0 || min >= MINS_PER_HOUR)
2952  return DTERR_TZDISP_OVERFLOW;
2953  if (sec < 0 || sec >= SECS_PER_MINUTE)
2954  return DTERR_TZDISP_OVERFLOW;
2955 
2956  tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec;
2957  if (*str == '-')
2958  tz = -tz;
2959 
2960  *tzp = -tz;
2961 
2962  if (*cp != '\0')
2963  return DTERR_BAD_FORMAT;
2964 
2965  return 0;
2966 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define MINS_PER_HOUR
Definition: timestamp.h:89
#define MAX_TZDISP_HOUR
Definition: timestamp.h:103
#define SECS_PER_MINUTE
Definition: timestamp.h:88
#define DTERR_TZDISP_OVERFLOW
Definition: datetime.h:286
static int strtoint(const char *nptr, char **endptr, int base)
Definition: datetime.c:258
int DecodeTimezoneAbbrev ( int  field,
char *  lowtoken,
int *  offset,
pg_tz **  tz 
)

Definition at line 2984 of file datetime.c.

References TimeZoneAbbrevTable::abbrevs, datebsearch(), DYNTZ, FetchDynamicTimeZone(), NULL, TimeZoneAbbrevTable::numabbrevs, datetkn::token, TOKMAXLEN, datetkn::type, UNKNOWN_FIELD, and datetkn::value.

Referenced by DecodeDateTime(), DecodeTimeOnly(), parse_sane_timezone(), timestamp_zone(), timestamptz_zone(), and timetz_zone().

2986 {
2987  int type;
2988  const datetkn *tp;
2989 
2990  tp = abbrevcache[field];
2991  /* use strncmp so that we match truncated tokens */
2992  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
2993  {
2994  if (zoneabbrevtbl)
2995  tp = datebsearch(lowtoken, zoneabbrevtbl->abbrevs,
2997  else
2998  tp = NULL;
2999  }
3000  if (tp == NULL)
3001  {
3002  type = UNKNOWN_FIELD;
3003  *offset = 0;
3004  *tz = NULL;
3005  }
3006  else
3007  {
3008  abbrevcache[field] = tp;
3009  type = tp->type;
3010  if (type == DYNTZ)
3011  {
3012  *offset = 0;
3014  }
3015  else
3016  {
3017  *offset = tp->value;
3018  *tz = NULL;
3019  }
3020  }
3021 
3022  return type;
3023 }
static pg_tz * FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp)
Definition: datetime.c:4614
#define UNKNOWN_FIELD
Definition: datetime.h:125
int32 value
Definition: datetime.h:214
char token[TOKMAXLEN+1]
Definition: datetime.h:212
datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:222
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:3810
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:229
static TimeZoneAbbrevTable * zoneabbrevtbl
Definition: datetime.c:243
static const datetkn * abbrevcache[MAXDATEFIELDS]
Definition: datetime.c:251
#define DYNTZ
Definition: datetime.h:98
#define TOKMAXLEN
Definition: datetime.h:207
int DecodeUnits ( int  field,
char *  lowtoken,
int *  val 
)

Definition at line 3728 of file datetime.c.

Referenced by DecodeInterval(), interval_part(), interval_trunc(), time_part(), timestamp_part(), timestamp_trunc(), timestamptz_part(), timestamptz_trunc(), and timetz_part().

3729 {
3730  int type;
3731  const datetkn *tp;
3732 
3733  tp = deltacache[field];
3734  /* use strncmp so that we match truncated tokens */
3735  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3736  {
3737  tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
3738  }
3739  if (tp == NULL)
3740  {
3741  type = UNKNOWN_FIELD;
3742  *val = 0;
3743  }
3744  else
3745  {
3746  deltacache[field] = tp;
3747  type = tp->type;
3748  *val = tp->value;
3749  }
3750 
3751  return type;
3752 } /* DecodeUnits() */
static const datetkn * deltacache[MAXDATEFIELDS]
Definition: datetime.c:249
#define UNKNOWN_FIELD
Definition: datetime.h:125
int32 value
Definition: datetime.h:214
char token[TOKMAXLEN+1]
Definition: datetime.h:212
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:3810
static const datetkn deltatktbl[]
Definition: datetime.c:174
static int szdeltatktbl
Definition: datetime.c:241
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:229
#define TOKMAXLEN
Definition: datetime.h:207
long val
Definition: informix.c:689
int DetermineTimeZoneAbbrevOffset ( struct pg_tm tm,
const char *  abbr,
pg_tz tzp 
)

Definition at line 1629 of file datetime.c.

References DetermineTimeZoneAbbrevOffsetInternal(), DetermineTimeZoneOffsetInternal(), and pg_tm::tm_isdst.

Referenced by DecodeDateTime(), DecodeTimeOnly(), parse_sane_timezone(), timestamp_zone(), and timetz_zone().

1630 {
1631  pg_time_t t;
1632  int zone_offset;
1633  int abbr_offset;
1634  int abbr_isdst;
1635 
1636  /*
1637  * Compute the UTC time we want to probe at. (In event of overflow, we'll
1638  * probe at the epoch, which is a bit random but probably doesn't matter.)
1639  */
1640  zone_offset = DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1641 
1642  /*
1643  * Try to match the abbreviation to something in the zone definition.
1644  */
1645  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1646  &abbr_offset, &abbr_isdst))
1647  {
1648  /* Success, so use the abbrev-specific answers. */
1649  tm->tm_isdst = abbr_isdst;
1650  return abbr_offset;
1651  }
1652 
1653  /*
1654  * No match, so use the answers we already got from
1655  * DetermineTimeZoneOffsetInternal.
1656  */
1657  return zone_offset;
1658 }
int64 pg_time_t
Definition: pgtime.h:23
int tm_isdst
Definition: pgtime.h:35
static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp, pg_time_t *tp)
Definition: datetime.c:1493
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, int *offset, int *isdst)
Definition: datetime.c:1704
static bool DetermineTimeZoneAbbrevOffsetInternal ( pg_time_t  t,
const char *  abbr,
pg_tz tzp,
int *  offset,
int *  isdst 
)
static

Definition at line 1704 of file datetime.c.

References pg_interpret_timezone_abbrev(), pg_toupper(), strlcpy(), and TZ_STRLEN_MAX.

Referenced by DetermineTimeZoneAbbrevOffset(), and DetermineTimeZoneAbbrevOffsetTS().

1706 {
1707  char upabbr[TZ_STRLEN_MAX + 1];
1708  unsigned char *p;
1709  long int gmtoff;
1710 
1711  /* We need to force the abbrev to upper case */
1712  strlcpy(upabbr, abbr, sizeof(upabbr));
1713  for (p = (unsigned char *) upabbr; *p; p++)
1714  *p = pg_toupper(*p);
1715 
1716  /* Look up the abbrev's meaning at this time in this zone */
1717  if (pg_interpret_timezone_abbrev(upabbr,
1718  &t,
1719  &gmtoff,
1720  isdst,
1721  tzp))
1722  {
1723  /* Change sign to agree with DetermineTimeZoneOffset() */
1724  *offset = (int) -gmtoff;
1725  return true;
1726  }
1727  return false;
1728 }
#define TZ_STRLEN_MAX
Definition: pgtime.h:44
bool pg_interpret_timezone_abbrev(const char *abbrev, const pg_time_t *timep, long int *gmtoff, int *isdst, const pg_tz *tz)
Definition: localtime.c:1652
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
unsigned char pg_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:105
int DetermineTimeZoneAbbrevOffsetTS ( TimestampTz  ts,
const char *  abbr,
pg_tz tzp,
int *  isdst 
)

Definition at line 1667 of file datetime.c.

References DetermineTimeZoneAbbrevOffsetInternal(), DetermineTimeZoneOffset(), ereport, errcode(), errmsg(), ERROR, NULL, timestamp2tm(), timestamptz_to_time_t(), and pg_tm::tm_isdst.

Referenced by pg_timezone_abbrevs(), and timestamptz_zone().

1669 {
1671  int zone_offset;
1672  int abbr_offset;
1673  int tz;
1674  struct pg_tm tm;
1675  fsec_t fsec;
1676 
1677  /*
1678  * If the abbrev matches anything in the zone data, this is pretty easy.
1679  */
1680  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1681  &abbr_offset, isdst))
1682  return abbr_offset;
1683 
1684  /*
1685  * Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1686  */
1687  if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0)
1688  ereport(ERROR,
1689  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1690  errmsg("timestamp out of range")));
1691 
1692  zone_offset = DetermineTimeZoneOffset(&tm, tzp);
1693  *isdst = tm.tm_isdst;
1694  return zone_offset;
1695 }
int64 pg_time_t
Definition: pgtime.h:23
int tm_isdst
Definition: pgtime.h:35
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1757
int errcode(int sqlerrcode)
Definition: elog.c:575
Definition: pgtime.h:25
static struct pg_tm tm
Definition: localtime.c:103
#define ERROR
Definition: elog.h:43
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1471
pg_time_t timestamptz_to_time_t(TimestampTz t)
Definition: timestamp.c:1691
int32 fsec_t
Definition: timestamp.h:41
#define ereport(elevel, rest)
Definition: elog.h:122
#define NULL
Definition: c.h:229
int errmsg(const char *fmt,...)
Definition: elog.c:797
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, int *offset, int *isdst)
Definition: datetime.c:1704
int DetermineTimeZoneOffset ( struct pg_tm tm,
pg_tz tzp 
)

Definition at line 1471 of file datetime.c.

References DetermineTimeZoneOffsetInternal().

Referenced by date2timestamptz(), DecodeDateTime(), DecodeTimeOnly(), DetermineTimeZoneAbbrevOffsetTS(), parse_sane_timezone(), time_timetz(), timestamp2timestamptz(), timestamp_abstime(), timestamp_zone(), timestamptz_pl_interval(), timestamptz_trunc(), and to_timestamp().

1472 {
1473  pg_time_t t;
1474 
1475  return DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1476 }
int64 pg_time_t
Definition: pgtime.h:23
static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp, pg_time_t *tp)
Definition: datetime.c:1493
static int DetermineTimeZoneOffsetInternal ( struct pg_tm tm,
pg_tz tzp,
pg_time_t tp 
)
static

Definition at line 1493 of file datetime.c.

References date2j(), IS_VALID_JULIAN, MINS_PER_HOUR, pg_next_dst_boundary(), SECS_PER_DAY, SECS_PER_MINUTE, pg_tm::tm_hour, pg_tm::tm_isdst, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_year, and UNIX_EPOCH_JDATE.

Referenced by DetermineTimeZoneAbbrevOffset(), and DetermineTimeZoneOffset().

1494 {
1495  int date,
1496  sec;
1497  pg_time_t day,
1498  mytime,
1499  prevtime,
1500  boundary,
1501  beforetime,
1502  aftertime;
1503  long int before_gmtoff,
1504  after_gmtoff;
1505  int before_isdst,
1506  after_isdst;
1507  int res;
1508 
1509  /*
1510  * First, generate the pg_time_t value corresponding to the given
1511  * y/m/d/h/m/s taken as GMT time. If this overflows, punt and decide the
1512  * timezone is GMT. (For a valid Julian date, integer overflow should be
1513  * impossible with 64-bit pg_time_t, but let's check for safety.)
1514  */
1515  if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
1516  goto overflow;
1517  date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
1518 
1519  day = ((pg_time_t) date) * SECS_PER_DAY;
1520  if (day / SECS_PER_DAY != date)
1521  goto overflow;
1522  sec = tm->tm_sec + (tm->tm_min + tm->tm_hour * MINS_PER_HOUR) * SECS_PER_MINUTE;
1523  mytime = day + sec;
1524  /* since sec >= 0, overflow could only be from +day to -mytime */
1525  if (mytime < 0 && day > 0)
1526  goto overflow;
1527 
1528  /*
1529  * Find the DST time boundary just before or following the target time. We
1530  * assume that all zones have GMT offsets less than 24 hours, and that DST
1531  * boundaries can't be closer together than 48 hours, so backing up 24
1532  * hours and finding the "next" boundary will work.
1533  */
1534  prevtime = mytime - SECS_PER_DAY;
1535  if (mytime < 0 && prevtime > 0)
1536  goto overflow;
1537 
1538  res = pg_next_dst_boundary(&prevtime,
1539  &before_gmtoff, &before_isdst,
1540  &boundary,
1541  &after_gmtoff, &after_isdst,
1542  tzp);
1543  if (res < 0)
1544  goto overflow; /* failure? */
1545 
1546  if (res == 0)
1547  {
1548  /* Non-DST zone, life is simple */
1549  tm->tm_isdst = before_isdst;
1550  *tp = mytime - before_gmtoff;
1551  return -(int) before_gmtoff;
1552  }
1553 
1554  /*
1555  * Form the candidate pg_time_t values with local-time adjustment
1556  */
1557  beforetime = mytime - before_gmtoff;
1558  if ((before_gmtoff > 0 &&
1559  mytime < 0 && beforetime > 0) ||
1560  (before_gmtoff <= 0 &&
1561  mytime > 0 && beforetime < 0))
1562  goto overflow;
1563  aftertime = mytime - after_gmtoff;
1564  if ((after_gmtoff > 0 &&
1565  mytime < 0 && aftertime > 0) ||
1566  (after_gmtoff <= 0 &&
1567  mytime > 0 && aftertime < 0))
1568  goto overflow;
1569 
1570  /*
1571  * If both before or both after the boundary time, we know what to do. The
1572  * boundary time itself is considered to be after the transition, which
1573  * means we can accept aftertime == boundary in the second case.
1574  */
1575  if (beforetime < boundary && aftertime < boundary)
1576  {
1577  tm->tm_isdst = before_isdst;
1578  *tp = beforetime;
1579  return -(int) before_gmtoff;
1580  }
1581  if (beforetime > boundary && aftertime >= boundary)
1582  {
1583  tm->tm_isdst = after_isdst;
1584  *tp = aftertime;
1585  return -(int) after_gmtoff;
1586  }
1587 
1588  /*
1589  * It's an invalid or ambiguous time due to timezone transition. In a
1590  * spring-forward transition, prefer the "before" interpretation; in a
1591  * fall-back transition, prefer "after". (We used to define and implement
1592  * this test as "prefer the standard-time interpretation", but that rule
1593  * does not help to resolve the behavior when both times are reported as
1594  * standard time; which does happen, eg Europe/Moscow in Oct 2014.)
1595  */
1596  if (beforetime > aftertime)
1597  {
1598  tm->tm_isdst = before_isdst;
1599  *tp = beforetime;
1600  return -(int) before_gmtoff;
1601  }
1602  tm->tm_isdst = after_isdst;
1603  *tp = aftertime;
1604  return -(int) after_gmtoff;
1605 
1606 overflow:
1607  /* Given date is out of range, so assume UTC */
1608  tm->tm_isdst = 0;
1609  *tp = 0;
1610  return 0;
1611 }
int64 pg_time_t
Definition: pgtime.h:23
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:1505
int tm_isdst
Definition: pgtime.h:35
int tm_hour
Definition: pgtime.h:29
long date
Definition: pgtypes_date.h:8
#define MINS_PER_HOUR
Definition: timestamp.h:89
#define SECS_PER_DAY
Definition: timestamp.h:86
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:88
#define IS_VALID_JULIAN(y, m, d)
Definition: timestamp.h:155
int date2j(int y, int m, int d)
Definition: datetime.c:292
int tm_year
Definition: pgtime.h:32
#define UNIX_EPOCH_JDATE
Definition: timestamp.h:162
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
void EncodeDateOnly ( struct pg_tm tm,
int  style,
char *  str 
)

Definition at line 3884 of file datetime.c.

References Assert, DateOrder, DATEORDER_DMY, MONTHS_PER_YEAR, pg_ltostr_zeropad(), pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_year, USE_GERMAN_DATES, USE_ISO_DATES, USE_POSTGRES_DATES, USE_SQL_DATES, and USE_XSD_DATES.

Referenced by date_out(), datum_to_json(), datum_to_jsonb(), map_sql_value_to_xml_value(), and PGTYPESdate_to_asc().

3885 {
3886  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
3887 
3888  switch (style)
3889  {
3890  case USE_ISO_DATES:
3891  case USE_XSD_DATES:
3892  /* compatible with ISO date formats */
3893  str = pg_ltostr_zeropad(str,
3894  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
3895  *str++ = '-';
3896  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3897  *str++ = '-';
3898  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3899  break;
3900 
3901  case USE_SQL_DATES:
3902  /* compatible with Oracle/Ingres date formats */
3903  if (DateOrder == DATEORDER_DMY)
3904  {
3905  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3906  *str++ = '/';
3907  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3908  }
3909  else
3910  {
3911  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3912  *str++ = '/';
3913  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3914  }
3915  *str++ = '/';
3916  str = pg_ltostr_zeropad(str,
3917  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
3918  break;
3919 
3920  case USE_GERMAN_DATES:
3921  /* German-style date format */
3922  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3923  *str++ = '.';
3924  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3925  *str++ = '.';
3926  str = pg_ltostr_zeropad(str,
3927  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
3928  break;
3929 
3930  case USE_POSTGRES_DATES:
3931  default:
3932  /* traditional date-only style for Postgres */
3933  if (DateOrder == DATEORDER_DMY)
3934  {
3935  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3936  *str++ = '-';
3937  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3938  }
3939  else
3940  {
3941  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3942  *str++ = '-';
3943  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3944  }
3945  *str++ = '-';
3946  str = pg_ltostr_zeropad(str,
3947  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
3948  break;
3949  }
3950 
3951  if (tm->tm_year <= 0)
3952  {
3953  memcpy(str, " BC", 3); /* Don't copy NUL */
3954  str += 3;
3955  }
3956  *str = '\0';
3957 }
#define USE_SQL_DATES
Definition: miscadmin.h:211
#define USE_ISO_DATES
Definition: miscadmin.h:210
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define USE_POSTGRES_DATES
Definition: miscadmin.h:209
int DateOrder
Definition: globals.c:107
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
#define DATEORDER_DMY
Definition: miscadmin.h:217
#define Assert(condition)
Definition: c.h:675
#define USE_XSD_DATES
Definition: miscadmin.h:213
int tm_year
Definition: pgtime.h:32
#define USE_GERMAN_DATES
Definition: miscadmin.h:212
void EncodeDateTime ( struct pg_tm tm,
fsec_t  fsec,
bool  print_tz,
int  tz,
const char *  tzn,
int  style,
char *  str 
)

Definition at line 3999 of file datetime.c.

References AppendTimestampSeconds(), Assert, date2j(), DateOrder, DATEORDER_DMY, days, EncodeTimezone(), j2day(), MAXTZLEN, months, MONTHS_PER_YEAR, pg_ltostr_zeropad(), pg_tm::tm_hour, pg_tm::tm_isdst, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_wday, pg_tm::tm_year, USE_GERMAN_DATES, USE_ISO_DATES, USE_POSTGRES_DATES, USE_SQL_DATES, and USE_XSD_DATES.

Referenced by abstimeout(), datum_to_json(), datum_to_jsonb(), map_sql_value_to_xml_value(), PGTYPEStimestamp_to_asc(), timestamp_out(), timestamptz_out(), and timestamptz_to_str().

4000 {
4001  int day;
4002 
4003  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
4004 
4005  /*
4006  * Negative tm_isdst means we have no valid time zone translation.
4007  */
4008  if (tm->tm_isdst < 0)
4009  print_tz = false;
4010 
4011  switch (style)
4012  {
4013  case USE_ISO_DATES:
4014  case USE_XSD_DATES:
4015  /* Compatible with ISO-8601 date formats */
4016  str = pg_ltostr_zeropad(str,
4017  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4018  *str++ = '-';
4019  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4020  *str++ = '-';
4021  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4022  *str++ = (style == USE_ISO_DATES) ? ' ' : 'T';
4023  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4024  *str++ = ':';
4025  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4026  *str++ = ':';
4027  str = AppendTimestampSeconds(str, tm, fsec);
4028  if (print_tz)
4029  str = EncodeTimezone(str, tz, style);
4030  break;
4031 
4032  case USE_SQL_DATES:
4033  /* Compatible with Oracle/Ingres date formats */
4034  if (DateOrder == DATEORDER_DMY)
4035  {
4036  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4037  *str++ = '/';
4038  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4039  }
4040  else
4041  {
4042  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4043  *str++ = '/';
4044  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4045  }
4046  *str++ = '/';
4047  str = pg_ltostr_zeropad(str,
4048  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4049  *str++ = ' ';
4050  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4051  *str++ = ':';
4052  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4053  *str++ = ':';
4054  str = AppendTimestampSeconds(str, tm, fsec);
4055 
4056  /*
4057  * Note: the uses of %.*s in this function would be risky if the
4058  * timezone names ever contain non-ASCII characters. However, all
4059  * TZ abbreviations in the IANA database are plain ASCII.
4060  */
4061  if (print_tz)
4062  {
4063  if (tzn)
4064  {
4065  sprintf(str, " %.*s", MAXTZLEN, tzn);
4066  str += strlen(str);
4067  }
4068  else
4069  str = EncodeTimezone(str, tz, style);
4070  }
4071  break;
4072 
4073  case USE_GERMAN_DATES:
4074  /* German variant on European style */
4075  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4076  *str++ = '.';
4077  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4078  *str++ = '.';
4079  str = pg_ltostr_zeropad(str,
4080  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4081  *str++ = ' ';
4082  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4083  *str++ = ':';
4084  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4085  *str++ = ':';
4086  str = AppendTimestampSeconds(str, tm, fsec);
4087 
4088  if (print_tz)
4089  {
4090  if (tzn)
4091  {
4092  sprintf(str, " %.*s", MAXTZLEN, tzn);
4093  str += strlen(str);
4094  }
4095  else
4096  str = EncodeTimezone(str, tz, style);
4097  }
4098  break;
4099 
4100  case USE_POSTGRES_DATES:
4101  default:
4102  /* Backward-compatible with traditional Postgres abstime dates */
4103  day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4104  tm->tm_wday = j2day(day);
4105  memcpy(str, days[tm->tm_wday], 3);
4106  str += 3;
4107  *str++ = ' ';
4108  if (DateOrder == DATEORDER_DMY)
4109  {
4110  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4111  *str++ = ' ';
4112  memcpy(str, months[tm->tm_mon - 1], 3);
4113  str += 3;
4114  }
4115  else
4116  {
4117  memcpy(str, months[tm->tm_mon - 1], 3);
4118  str += 3;
4119  *str++ = ' ';
4120  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4121  }
4122  *str++ = ' ';
4123  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4124  *str++ = ':';
4125  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4126  *str++ = ':';
4127  str = AppendTimestampSeconds(str, tm, fsec);
4128  *str++ = ' ';
4129  str = pg_ltostr_zeropad(str,
4130  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4131 
4132  if (print_tz)
4133  {
4134  if (tzn)
4135  {
4136  sprintf(str, " %.*s", MAXTZLEN, tzn);
4137  str += strlen(str);
4138  }
4139  else
4140  {
4141  /*
4142  * We have a time zone, but no string version. Use the
4143  * numeric form, but be sure to include a leading space to
4144  * avoid formatting something which would be rejected by
4145  * the date/time parser later. - thomas 2001-10-19
4146  */
4147  *str++ = ' ';
4148  str = EncodeTimezone(str, tz, style);
4149  }
4150  }
4151  break;
4152  }
4153 
4154  if (tm->tm_year <= 0)
4155  {
4156  memcpy(str, " BC", 3); /* Don't copy NUL */
4157  str += 3;
4158  }
4159  *str = '\0';
4160 }
int tm_wday
Definition: pgtime.h:33
int tm_isdst
Definition: pgtime.h:35
int tm_hour
Definition: pgtime.h:29
static char * EncodeTimezone(char *str, int tz, int style)
Definition: datetime.c:3846
#define USE_SQL_DATES
Definition: miscadmin.h:211
#define MAXTZLEN
Definition: miscadmin.h:237
#define USE_ISO_DATES
Definition: miscadmin.h:210
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
const char *const months[]
Definition: datetime.c:66
int j2day(int date)
Definition: datetime.c:352
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define USE_POSTGRES_DATES
Definition: miscadmin.h:209
const char *const days[]
Definition: datetime.c:69
int DateOrder
Definition: globals.c:107
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
static char * AppendTimestampSeconds(char *cp, struct pg_tm *tm, fsec_t fsec)
Definition: datetime.c:474
#define DATEORDER_DMY
Definition: miscadmin.h:217
int date2j(int y, int m, int d)
Definition: datetime.c:292
#define Assert(condition)
Definition: c.h:675
#define USE_XSD_DATES
Definition: miscadmin.h:213
int tm_year
Definition: pgtime.h:32
#define USE_GERMAN_DATES
Definition: miscadmin.h:212
int tm_min
Definition: pgtime.h:28
void EncodeInterval ( struct pg_tm tm,
fsec_t  fsec,
int  style,
char *  str 
)

Definition at line 4241 of file datetime.c.

References AddISO8601IntPart(), AddPostgresIntPart(), AddVerboseIntPart(), AppendSeconds(), FALSE, INTSTYLE_ISO_8601, INTSTYLE_POSTGRES, INTSTYLE_POSTGRES_VERBOSE, INTSTYLE_SQL_STANDARD, MAX_INTERVAL_PRECISION, pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_year, and TRUE.

Referenced by interval_out(), and reltimeout().

4242 {
4243  char *cp = str;
4244  int year = tm->tm_year;
4245  int mon = tm->tm_mon;
4246  int mday = tm->tm_mday;
4247  int hour = tm->tm_hour;
4248  int min = tm->tm_min;
4249  int sec = tm->tm_sec;
4250  bool is_before = FALSE;
4251  bool is_zero = TRUE;
4252 
4253  /*
4254  * The sign of year and month are guaranteed to match, since they are
4255  * stored internally as "month". But we'll need to check for is_before and
4256  * is_zero when determining the signs of day and hour/minute/seconds
4257  * fields.
4258  */
4259  switch (style)
4260  {
4261  /* SQL Standard interval format */
4262  case INTSTYLE_SQL_STANDARD:
4263  {
4264  bool has_negative = year < 0 || mon < 0 ||
4265  mday < 0 || hour < 0 ||
4266  min < 0 || sec < 0 || fsec < 0;
4267  bool has_positive = year > 0 || mon > 0 ||
4268  mday > 0 || hour > 0 ||
4269  min > 0 || sec > 0 || fsec > 0;
4270  bool has_year_month = year != 0 || mon != 0;
4271  bool has_day_time = mday != 0 || hour != 0 ||
4272  min != 0 || sec != 0 || fsec != 0;
4273  bool has_day = mday != 0;
4274  bool sql_standard_value = !(has_negative && has_positive) &&
4275  !(has_year_month && has_day_time);
4276 
4277  /*
4278  * SQL Standard wants only 1 "<sign>" preceding the whole
4279  * interval ... but can't do that if mixed signs.
4280  */
4281  if (has_negative && sql_standard_value)
4282  {
4283  *cp++ = '-';
4284  year = -year;
4285  mon = -mon;
4286  mday = -mday;
4287  hour = -hour;
4288  min = -min;
4289  sec = -sec;
4290  fsec = -fsec;
4291  }
4292 
4293  if (!has_negative && !has_positive)
4294  {
4295  sprintf(cp, "0");
4296  }
4297  else if (!sql_standard_value)
4298  {
4299  /*
4300  * For non sql-standard interval values, force outputting
4301  * the signs to avoid ambiguities with intervals with
4302  * mixed sign components.
4303  */
4304  char year_sign = (year < 0 || mon < 0) ? '-' : '+';
4305  char day_sign = (mday < 0) ? '-' : '+';
4306  char sec_sign = (hour < 0 || min < 0 ||
4307  sec < 0 || fsec < 0) ? '-' : '+';
4308 
4309  sprintf(cp, "%c%d-%d %c%d %c%d:%02d:",
4310  year_sign, abs(year), abs(mon),
4311  day_sign, abs(mday),
4312  sec_sign, abs(hour), abs(min));
4313  cp += strlen(cp);
4314  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4315  *cp = '\0';
4316  }
4317  else if (has_year_month)
4318  {
4319  sprintf(cp, "%d-%d", year, mon);
4320  }
4321  else if (has_day)
4322  {
4323  sprintf(cp, "%d %d:%02d:", mday, hour, min);
4324  cp += strlen(cp);
4325  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4326  *cp = '\0';
4327  }
4328  else
4329  {
4330  sprintf(cp, "%d:%02d:", hour, min);
4331  cp += strlen(cp);
4332  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4333  *cp = '\0';
4334  }
4335  }
4336  break;
4337 
4338  /* ISO 8601 "time-intervals by duration only" */
4339  case INTSTYLE_ISO_8601:
4340  /* special-case zero to avoid printing nothing */
4341  if (year == 0 && mon == 0 && mday == 0 &&
4342  hour == 0 && min == 0 && sec == 0 && fsec == 0)
4343  {
4344  sprintf(cp, "PT0S");
4345  break;
4346  }
4347  *cp++ = 'P';
4348  cp = AddISO8601IntPart(cp, year, 'Y');
4349  cp = AddISO8601IntPart(cp, mon, 'M');
4350  cp = AddISO8601IntPart(cp, mday, 'D');
4351  if (hour != 0 || min != 0 || sec != 0 || fsec != 0)
4352  *cp++ = 'T';
4353  cp = AddISO8601IntPart(cp, hour, 'H');
4354  cp = AddISO8601IntPart(cp, min, 'M');
4355  if (sec != 0 || fsec != 0)
4356  {
4357  if (sec < 0 || fsec < 0)
4358  *cp++ = '-';
4359  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4360  *cp++ = 'S';
4361  *cp++ = '\0';
4362  }
4363  break;
4364 
4365  /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
4366  case INTSTYLE_POSTGRES:
4367  cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before);
4368 
4369  /*
4370  * Ideally we should spell out "month" like we do for "year" and
4371  * "day". However, for backward compatibility, we can't easily
4372  * fix this. bjm 2011-05-24
4373  */
4374  cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before);
4375  cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before);
4376  if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0)
4377  {
4378  bool minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
4379 
4380  sprintf(cp, "%s%s%02d:%02d:",
4381  is_zero ? "" : " ",
4382  (minus ? "-" : (is_before ? "+" : "")),
4383  abs(hour), abs(min));
4384  cp += strlen(cp);
4385  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4386  *cp = '\0';
4387  }
4388  break;
4389 
4390  /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
4392  default:
4393  strcpy(cp, "@");
4394  cp++;
4395  cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
4396  cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
4397  cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
4398  cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
4399  cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
4400  if (sec != 0 || fsec != 0)
4401  {
4402  *cp++ = ' ';
4403  if (sec < 0 || (sec == 0 && fsec < 0))
4404  {
4405  if (is_zero)
4406  is_before = TRUE;
4407  else if (!is_before)
4408  *cp++ = '-';
4409  }
4410  else if (is_before)
4411  *cp++ = '-';
4412  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4413  sprintf(cp, " sec%s",
4414  (abs(sec) != 1 || fsec != 0) ? "s" : "");
4415  is_zero = FALSE;
4416  }
4417  /* identically zero? then put in a unitless zero... */
4418  if (is_zero)
4419  strcat(cp, " 0");
4420  if (is_before)
4421  strcat(cp, " ago");
4422  break;
4423  }
4424 }
#define INTSTYLE_POSTGRES_VERBOSE
Definition: miscadmin.h:231
int tm_hour
Definition: pgtime.h:29
#define MAX_INTERVAL_PRECISION
Definition: timestamp.h:54
static char * AddISO8601IntPart(char *cp, int value, char units)
Definition: datetime.c:4169
#define FALSE
Definition: c.h:221
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
static char * AddPostgresIntPart(char *cp, int value, const char *units, bool *is_zero, bool *is_before)
Definition: datetime.c:4179
#define INTSTYLE_ISO_8601
Definition: miscadmin.h:233
static char * AddVerboseIntPart(char *cp, int value, const char *units, bool *is_zero, bool *is_before)
Definition: datetime.c:4202
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:411
#define INTSTYLE_SQL_STANDARD
Definition: miscadmin.h:232
int tm_year
Definition: pgtime.h:32
#define TRUE
Definition: c.h:217
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
#define INTSTYLE_POSTGRES
Definition: miscadmin.h:230
void EncodeTimeOnly ( struct pg_tm tm,
fsec_t  fsec,
bool  print_tz,
int  tz,
int  style,
char *  str 
)

Definition at line 3969 of file datetime.c.

References AppendSeconds(), EncodeTimezone(), MAX_TIME_PRECISION, pg_ltostr_zeropad(), pg_tm::tm_hour, pg_tm::tm_min, and pg_tm::tm_sec.

Referenced by time_out(), and timetz_out().

3970 {
3971  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
3972  *str++ = ':';
3973  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
3974  *str++ = ':';
3975  str = AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
3976  if (print_tz)
3977  str = EncodeTimezone(str, tz, style);
3978  *str = '\0';
3979 }
int tm_hour
Definition: pgtime.h:29
static char * EncodeTimezone(char *str, int tz, int style)
Definition: datetime.c:3846
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:411
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
#define MAX_TIME_PRECISION
Definition: date.h:50
static char* EncodeTimezone ( char *  str,
int  tz,
int  style 
)
static

Definition at line 3846 of file datetime.c.

References MINS_PER_HOUR, pg_ltostr_zeropad(), SECS_PER_MINUTE, and USE_XSD_DATES.

Referenced by EncodeDateTime(), and EncodeTimeOnly().

3847 {
3848  int hour,
3849  min,
3850  sec;
3851 
3852  sec = abs(tz);
3853  min = sec / SECS_PER_MINUTE;
3854  sec -= min * SECS_PER_MINUTE;
3855  hour = min / MINS_PER_HOUR;
3856  min -= hour * MINS_PER_HOUR;
3857 
3858  /* TZ is negated compared to sign we wish to display ... */
3859  *str++ = (tz <= 0 ? '+' : '-');
3860 
3861  if (sec != 0)
3862  {
3863  str = pg_ltostr_zeropad(str, hour, 2);
3864  *str++ = ':';
3865  str = pg_ltostr_zeropad(str, min, 2);
3866  *str++ = ':';
3867  str = pg_ltostr_zeropad(str, sec, 2);
3868  }
3869  else if (min != 0 || style == USE_XSD_DATES)
3870  {
3871  str = pg_ltostr_zeropad(str, hour, 2);
3872  *str++ = ':';
3873  str = pg_ltostr_zeropad(str, min, 2);
3874  }
3875  else
3876  str = pg_ltostr_zeropad(str, hour, 2);
3877  return str;
3878 }
#define MINS_PER_HOUR
Definition: timestamp.h:89
#define SECS_PER_MINUTE
Definition: timestamp.h:88
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
#define USE_XSD_DATES
Definition: miscadmin.h:213
static pg_tz * FetchDynamicTimeZone ( TimeZoneAbbrevTable tbl,
const datetkn tp 
)
static

Definition at line 4614 of file datetime.c.

References Assert, DYNTZ, ereport, errcode(), errdetail(), errmsg(), ERROR, NULL, pg_tzset(), TimeZoneAbbrevTable::tblsize, datetkn::token, datetkn::type, DynamicZoneAbbrev::tz, datetkn::value, and DynamicZoneAbbrev::zone.

Referenced by DecodeTimezoneAbbrev(), and pg_timezone_abbrevs().

4615 {
4616  DynamicZoneAbbrev *dtza;
4617 
4618  /* Just some sanity checks to prevent indexing off into nowhere */
4619  Assert(tp->type == DYNTZ);
4620  Assert(tp->value > 0 && tp->value < tbl->tblsize);
4621 
4622  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tp->value);
4623 
4624  /* Look up the underlying zone if we haven't already */
4625  if (dtza->tz == NULL)
4626  {
4627  dtza->tz = pg_tzset(dtza->zone);
4628 
4629  /*
4630  * Ideally we'd let the caller ereport instead of doing it here, but
4631  * then there is no way to report the bad time zone name.
4632  */
4633  if (dtza->tz == NULL)
4634  ereport(ERROR,
4635  (errcode(ERRCODE_CONFIG_FILE_ERROR),
4636  errmsg("time zone \"%s\" not recognized",
4637  dtza->zone),
4638  errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".",
4639  tp->token)));
4640  }
4641  return dtza->tz;
4642 }
int errcode(int sqlerrcode)
Definition: elog.c:575
int32 value
Definition: datetime.h:214
pg_tz * pg_tzset(const char *tzname)
Definition: pgtz.c:218
#define ERROR
Definition: elog.h:43
char token[TOKMAXLEN+1]
Definition: datetime.h:212
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
char zone[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:230
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define DYNTZ
Definition: datetime.h:98
void GetCurrentDateTime ( struct pg_tm tm)

Definition at line 370 of file datetime.c.

References GetCurrentTransactionStartTimestamp(), NULL, and timestamp2tm().

Referenced by date_in(), DecodeDateTime(), DecodeTimeOnly(), PGTYPESdate_today(), PGTYPEStimestamp_current(), and time_timetz().

371 {
372  int tz;
373  fsec_t fsec;
374 
376  NULL, NULL);
377  /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */
378 }
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1757
int32 fsec_t
Definition: timestamp.h:41
TimestampTz GetCurrentTransactionStartTimestamp(void)
Definition: xact.c:708
#define NULL
Definition: c.h:229
void GetCurrentTimeUsec ( struct pg_tm tm,
fsec_t fsec,
int *  tzp 
)

Definition at line 387 of file datetime.c.

References GetCurrentTransactionStartTimestamp(), NULL, and timestamp2tm().

Referenced by DecodeDateTime(), and DecodeTimeOnly().

388 {
389  int tz;
390 
392  NULL, NULL);
393  /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */
394  if (tzp != NULL)
395  *tzp = tz;
396 }
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1757
TimestampTz GetCurrentTransactionStartTimestamp(void)
Definition: xact.c:708
#define NULL
Definition: c.h:229
void InstallTimeZoneAbbrevs ( TimeZoneAbbrevTable tbl)

Definition at line 4603 of file datetime.c.

Referenced by assign_timezone_abbreviations().

4604 {
4605  zoneabbrevtbl = tbl;
4606  /* reset abbrevcache, which may contain pointers into old table */
4607  memset(abbrevcache, 0, sizeof(abbrevcache));
4608 }
static TimeZoneAbbrevTable * zoneabbrevtbl
Definition: datetime.c:243
static const datetkn * abbrevcache[MAXDATEFIELDS]
Definition: datetime.c:251
static int ISO8601IntegerWidth ( char *  fieldstart)
static

Definition at line 3494 of file datetime.c.

Referenced by DecodeISO8601Interval().

3495 {
3496  /* We might have had a leading '-' */
3497  if (*fieldstart == '-')
3498  fieldstart++;
3499  return strspn(fieldstart, "0123456789");
3500 }
void j2date ( int  jd,
int *  year,
int *  month,
int *  day 
)

Definition at line 317 of file datetime.c.

Referenced by date2timestamptz(), date_out(), datum_to_json(), datum_to_jsonb(), DecodeDateTime(), DecodeTimeOnly(), do_to_timestamp(), isoweek2date(), isoweekdate2date(), map_sql_value_to_xml_value(), PGTYPESdate_fmt_asc(), PGTYPESdate_julmdy(), PGTYPESdate_to_asc(), timestamp2tm(), timestamp_pl_interval(), timestamptz_pl_interval(), and ValidateDate().

318 {
319  unsigned int julian;
320  unsigned int quad;
321  unsigned int extra;
322  int y;
323 
324  julian = jd;
325  julian += 32044;
326  quad = julian / 146097;
327  extra = (julian - quad * 146097) * 4 + 3;
328  julian += 60 + quad * 3 + extra / 146097;
329  quad = julian / 1461;
330  julian -= quad * 1461;
331  y = julian * 4 / 1461;
332  julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
333  + 123;
334  y += quad * 4;
335  *year = y - 4800;
336  quad = julian * 2141 / 65536;
337  *day = julian - 7834 * quad / 256;
338  *month = (quad + 10) % MONTHS_PER_YEAR + 1;
339 
340  return;
341 } /* j2date() */
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
int j2day ( int  date)

Definition at line 352 of file datetime.c.

Referenced by date2isoweek(), date2isoyear(), EncodeDateTime(), isoweek2j(), timestamp_part(), and timestamptz_part().

353 {
354  date += 1;
355  date %= 7;
356  /* Cope if division truncates towards zero, as it probably does */
357  if (date < 0)
358  date += 7;
359 
360  return date;
361 } /* j2day() */
long date
Definition: pgtypes_date.h:8
int ParseDateTime ( const char *  timestr,
char *  workbuf,
size_t  buflen,
char **  field,
int *  ftype,
int  maxfields,
int *  numfields 
)

Definition at line 562 of file datetime.c.

References APPEND_CHAR, datebsearch(), DTERR_BAD_FORMAT, DTK_DATE, DTK_NUMBER, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TZ, NULL, pg_tolower(), and szdatetktbl.

Referenced by abstimein(), date_in(), interval_in(), pg_logdir_ls(), PGTYPESdate_from_asc(), PGTYPESinterval_from_asc(), PGTYPEStimestamp_from_asc(), reltimein(), time_in(), timestamp_in(), timestamptz_in(), and timetz_in().

564 {
565  int nf = 0;
566  const char *cp = timestr;
567  char *bufp = workbuf;
568  const char *bufend = workbuf + buflen;
569 
570  /*
571  * Set the character pointed-to by "bufptr" to "newchar", and increment
572  * "bufptr". "end" gives the end of the buffer -- we return an error if
573  * there is no space left to append a character to the buffer. Note that
574  * "bufptr" is evaluated twice.
575  */
576 #define APPEND_CHAR(bufptr, end, newchar) \
577  do \
578  { \
579  if (((bufptr) + 1) >= (end)) \
580  return DTERR_BAD_FORMAT; \
581  *(bufptr)++ = newchar; \
582  } while (0)
583 
584  /* outer loop through fields */
585  while (*cp != '\0')
586  {
587  /* Ignore spaces between fields */
588  if (isspace((unsigned char) *cp))
589  {
590  cp++;
591  continue;
592  }
593 
594  /* Record start of current field */
595  if (nf >= maxfields)
596  return DTERR_BAD_FORMAT;
597  field[nf] = bufp;
598 
599  /* leading digit? then date or time */
600  if (isdigit((unsigned char) *cp))
601  {
602  APPEND_CHAR(bufp, bufend, *cp++);
603  while (isdigit((unsigned char) *cp))
604  APPEND_CHAR(bufp, bufend, *cp++);
605 
606  /* time field? */
607  if (*cp == ':')
608  {
609  ftype[nf] = DTK_TIME;
610  APPEND_CHAR(bufp, bufend, *cp++);
611  while (isdigit((unsigned char) *cp) ||
612  (*cp == ':') || (*cp == '.'))
613  APPEND_CHAR(bufp, bufend, *cp++);
614  }
615  /* date field? allow embedded text month */
616  else if (*cp == '-' || *cp == '/' || *cp == '.')
617  {
618  /* save delimiting character to use later */
619  char delim = *cp;
620 
621  APPEND_CHAR(bufp, bufend, *cp++);
622  /* second field is all digits? then no embedded text month */
623  if (isdigit((unsigned char) *cp))
624  {
625  ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
626  while (isdigit((unsigned char) *cp))
627  APPEND_CHAR(bufp, bufend, *cp++);
628 
629  /*
630  * insist that the delimiters match to get a three-field
631  * date.
632  */
633  if (*cp == delim)
634  {
635  ftype[nf] = DTK_DATE;
636  APPEND_CHAR(bufp, bufend, *cp++);
637  while (isdigit((unsigned char) *cp) || *cp == delim)
638  APPEND_CHAR(bufp, bufend, *cp++);
639  }
640  }
641  else
642  {
643  ftype[nf] = DTK_DATE;
644  while (isalnum((unsigned char) *cp) || *cp == delim)
645  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
646  }
647  }
648 
649  /*
650  * otherwise, number only and will determine year, month, day, or
651  * concatenated fields later...
652  */
653  else
654  ftype[nf] = DTK_NUMBER;
655  }
656  /* Leading decimal point? Then fractional seconds... */
657  else if (*cp == '.')
658  {
659  APPEND_CHAR(bufp, bufend, *cp++);
660  while (isdigit((unsigned char) *cp))
661  APPEND_CHAR(bufp, bufend, *cp++);
662 
663  ftype[nf] = DTK_NUMBER;
664  }
665 
666  /*
667  * text? then date string, month, day of week, special, or timezone
668  */
669  else if (isalpha((unsigned char) *cp))
670  {
671  bool is_date;
672 
673  ftype[nf] = DTK_STRING;
674  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
675  while (isalpha((unsigned char) *cp))
676  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
677 
678  /*
679  * Dates can have embedded '-', '/', or '.' separators. It could
680  * also be a timezone name containing embedded '/', '+', '-', '_',
681  * or ':' (but '_' or ':' can't be the first punctuation). If the
682  * next character is a digit or '+', we need to check whether what
683  * we have so far is a recognized non-timezone keyword --- if so,
684  * don't believe that this is the start of a timezone.
685  */
686  is_date = false;
687  if (*cp == '-' || *cp == '/' || *cp == '.')
688  is_date = true;
689  else if (*cp == '+' || isdigit((unsigned char) *cp))
690  {
691  *bufp = '\0'; /* null-terminate current field value */
692  /* we need search only the core token table, not TZ names */
693  if (datebsearch(field[nf], datetktbl, szdatetktbl) == NULL)
694  is_date = true;
695  }
696  if (is_date)
697  {
698  ftype[nf] = DTK_DATE;
699  do
700  {
701  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
702  } while (*cp == '+' || *cp == '-' ||
703  *cp == '/' || *cp == '_' ||
704  *cp == '.' || *cp == ':' ||
705  isalnum((unsigned char) *cp));
706  }
707  }
708  /* sign? then special or numeric timezone */
709  else if (*cp == '+' || *cp == '-')
710  {
711  APPEND_CHAR(bufp, bufend, *cp++);
712  /* soak up leading whitespace */
713  while (isspace((unsigned char) *cp))
714  cp++;
715  /* numeric timezone? */
716  /* note that "DTK_TZ" could also be a signed float or yyyy-mm */
717  if (isdigit((unsigned char) *cp))
718  {
719  ftype[nf] = DTK_TZ;
720  APPEND_CHAR(bufp, bufend, *cp++);
721  while (isdigit((unsigned char) *cp) ||
722  *cp == ':' || *cp == '.' || *cp == '-')
723  APPEND_CHAR(bufp, bufend, *cp++);
724  }
725  /* special? */
726  else if (isalpha((unsigned char) *cp))
727  {
728  ftype[nf] = DTK_SPECIAL;
729  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
730  while (isalpha((unsigned char) *cp))
731  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
732  }
733  /* otherwise something wrong... */
734  else
735  return DTERR_BAD_FORMAT;
736  }
737  /* ignore other punctuation but use as delimiter */
738  else if (ispunct((unsigned char) *cp))
739  {
740  cp++;
741  continue;
742  }
743  /* otherwise, something is not right... */
744  else
745  return DTERR_BAD_FORMAT;
746 
747  /* force in a delimiter after each field */
748  *bufp++ = '\0';
749  nf++;
750  }
751 
752  *numfields = nf;
753 
754  return 0;
755 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define APPEND_CHAR(bufptr, end, newchar)
static const datetkn datetktbl[]
Definition: datetime.c:90
unsigned char pg_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:122
static int szdatetktbl
Definition: datetime.c:168
#define DTK_TZ
Definition: datetime.h:147
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:3810
#define DTK_NUMBER
Definition: datetime.h:142
#define DTK_TIME
Definition: datetime.h:146
#define NULL
Definition: c.h:229
#define DTK_STRING
Definition: datetime.h:143
#define DTK_DATE
Definition: datetime.h:145
#define DTK_SPECIAL
Definition: datetime.h:150
static int ParseFractionalSecond ( char *  cp,
fsec_t fsec 
)
static

Definition at line 514 of file datetime.c.

References Assert, DTERR_BAD_FORMAT, and rint().

Referenced by DecodeDateTime(), DecodeNumber(), DecodeTime(), and DecodeTimeOnly().

515 {
516  double frac;
517 
518  /* Caller