PostgreSQL Source Code  git master
datetime.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "common/int.h"
#include "common/string.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/scansup.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/guc.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 *str, 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 DecodeTimeCommon (char *str, int fmask, int range, int *tmask, struct pg_itm *itm)
 
static int DecodeTime (char *str, int fmask, int range, int *tmask, struct pg_tm *tm, fsec_t *fsec)
 
static int DecodeTimeForInterval (char *str, int fmask, int range, int *tmask, struct pg_itm_in *itm_in)
 
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 bool int64_multiply_add (int64 val, int64 multiplier, int64 *sum)
 
static bool AdjustFractMicroseconds (double frac, int64 scale, struct pg_itm_in *itm_in)
 
static bool AdjustFractDays (double frac, int scale, struct pg_itm_in *itm_in)
 
static bool AdjustFractYears (double frac, int scale, struct pg_itm_in *itm_in)
 
static bool AdjustMicroseconds (int64 val, double fval, int64 scale, struct pg_itm_in *itm_in)
 
static bool AdjustDays (int64 val, int scale, struct pg_itm_in *itm_in)
 
static bool AdjustMonths (int64 val, struct pg_itm_in *itm_in)
 
static bool AdjustYears (int64 val, int scale, struct pg_itm_in *itm_in)
 
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, DateTimeErrorExtra *extra)
 
int date2j (int year, int month, int day)
 
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 ParseFraction (char *cp, double *frac)
 
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, DateTimeErrorExtra *extra)
 
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, DateTimeErrorExtra *extra)
 
int ValidateDate (int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
 
int DecodeTimezone (const char *str, int *tzp)
 
int DecodeTimezoneAbbrev (int field, const char *lowtoken, int *ftype, int *offset, pg_tz **tz, DateTimeErrorExtra *extra)
 
int DecodeSpecial (int field, const char *lowtoken, int *val)
 
int DecodeTimezoneName (const char *tzname, int *offset, pg_tz **tz)
 
pg_tzDecodeTimezoneNameToTz (const char *tzname)
 
static void ClearPgItmIn (struct pg_itm_in *itm_in)
 
int DecodeInterval (char **field, int *ftype, int nf, int range, int *dtype, struct pg_itm_in *itm_in)
 
static int ParseISO8601Number (char *str, char **endptr, int64 *ipart, double *fpart)
 
static int ISO8601IntegerWidth (char *fieldstart)
 
int DecodeISO8601Interval (char *str, int *dtype, struct pg_itm_in *itm_in)
 
int DecodeUnits (int field, const char *lowtoken, int *val)
 
void DateTimeParseError (int dterr, DateTimeErrorExtra *extra, const char *str, const char *datatype, Node *escontext)
 
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, int64 value, char units)
 
static char * AddPostgresIntPart (char *cp, int64 value, const char *units, bool *is_zero, bool *is_before)
 
static char * AddVerboseIntPart (char *cp, int64 value, const char *units, bool *is_zero, bool *is_before)
 
void EncodeInterval (struct pg_itm *itm, int style, char *str)
 
static bool CheckDateTokenTable (const char *tablename, const datetkn *base, int nel)
 
bool CheckDateTokenTables (void)
 
NodeTemporalSimplify (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 const int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0]
 
static const datetkn deltatktbl []
 
static const 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

◆ APPEND_CHAR

#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

Function Documentation

◆ AddISO8601IntPart()

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

Definition at line 4402 of file datetime.c.

4403 {
4404  if (value == 0)
4405  return cp;
4406  sprintf(cp, "%lld%c", (long long) value, units);
4407  return cp + strlen(cp);
4408 }
static struct @148 value
#define sprintf
Definition: port.h:240

References sprintf, and value.

Referenced by EncodeInterval().

◆ AddPostgresIntPart()

static char* AddPostgresIntPart ( char *  cp,
int64  value,
const char *  units,
bool is_zero,
bool is_before 
)
static

Definition at line 4412 of file datetime.c.

4414 {
4415  if (value == 0)
4416  return cp;
4417  sprintf(cp, "%s%s%lld %s%s",
4418  (!*is_zero) ? " " : "",
4419  (*is_before && value > 0) ? "+" : "",
4420  (long long) value,
4421  units,
4422  (value != 1) ? "s" : "");
4423 
4424  /*
4425  * Each nonzero field sets is_before for (only) the next one. This is a
4426  * tad bizarre but it's how it worked before...
4427  */
4428  *is_before = (value < 0);
4429  *is_zero = false;
4430  return cp + strlen(cp);
4431 }

References sprintf, and value.

Referenced by EncodeInterval().

◆ AddVerboseIntPart()

static char* AddVerboseIntPart ( char *  cp,
int64  value,
const char *  units,
bool is_zero,
bool is_before 
)
static

Definition at line 4435 of file datetime.c.

4437 {
4438  if (value == 0)
4439  return cp;
4440  /* first nonzero value sets is_before */
4441  if (*is_zero)
4442  {
4443  *is_before = (value < 0);
4444  value = i64abs(value);
4445  }
4446  else if (*is_before)
4447  value = -value;
4448  sprintf(cp, " %lld %s%s", (long long) value, units, (value == 1) ? "" : "s");
4449  *is_zero = false;
4450  return cp + strlen(cp);
4451 }
#define i64abs(i)
Definition: c.h:1317

References i64abs, sprintf, and value.

Referenced by EncodeInterval().

◆ AdjustDays()

static bool AdjustDays ( int64  val,
int  scale,
struct pg_itm_in itm_in 
)
static

Definition at line 635 of file datetime.c.

636 {
637  int days;
638 
639  if (val < INT_MIN || val > INT_MAX)
640  return false;
641  return !pg_mul_s32_overflow((int32) val, scale, &days) &&
642  !pg_add_s32_overflow(itm_in->tm_mday, days, &itm_in->tm_mday);
643 }
const char *const days[]
Definition: datetime.c:86
signed int int32
Definition: c.h:483
long val
Definition: informix.c:664
static bool pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:140
static bool pg_add_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:104
int scale
Definition: pgbench.c:181
int tm_mday
Definition: timestamp.h:85

References days, pg_add_s32_overflow(), pg_mul_s32_overflow(), scale, pg_itm_in::tm_mday, and val.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

◆ AdjustFractDays()

static bool AdjustFractDays ( double  frac,
int  scale,
struct pg_itm_in itm_in 
)
static

Definition at line 571 of file datetime.c.

573 {
574  int extra_days;
575 
576  /* Fast path for common case */
577  if (frac == 0)
578  return true;
579 
580  /*
581  * We assume the input frac has abs value less than 1, so overflow of frac
582  * or extra_days is not an issue.
583  */
584  frac *= scale;
585  extra_days = (int) frac;
586 
587  /* ... but this could overflow, if tm_mday is already nonzero */
588  if (pg_add_s32_overflow(itm_in->tm_mday, extra_days, &itm_in->tm_mday))
589  return false;
590 
591  /* Handle any fractional day */
592  frac -= extra_days;
593  return AdjustFractMicroseconds(frac, USECS_PER_DAY, itm_in);
594 }
static bool AdjustFractMicroseconds(double frac, int64 scale, struct pg_itm_in *itm_in)
Definition: datetime.c:539
#define USECS_PER_DAY
Definition: timestamp.h:130

References AdjustFractMicroseconds(), pg_add_s32_overflow(), scale, pg_itm_in::tm_mday, and USECS_PER_DAY.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

◆ AdjustFractMicroseconds()

static bool AdjustFractMicroseconds ( double  frac,
int64  scale,
struct pg_itm_in itm_in 
)
static

Definition at line 539 of file datetime.c.

541 {
542  int64 usec;
543 
544  /* Fast path for common case */
545  if (frac == 0)
546  return true;
547 
548  /*
549  * We assume the input frac has abs value less than 1, so overflow of frac
550  * or usec is not an issue for interesting values of scale.
551  */
552  frac *= scale;
553  usec = (int64) frac;
554 
555  /* Round off any fractional microsecond */
556  frac -= usec;
557  if (frac > 0.5)
558  usec++;
559  else if (frac < -0.5)
560  usec--;
561 
562  return !pg_add_s64_overflow(itm_in->tm_usec, usec, &itm_in->tm_usec);
563 }
static bool pg_add_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:161
int64 tm_usec
Definition: timestamp.h:84

References pg_add_s64_overflow(), scale, and pg_itm_in::tm_usec.

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

◆ AdjustFractYears()

static bool AdjustFractYears ( double  frac,
int  scale,
struct pg_itm_in itm_in 
)
static

Definition at line 603 of file datetime.c.

605 {
606  /*
607  * As above, we assume abs(frac) < 1, so this can't overflow for any
608  * interesting value of scale.
609  */
610  int extra_months = (int) rint(frac * scale * MONTHS_PER_YEAR);
611 
612  return !pg_add_s32_overflow(itm_in->tm_mon, extra_months, &itm_in->tm_mon);
613 }
#define MONTHS_PER_YEAR
Definition: timestamp.h:108
int tm_mon
Definition: timestamp.h:86

References MONTHS_PER_YEAR, pg_add_s32_overflow(), scale, and pg_itm_in::tm_mon.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

◆ AdjustMicroseconds()

static bool AdjustMicroseconds ( int64  val,
double  fval,
int64  scale,
struct pg_itm_in itm_in 
)
static

Definition at line 620 of file datetime.c.

622 {
623  /* Handle the integer part */
624  if (!int64_multiply_add(val, scale, &itm_in->tm_usec))
625  return false;
626  /* Handle the float part */
627  return AdjustFractMicroseconds(fval, scale, itm_in);
628 }
static bool int64_multiply_add(int64 val, int64 multiplier, int64 *sum)
Definition: datetime.c:524

References AdjustFractMicroseconds(), int64_multiply_add(), scale, pg_itm_in::tm_usec, and val.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

◆ AdjustMonths()

static bool AdjustMonths ( int64  val,
struct pg_itm_in itm_in 
)
static

Definition at line 651 of file datetime.c.

652 {
653  if (val < INT_MIN || val > INT_MAX)
654  return false;
655  return !pg_add_s32_overflow(itm_in->tm_mon, (int32) val, &itm_in->tm_mon);
656 }

References pg_add_s32_overflow(), pg_itm_in::tm_mon, and val.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

◆ AdjustYears()

static bool AdjustYears ( int64  val,
int  scale,
struct pg_itm_in itm_in 
)
static

Definition at line 663 of file datetime.c.

665 {
666  int years;
667 
668  if (val < INT_MIN || val > INT_MAX)
669  return false;
670  return !pg_mul_s32_overflow((int32) val, scale, &years) &&
671  !pg_add_s32_overflow(itm_in->tm_year, years, &itm_in->tm_year);
672 }
int tm_year
Definition: timestamp.h:87

References pg_add_s32_overflow(), pg_mul_s32_overflow(), scale, pg_itm_in::tm_year, and val.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

◆ AppendSeconds()

static char * AppendSeconds ( char *  cp,
int  sec,
fsec_t  fsec,
int  precision,
bool  fillzeros 
)
static

Definition at line 450 of file datetime.c.

451 {
452  Assert(precision >= 0);
453 
454  if (fillzeros)
455  cp = pg_ultostr_zeropad(cp, abs(sec), 2);
456  else
457  cp = pg_ultostr(cp, abs(sec));
458 
459  /* fsec_t is just an int32 */
460  if (fsec != 0)
461  {
462  int32 value = abs(fsec);
463  char *end = &cp[precision + 1];
464  bool gotnonzero = false;
465 
466  *cp++ = '.';
467 
468  /*
469  * Append the fractional seconds part. Note that we don't want any
470  * trailing zeros here, so since we're building the number in reverse
471  * we'll skip appending zeros until we've output a non-zero digit.
472  */
473  while (precision--)
474  {
475  int32 oldval = value;
476  int32 remainder;
477 
478  value /= 10;
479  remainder = oldval - value * 10;
480 
481  /* check if we got a non-zero */
482  if (remainder)
483  gotnonzero = true;
484 
485  if (gotnonzero)
486  cp[precision] = '0' + remainder;
487  else
488  end = &cp[precision];
489  }
490 
491  /*
492  * If we still have a non-zero value then precision must have not been
493  * enough to print the number. We punt the problem to pg_ultostr(),
494  * which will generate a correct answer in the minimum valid width.
495  */
496  if (value)
497  return pg_ultostr(cp, abs(fsec));
498 
499  return end;
500  }
501  else
502  return cp;
503 }
Assert(fmt[strlen(fmt) - 1] !='\n')
char * pg_ultostr(char *str, uint32 value)
Definition: numutils.c:1310
char * pg_ultostr_zeropad(char *str, uint32 value, int32 minwidth)
Definition: numutils.c:1270

References Assert(), pg_ultostr(), pg_ultostr_zeropad(), and value.

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

◆ AppendTimestampSeconds()

static char* AppendTimestampSeconds ( char *  cp,
struct pg_tm tm,
fsec_t  fsec 
)
static

Definition at line 513 of file datetime.c.

514 {
515  return AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
516 }
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:450
#define MAX_TIMESTAMP_PRECISION
Definition: timestamp.h:92
static struct pg_tm tm
Definition: localtime.c:104
int tm_sec
Definition: pgtime.h:36

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

Referenced by EncodeDateTime().

◆ CheckDateTokenTable()

static bool CheckDateTokenTable ( const char *  tablename,
const datetkn base,
int  nel 
)
static

Definition at line 4668 of file datetime.c.

4669 {
4670  bool ok = true;
4671  int i;
4672 
4673  for (i = 0; i < nel; i++)
4674  {
4675  /* check for token strings that don't fit */
4676  if (strlen(base[i].token) > TOKMAXLEN)
4677  {
4678  /* %.*s is safe since all our tokens are ASCII */
4679  elog(LOG, "token too long in %s table: \"%.*s\"",
4680  tablename,
4681  TOKMAXLEN + 1, base[i].token);
4682  ok = false;
4683  break; /* don't risk applying strcmp */
4684  }
4685  /* check for out of order */
4686  if (i > 0 &&
4687  strcmp(base[i - 1].token, base[i].token) >= 0)
4688  {
4689  elog(LOG, "ordering error in %s table: \"%s\" >= \"%s\"",
4690  tablename,
4691  base[i - 1].token,
4692  base[i].token);
4693  ok = false;
4694  }
4695  }
4696  return ok;
4697 }
#define LOG
Definition: elog.h:31
#define TOKMAXLEN
Definition: datetime.h:204
#define token
Definition: indent_globs.h:126
int i
Definition: isn.c:73

References elog(), i, LOG, token, and TOKMAXLEN.

Referenced by CheckDateTokenTables(), and ConvertTimeZoneAbbrevs().

◆ CheckDateTokenTables()

bool CheckDateTokenTables ( void  )

Definition at line 4700 of file datetime.c.

4701 {
4702  bool ok = true;
4703 
4704  Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1));
4705  Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1));
4706 
4707  ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
4708  ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
4709  return ok;
4710 }
static bool CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
Definition: datetime.c:4668
static const datetkn datetktbl[]
Definition: datetime.c:107
static const int szdeltatktbl
Definition: datetime.c:254
static const int szdatetktbl
Definition: datetime.c:183
int date2j(int year, int month, int day)
Definition: datetime.c:288
static const datetkn deltatktbl[]
Definition: datetime.c:189
#define UNIX_EPOCH_JDATE
Definition: timestamp.h:208
#define POSTGRES_EPOCH_JDATE
Definition: timestamp.h:209

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

Referenced by PostmasterMain().

◆ ClearPgItmIn()

static void ClearPgItmIn ( struct pg_itm_in itm_in)
inlinestatic

Definition at line 3255 of file datetime.c.

3256 {
3257  itm_in->tm_usec = 0;
3258  itm_in->tm_mday = 0;
3259  itm_in->tm_mon = 0;
3260  itm_in->tm_year = 0;
3261 }

References pg_itm_in::tm_mday, pg_itm_in::tm_mon, pg_itm_in::tm_usec, and pg_itm_in::tm_year.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

◆ ConvertTimeZoneAbbrevs()

TimeZoneAbbrevTable* ConvertTimeZoneAbbrevs ( struct tzEntry abbrevs,
int  n 
)

Definition at line 4762 of file datetime.c.

4763 {
4764  TimeZoneAbbrevTable *tbl;
4765  Size tbl_size;
4766  int i;
4767 
4768  /* Space for fixed fields and datetkn array */
4769  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4770  n * sizeof(datetkn);
4771  tbl_size = MAXALIGN(tbl_size);
4772  /* Count up space for dynamic abbreviations */
4773  for (i = 0; i < n; i++)
4774  {
4775  struct tzEntry *abbr = abbrevs + i;
4776 
4777  if (abbr->zone != NULL)
4778  {
4779  Size dsize;
4780 
4781  dsize = offsetof(DynamicZoneAbbrev, zone) +
4782  strlen(abbr->zone) + 1;
4783  tbl_size += MAXALIGN(dsize);
4784  }
4785  }
4786 
4787  /* Alloc the result ... */
4788  tbl = guc_malloc(LOG, tbl_size);
4789  if (!tbl)
4790  return NULL;
4791 
4792  /* ... and fill it in */
4793  tbl->tblsize = tbl_size;
4794  tbl->numabbrevs = n;
4795  /* in this loop, tbl_size reprises the space calculation above */
4796  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4797  n * sizeof(datetkn);
4798  tbl_size = MAXALIGN(tbl_size);
4799  for (i = 0; i < n; i++)
4800  {
4801  struct tzEntry *abbr = abbrevs + i;
4802  datetkn *dtoken = tbl->abbrevs + i;
4803 
4804  /* use strlcpy to truncate name if necessary */
4805  strlcpy(dtoken->token, abbr->abbrev, TOKMAXLEN + 1);
4806  if (abbr->zone != NULL)
4807  {
4808  /* Allocate a DynamicZoneAbbrev for this abbreviation */
4809  DynamicZoneAbbrev *dtza;
4810  Size dsize;
4811 
4812  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tbl_size);
4813  dtza->tz = NULL;
4814  strcpy(dtza->zone, abbr->zone);
4815 
4816  dtoken->type = DYNTZ;
4817  /* value is offset from table start to DynamicZoneAbbrev */
4818  dtoken->value = (int32) tbl_size;
4819 
4820  dsize = offsetof(DynamicZoneAbbrev, zone) +
4821  strlen(abbr->zone) + 1;
4822  tbl_size += MAXALIGN(dsize);
4823  }
4824  else
4825  {
4826  dtoken->type = abbr->is_dst ? DTZ : TZ;
4827  dtoken->value = abbr->offset;
4828  }
4829  }
4830 
4831  /* Assert the two loops above agreed on size calculations */
4832  Assert(tbl->tblsize == tbl_size);
4833 
4834  /* Check the ordering, if testing */
4835  Assert(CheckDateTokenTable("timezone abbreviations", tbl->abbrevs, n));
4836 
4837  return tbl;
4838 }
#define MAXALIGN(LEN)
Definition: c.h:800
size_t Size
Definition: c.h:594
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:631
#define TZ
Definition: datetime.h:95
#define DTZ
Definition: datetime.h:96
#define DYNTZ
Definition: datetime.h:97
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char zone[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:227
datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:219
char token[TOKMAXLEN+1]
Definition: datetime.h:209
int32 value
Definition: datetime.h:211
char type
Definition: datetime.h:210
char * zone
Definition: tzparser.h:27
int offset
Definition: tzparser.h:29
char * abbrev
Definition: tzparser.h:26
bool is_dst
Definition: tzparser.h:30
Definition: zic.c:94

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

Referenced by load_tzoffsets().

◆ date2j()

int date2j ( int  year,
int  month,
int  day 
)

Definition at line 288 of file datetime.c.

289 {
290  int julian;
291  int century;
292 
293  if (month > 2)
294  {
295  month += 1;
296  year += 4800;
297  }
298  else
299  {
300  month += 13;
301  year += 4799;
302  }
303 
304  century = year / 100;
305  julian = year * 365 - 32167;
306  julian += year / 4 - century + century / 4;
307  julian += 7834 * month / 256 + day;
308 
309  return julian;
310 } /* date2j() */

Referenced by CheckDateTokenTables(), date2isoweek(), date2isoyear(), date2isoyearday(), date_in(), DCH_to_char(), DecodeDateTime(), DetermineTimeZoneOffsetInternal(), EncodeDateTime(), extract_date(), GetSQLCurrentDate(), isoweek2j(), make_date(), make_timestamp_internal(), parse_datetime(), 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_common(), timestamp_pl_interval(), timestamp_to_char(), timestamptz_date(), timestamptz_part_common(), timestamptz_pl_interval_internal(), timestamptz_to_char(), tm2timestamp(), to_date(), and ValidateDate().

◆ datebsearch()

static const datetkn * datebsearch ( const char *  key,
const datetkn base,
int  nel 
)
static

Definition at line 4042 of file datetime.c.

4043 {
4044  if (nel > 0)
4045  {
4046  const datetkn *last = base + nel - 1,
4047  *position;
4048  int result;
4049 
4050  while (last >= base)
4051  {
4052  position = base + ((last - base) >> 1);
4053  /* precheck the first character for a bit of extra speed */
4054  result = (int) key[0] - (int) position->token[0];
4055  if (result == 0)
4056  {
4057  /* use strncmp so that we match truncated tokens */
4058  result = strncmp(key, position->token, TOKMAXLEN);
4059  if (result == 0)
4060  return position;
4061  }
4062  if (result < 0)
4063  last = position - 1;
4064  else
4065  base = position + 1;
4066  }
4067  }
4068  return NULL;
4069 }

References sort-test::key, and TOKMAXLEN.

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

◆ DateTimeParseError()

void DateTimeParseError ( int  dterr,
DateTimeErrorExtra extra,
const char *  str,
const char *  datatype,
Node escontext 
)

Definition at line 3981 of file datetime.c.

3984 {
3985  switch (dterr)
3986  {
3987  case DTERR_FIELD_OVERFLOW:
3988  errsave(escontext,
3989  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3990  errmsg("date/time field value out of range: \"%s\"",
3991  str)));
3992  break;
3994  /* <nanny>same as above, but add hint about DateStyle</nanny> */
3995  errsave(escontext,
3996  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3997  errmsg("date/time field value out of range: \"%s\"",
3998  str),
3999  errhint("Perhaps you need a different \"datestyle\" setting.")));
4000  break;
4002  errsave(escontext,
4003  (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
4004  errmsg("interval field value out of range: \"%s\"",
4005  str)));
4006  break;
4007  case DTERR_TZDISP_OVERFLOW:
4008  errsave(escontext,
4009  (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
4010  errmsg("time zone displacement out of range: \"%s\"",
4011  str)));
4012  break;
4013  case DTERR_BAD_TIMEZONE:
4014  errsave(escontext,
4015  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4016  errmsg("time zone \"%s\" not recognized",
4017  extra->dtee_timezone)));
4018  break;
4019  case DTERR_BAD_ZONE_ABBREV:
4020  errsave(escontext,
4021  (errcode(ERRCODE_CONFIG_FILE_ERROR),
4022  errmsg("time zone \"%s\" not recognized",
4023  extra->dtee_timezone),
4024  errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".",
4025  extra->dtee_abbrev)));
4026  break;
4027  case DTERR_BAD_FORMAT:
4028  default:
4029  errsave(escontext,
4030  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4031  errmsg("invalid input syntax for type %s: \"%s\"",
4032  datatype, str)));
4033  break;
4034  }
4035 }
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define errsave(context,...)
Definition: elog.h:260
#define DTERR_BAD_ZONE_ABBREV
Definition: datetime.h:288
#define DTERR_INTERVAL_OVERFLOW
Definition: datetime.h:285
#define DTERR_BAD_TIMEZONE
Definition: datetime.h:287
#define DTERR_TZDISP_OVERFLOW
Definition: datetime.h:286
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
#define DTERR_MD_FIELD_OVERFLOW
Definition: datetime.h:284
const char * dtee_timezone
Definition: datetime.h:293
const char * dtee_abbrev
Definition: datetime.h:295

References DateTimeErrorExtra::dtee_abbrev, DateTimeErrorExtra::dtee_timezone, DTERR_BAD_FORMAT, DTERR_BAD_TIMEZONE, DTERR_BAD_ZONE_ABBREV, DTERR_FIELD_OVERFLOW, DTERR_INTERVAL_OVERFLOW, DTERR_MD_FIELD_OVERFLOW, DTERR_TZDISP_OVERFLOW, errcode(), errdetail(), errhint(), errmsg(), errsave, and generate_unaccent_rules::str.

Referenced by date_in(), DecodeTimezoneName(), do_to_timestamp(), interval_in(), parse_datetime(), pg_timezone_abbrevs(), time_in(), timestamp_in(), timestamptz_in(), timetz_in(), and to_timestamp().

◆ DecodeDate()

static int DecodeDate ( char *  str,
int  fmask,
int *  tmask,
bool is2digits,
struct pg_tm tm 
)
static

Definition at line 2389 of file datetime.c.

2391 {
2392  fsec_t fsec;
2393  int nf = 0;
2394  int i,
2395  len;
2396  int dterr;
2397  bool haveTextMonth = false;
2398  int type,
2399  val,
2400  dmask = 0;
2401  char *field[MAXDATEFIELDS];
2402 
2403  *tmask = 0;
2404 
2405  /* parse this string... */
2406  while (*str != '\0' && nf < MAXDATEFIELDS)
2407  {
2408  /* skip field separators */
2409  while (*str != '\0' && !isalnum((unsigned char) *str))
2410  str++;
2411 
2412  if (*str == '\0')
2413  return DTERR_BAD_FORMAT; /* end of string after separator */
2414 
2415  field[nf] = str;
2416  if (isdigit((unsigned char) *str))
2417  {
2418  while (isdigit((unsigned char) *str))
2419  str++;
2420  }
2421  else if (isalpha((unsigned char) *str))
2422  {
2423  while (isalpha((unsigned char) *str))
2424  str++;
2425  }
2426 
2427  /* Just get rid of any non-digit, non-alpha characters... */
2428  if (*str != '\0')
2429  *str++ = '\0';
2430  nf++;
2431  }
2432 
2433  /* look first for text fields, since that will be unambiguous month */
2434  for (i = 0; i < nf; i++)
2435  {
2436  if (isalpha((unsigned char) *field[i]))
2437  {
2438  type = DecodeSpecial(i, field[i], &val);
2439  if (type == IGNORE_DTF)
2440  continue;
2441 
2442  dmask = DTK_M(type);
2443  switch (type)
2444  {
2445  case MONTH:
2446  tm->tm_mon = val;
2447  haveTextMonth = true;
2448  break;
2449 
2450  default:
2451  return DTERR_BAD_FORMAT;
2452  }
2453  if (fmask & dmask)
2454  return DTERR_BAD_FORMAT;
2455 
2456  fmask |= dmask;
2457  *tmask |= dmask;
2458 
2459  /* mark this field as being completed */
2460  field[i] = NULL;
2461  }
2462  }
2463 
2464  /* now pick up remaining numeric fields */
2465  for (i = 0; i < nf; i++)
2466  {
2467  if (field[i] == NULL)
2468  continue;
2469 
2470  if ((len = strlen(field[i])) <= 0)
2471  return DTERR_BAD_FORMAT;
2472 
2473  dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,
2474  &dmask, tm,
2475  &fsec, is2digits);
2476  if (dterr)
2477  return dterr;
2478 
2479  if (fmask & dmask)
2480  return DTERR_BAD_FORMAT;
2481 
2482  fmask |= dmask;
2483  *tmask |= dmask;
2484  }
2485 
2486  if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
2487  return DTERR_BAD_FORMAT;
2488 
2489  /* validation of the field values must wait until ValidateDate() */
2490 
2491  return 0;
2492 }
static int DecodeNumber(int flen, char *str, bool haveTextMonth, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2718
int DecodeSpecial(int field, const char *lowtoken, int *val)
Definition: datetime.c:3139
int32 fsec_t
Definition: timestamp.h:41
#define MAXDATEFIELDS
Definition: datetime.h:202
#define MONTH
Definition: datetime.h:91
#define IGNORE_DTF
Definition: datetime.h:98
#define DTK_M(t)
Definition: datetime.h:187
#define DTK_DATE_M
Definition: datetime.h:191
#define DOY
Definition: datetime.h:105
const void size_t len
int tm_mon
Definition: pgtime.h:40
const char * type

References DecodeNumber(), DecodeSpecial(), DOY, DTERR_BAD_FORMAT, DTK_DATE_M, DTK_M, i, IGNORE_DTF, len, MAXDATEFIELDS, MONTH, generate_unaccent_rules::str, tm, pg_tm::tm_mon, type, TZ, and val.

Referenced by DecodeDateTime(), and DecodeTimeOnly().

◆ DecodeDateTime()

int DecodeDateTime ( char **  field,
int *  ftype,
int  nf,
int *  dtype,
struct pg_tm tm,
fsec_t fsec,
int *  tzp,
DateTimeErrorExtra extra 
)

Definition at line 980 of file datetime.c.

983 {
984  int fmask = 0,
985  tmask,
986  type;
987  int ptype = 0; /* "prefix type" for ISO and Julian formats */
988  int i;
989  int val;
990  int dterr;
991  int mer = HR24;
992  bool haveTextMonth = false;
993  bool isjulian = false;
994  bool is2digits = false;
995  bool bc = false;
996  pg_tz *namedTz = NULL;
997  pg_tz *abbrevTz = NULL;
998  pg_tz *valtz;
999  char *abbrev = NULL;
1000  struct pg_tm cur_tm;
1001 
1002  /*
1003  * We'll insist on at least all of the date fields, but initialize the
1004  * remaining fields in case they are not set later...
1005  */
1006  *dtype = DTK_DATE;
1007  tm->tm_hour = 0;
1008  tm->tm_min = 0;
1009  tm->tm_sec = 0;
1010  *fsec = 0;
1011  /* don't know daylight savings time status apriori */
1012  tm->tm_isdst = -1;
1013  if (tzp != NULL)
1014  *tzp = 0;
1015 
1016  for (i = 0; i < nf; i++)
1017  {
1018  switch (ftype[i])
1019  {
1020  case DTK_DATE:
1021 
1022  /*
1023  * Integral julian day with attached time zone? All other
1024  * forms with JD will be separated into distinct fields, so we
1025  * handle just this case here.
1026  */
1027  if (ptype == DTK_JULIAN)
1028  {
1029  char *cp;
1030  int jday;
1031 
1032  if (tzp == NULL)
1033  return DTERR_BAD_FORMAT;
1034 
1035  errno = 0;
1036  jday = strtoint(field[i], &cp, 10);
1037  if (errno == ERANGE || jday < 0)
1038  return DTERR_FIELD_OVERFLOW;
1039 
1040  j2date(jday, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1041  isjulian = true;
1042 
1043  /* Get the time zone from the end of the string */
1044  dterr = DecodeTimezone(cp, tzp);
1045  if (dterr)
1046  return dterr;
1047 
1048  tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
1049  ptype = 0;
1050  break;
1051  }
1052 
1053  /*
1054  * Already have a date? Then this might be a time zone name
1055  * with embedded punctuation (e.g. "America/New_York") or a
1056  * run-together time with trailing time zone (e.g. hhmmss-zz).
1057  * - thomas 2001-12-25
1058  *
1059  * We consider it a time zone if we already have month & day.
1060  * This is to allow the form "mmm dd hhmmss tz year", which
1061  * we've historically accepted.
1062  */
1063  else if (ptype != 0 ||
1064  ((fmask & (DTK_M(MONTH) | DTK_M(DAY))) ==
1065  (DTK_M(MONTH) | DTK_M(DAY))))
1066  {
1067  /* No time zone accepted? Then quit... */
1068  if (tzp == NULL)
1069  return DTERR_BAD_FORMAT;
1070 
1071  if (isdigit((unsigned char) *field[i]) || ptype != 0)
1072  {
1073  char *cp;
1074 
1075  /*
1076  * Allow a preceding "t" field, but no other units.
1077  */
1078  if (ptype != 0)
1079  {
1080  /* Sanity check; should not fail this test */
1081  if (ptype != DTK_TIME)
1082  return DTERR_BAD_FORMAT;
1083  ptype = 0;
1084  }
1085 
1086  /*
1087  * Starts with a digit but we already have a time
1088  * field? Then we are in trouble with a date and time
1089  * already...
1090  */
1091  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1092  return DTERR_BAD_FORMAT;
1093 
1094  if ((cp = strchr(field[i], '-')) == NULL)
1095  return DTERR_BAD_FORMAT;
1096 
1097  /* Get the time zone from the end of the string */
1098  dterr = DecodeTimezone(cp, tzp);
1099  if (dterr)
1100  return dterr;
1101  *cp = '\0';
1102 
1103  /*
1104  * Then read the rest of the field as a concatenated
1105  * time
1106  */
1107  dterr = DecodeNumberField(strlen(field[i]), field[i],
1108  fmask,
1109  &tmask, tm,
1110  fsec, &is2digits);
1111  if (dterr < 0)
1112  return dterr;
1113 
1114  /*
1115  * modify tmask after returning from
1116  * DecodeNumberField()
1117  */
1118  tmask |= DTK_M(TZ);
1119  }
1120  else
1121  {
1122  namedTz = pg_tzset(field[i]);
1123  if (!namedTz)
1124  {
1125  extra->dtee_timezone = field[i];
1126  return DTERR_BAD_TIMEZONE;
1127  }
1128  /* we'll apply the zone setting below */
1129  tmask = DTK_M(TZ);
1130  }
1131  }
1132  else
1133  {
1134  dterr = DecodeDate(field[i], fmask,
1135  &tmask, &is2digits, tm);
1136  if (dterr)
1137  return dterr;
1138  }
1139  break;
1140 
1141  case DTK_TIME:
1142 
1143  /*
1144  * This might be an ISO time following a "t" field.
1145  */
1146  if (ptype != 0)
1147  {
1148  /* Sanity check; should not fail this test */
1149  if (ptype != DTK_TIME)
1150  return DTERR_BAD_FORMAT;
1151  ptype = 0;
1152  }
1153  dterr = DecodeTime(field[i], fmask, INTERVAL_FULL_RANGE,
1154  &tmask, tm, fsec);
1155  if (dterr)
1156  return dterr;
1157 
1158  /* check for time overflow */
1160  *fsec))
1161  return DTERR_FIELD_OVERFLOW;
1162  break;
1163 
1164  case DTK_TZ:
1165  {
1166  int tz;
1167 
1168  if (tzp == NULL)
1169  return DTERR_BAD_FORMAT;
1170 
1171  dterr = DecodeTimezone(field[i], &tz);
1172  if (dterr)
1173  return dterr;
1174  *tzp = tz;
1175  tmask = DTK_M(TZ);
1176  }
1177  break;
1178 
1179  case DTK_NUMBER:
1180 
1181  /*
1182  * Deal with cases where previous field labeled this one
1183  */
1184  if (ptype != 0)
1185  {
1186  char *cp;
1187  int value;
1188 
1189  errno = 0;
1190  value = strtoint(field[i], &cp, 10);
1191  if (errno == ERANGE)
1192  return DTERR_FIELD_OVERFLOW;
1193  if (*cp != '.' && *cp != '\0')
1194  return DTERR_BAD_FORMAT;
1195 
1196  switch (ptype)
1197  {
1198  case DTK_JULIAN:
1199  /* previous field was a label for "julian date" */
1200  if (value < 0)
1201  return DTERR_FIELD_OVERFLOW;
1202  tmask = DTK_DATE_M;
1203  j2date(value, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1204  isjulian = true;
1205 
1206  /* fractional Julian Day? */
1207  if (*cp == '.')
1208  {
1209  double time;
1210 
1211  dterr = ParseFraction(cp, &time);
1212  if (dterr)
1213  return dterr;
1214  time *= USECS_PER_DAY;
1215  dt2time(time,
1216  &tm->tm_hour, &tm->tm_min,
1217  &tm->tm_sec, fsec);
1218  tmask |= DTK_TIME_M;
1219  }
1220  break;
1221 
1222  case DTK_TIME:
1223  /* previous field was "t" for ISO time */
1224  dterr = DecodeNumberField(strlen(field[i]), field[i],
1225  (fmask | DTK_DATE_M),
1226  &tmask, tm,
1227  fsec, &is2digits);
1228  if (dterr < 0)
1229  return dterr;
1230  if (tmask != DTK_TIME_M)
1231  return DTERR_BAD_FORMAT;
1232  break;
1233 
1234  default:
1235  return DTERR_BAD_FORMAT;
1236  break;
1237  }
1238 
1239  ptype = 0;
1240  *dtype = DTK_DATE;
1241  }
1242  else
1243  {
1244  char *cp;
1245  int flen;
1246 
1247  flen = strlen(field[i]);
1248  cp = strchr(field[i], '.');
1249 
1250  /* Embedded decimal and no date yet? */
1251  if (cp != NULL && !(fmask & DTK_DATE_M))
1252  {
1253  dterr = DecodeDate(field[i], fmask,
1254  &tmask, &is2digits, tm);
1255  if (dterr)
1256  return dterr;
1257  }
1258  /* embedded decimal and several digits before? */
1259  else if (cp != NULL && flen - strlen(cp) > 2)
1260  {
1261  /*
1262  * Interpret as a concatenated date or time Set the
1263  * type field to allow decoding other fields later.
1264  * Example: 20011223 or 040506
1265  */
1266  dterr = DecodeNumberField(flen, field[i], fmask,
1267  &tmask, tm,
1268  fsec, &is2digits);
1269  if (dterr < 0)
1270  return dterr;
1271  }
1272 
1273  /*
1274  * Is this a YMD or HMS specification, or a year number?
1275  * YMD and HMS are required to be six digits or more, so
1276  * if it is 5 digits, it is a year. If it is six or more
1277  * digits, we assume it is YMD or HMS unless no date and
1278  * no time values have been specified. This forces 6+
1279  * digit years to be at the end of the string, or to use
1280  * the ISO date specification.
1281  */
1282  else if (flen >= 6 && (!(fmask & DTK_DATE_M) ||
1283  !(fmask & DTK_TIME_M)))
1284  {
1285  dterr = DecodeNumberField(flen, field[i], fmask,
1286  &tmask, tm,
1287  fsec, &is2digits);
1288  if (dterr < 0)
1289  return dterr;
1290  }
1291  /* otherwise it is a single date/time field... */
1292  else
1293  {
1294  dterr = DecodeNumber(flen, field[i],
1295  haveTextMonth, fmask,
1296  &tmask, tm,
1297  fsec, &is2digits);
1298  if (dterr)
1299  return dterr;
1300  }
1301  }
1302  break;
1303 
1304  case DTK_STRING:
1305  case DTK_SPECIAL:
1306  /* timezone abbrevs take precedence over built-in tokens */
1307  dterr = DecodeTimezoneAbbrev(i, field[i],
1308  &type, &val, &valtz, extra);
1309  if (dterr)
1310  return dterr;
1311  if (type == UNKNOWN_FIELD)
1312  type = DecodeSpecial(i, field[i], &val);
1313  if (type == IGNORE_DTF)
1314  continue;
1315 
1316  tmask = DTK_M(type);
1317  switch (type)
1318  {
1319  case RESERV:
1320  switch (val)
1321  {
1322  case DTK_NOW:
1323  tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
1324  *dtype = DTK_DATE;
1325  GetCurrentTimeUsec(tm, fsec, tzp);
1326  break;
1327 
1328  case DTK_YESTERDAY:
1329  tmask = DTK_DATE_M;
1330  *dtype = DTK_DATE;
1331  GetCurrentDateTime(&cur_tm);
1332  j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) - 1,
1333  &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1334  break;
1335 
1336  case DTK_TODAY:
1337  tmask = DTK_DATE_M;
1338  *dtype = DTK_DATE;
1339  GetCurrentDateTime(&cur_tm);
1340  tm->tm_year = cur_tm.tm_year;
1341  tm->tm_mon = cur_tm.tm_mon;
1342  tm->tm_mday = cur_tm.tm_mday;
1343  break;
1344 
1345  case DTK_TOMORROW:
1346  tmask = DTK_DATE_M;
1347  *dtype = DTK_DATE;
1348  GetCurrentDateTime(&cur_tm);
1349  j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) + 1,
1350  &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1351  break;
1352 
1353  case DTK_ZULU:
1354  tmask = (DTK_TIME_M | DTK_M(TZ));
1355  *dtype = DTK_DATE;
1356  tm->tm_hour = 0;
1357  tm->tm_min = 0;
1358  tm->tm_sec = 0;
1359  if (tzp != NULL)
1360  *tzp = 0;
1361  break;
1362 
1363  case DTK_EPOCH:
1364  case DTK_LATE:
1365  case DTK_EARLY:
1366  tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
1367  *dtype = val;
1368  /* caller ignores tm for these dtype codes */
1369  break;
1370 
1371  default:
1372  elog(ERROR, "unrecognized RESERV datetime token: %d",
1373  val);
1374  }
1375 
1376  break;
1377 
1378  case MONTH:
1379 
1380  /*
1381  * already have a (numeric) month? then see if we can
1382  * substitute...
1383  */
1384  if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
1385  !(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 &&
1386  tm->tm_mon <= 31)
1387  {
1388  tm->tm_mday = tm->tm_mon;
1389  tmask = DTK_M(DAY);
1390  }
1391  haveTextMonth = true;
1392  tm->tm_mon = val;
1393  break;
1394 
1395  case DTZMOD:
1396 
1397  /*
1398  * daylight savings time modifier (solves "MET DST"
1399  * syntax)
1400  */
1401  tmask |= DTK_M(DTZ);
1402  tm->tm_isdst = 1;
1403  if (tzp == NULL)
1404  return DTERR_BAD_FORMAT;
1405  *tzp -= val;
1406  break;
1407 
1408  case DTZ:
1409 
1410  /*
1411  * set mask for TZ here _or_ check for DTZ later when
1412  * getting default timezone
1413  */
1414  tmask |= DTK_M(TZ);
1415  tm->tm_isdst = 1;
1416  if (tzp == NULL)
1417  return DTERR_BAD_FORMAT;
1418  *tzp = -val;
1419  break;
1420 
1421  case TZ:
1422  tm->tm_isdst = 0;
1423  if (tzp == NULL)
1424  return DTERR_BAD_FORMAT;
1425  *tzp = -val;
1426  break;
1427 
1428  case DYNTZ:
1429  tmask |= DTK_M(TZ);
1430  if (tzp == NULL)
1431  return DTERR_BAD_FORMAT;
1432  /* we'll determine the actual offset later */
1433  abbrevTz = valtz;
1434  abbrev = field[i];
1435  break;
1436 
1437  case AMPM:
1438  mer = val;
1439  break;
1440 
1441  case ADBC:
1442  bc = (val == BC);
1443  break;
1444 
1445  case DOW:
1446  tm->tm_wday = val;
1447  break;
1448 
1449  case UNITS:
1450  tmask = 0;
1451  /* reject consecutive unhandled units */
1452  if (ptype != 0)
1453  return DTERR_BAD_FORMAT;
1454  ptype = val;
1455  break;
1456 
1457  case ISOTIME:
1458 
1459  /*
1460  * This is a filler field "t" indicating that the next
1461  * field is time. Try to verify that this is sensible.
1462  */
1463  tmask = 0;
1464 
1465  /* No preceding date? Then quit... */
1466  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1467  return DTERR_BAD_FORMAT;
1468 
1469  /* reject consecutive unhandled units */
1470  if (ptype != 0)
1471  return DTERR_BAD_FORMAT;
1472  ptype = val;
1473  break;
1474 
1475  case UNKNOWN_FIELD:
1476 
1477  /*
1478  * Before giving up and declaring error, check to see
1479  * if it is an all-alpha timezone name.
1480  */
1481  namedTz = pg_tzset(field[i]);
1482  if (!namedTz)
1483  return DTERR_BAD_FORMAT;
1484  /* we'll apply the zone setting below */
1485  tmask = DTK_M(TZ);
1486  break;
1487 
1488  default:
1489  return DTERR_BAD_FORMAT;
1490  }
1491  break;
1492 
1493  default:
1494  return DTERR_BAD_FORMAT;
1495  }
1496 
1497  if (tmask & fmask)
1498  return DTERR_BAD_FORMAT;
1499  fmask |= tmask;
1500  } /* end loop over fields */
1501 
1502  /* reject if prefix type appeared and was never handled */
1503  if (ptype != 0)
1504  return DTERR_BAD_FORMAT;
1505 
1506  /* do additional checking for normal date specs (but not "infinity" etc) */
1507  if (*dtype == DTK_DATE)
1508  {
1509  /* do final checking/adjustment of Y/M/D fields */
1510  dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
1511  if (dterr)
1512  return dterr;
1513 
1514  /* handle AM/PM */
1515  if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
1516  return DTERR_FIELD_OVERFLOW;
1517  if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
1518  tm->tm_hour = 0;
1519  else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
1520  tm->tm_hour += HOURS_PER_DAY / 2;
1521 
1522  /* check for incomplete input */
1523  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1524  {
1525  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1526  return 1;
1527  return DTERR_BAD_FORMAT;
1528  }
1529 
1530  /*
1531  * If we had a full timezone spec, compute the offset (we could not do
1532  * it before, because we need the date to resolve DST status).
1533  */
1534  if (namedTz != NULL)
1535  {
1536  /* daylight savings time modifier disallowed with full TZ */
1537  if (fmask & DTK_M(DTZMOD))
1538  return DTERR_BAD_FORMAT;
1539 
1540  *tzp = DetermineTimeZoneOffset(tm, namedTz);
1541  }
1542 
1543  /*
1544  * Likewise, if we had a dynamic timezone abbreviation, resolve it
1545  * now.
1546  */
1547  if (abbrevTz != NULL)
1548  {
1549  /* daylight savings time modifier disallowed with dynamic TZ */
1550  if (fmask & DTK_M(DTZMOD))
1551  return DTERR_BAD_FORMAT;
1552 
1553  *tzp = DetermineTimeZoneAbbrevOffset(tm, abbrev, abbrevTz);
1554  }
1555 
1556  /* timezone not specified? then use session timezone */
1557  if (tzp != NULL && !(fmask & DTK_M(TZ)))
1558  {
1559  /*
1560  * daylight savings time modifier but no standard timezone? then
1561  * error
1562  */
1563  if (fmask & DTK_M(DTZMOD))
1564  return DTERR_BAD_FORMAT;
1565 
1567  }
1568  }
1569 
1570  return 0;
1571 }
static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits, struct pg_tm *tm)
Definition: datetime.c:2389
static int DecodeNumberField(int len, char *str, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2903
static int ParseFraction(char *cp, double *frac)
Definition: datetime.c:682
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1587
int DecodeTimezoneAbbrev(int field, const char *lowtoken, int *ftype, int *offset, pg_tz **tz, DateTimeErrorExtra *extra)
Definition: datetime.c:3082
static int DecodeTime(char *str, int fmask, int range, int *tmask, struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:2663
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2499
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:313
void GetCurrentDateTime(struct pg_tm *tm)
Definition: datetime.c:368
int DecodeTimezone(const char *str, int *tzp)
Definition: datetime.c:2998
void GetCurrentTimeUsec(struct pg_tm *tm, fsec_t *fsec, int *tzp)
Definition: datetime.c:389
int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp)
Definition: datetime.c:1748
void dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
Definition: timestamp.c:1803
#define HOURS_PER_DAY
Definition: timestamp.h:117
bool time_overflows(int hour, int min, int sec, fsec_t fsec)
Definition: date.c:1426
#define ERROR
Definition: elog.h:39
#define DTK_TOMORROW
Definition: datetime.h:156
#define DTK_EPOCH
Definition: datetime.h:152
#define DTK_SPECIAL
Definition: datetime.h:149
#define AMPM
Definition: datetime.h:99
#define DTK_TIME
Definition: datetime.h:145
#define UNKNOWN_FIELD
Definition: datetime.h:124
#define PM
Definition: datetime.h:72
#define DTK_NUMBER
Definition: datetime.h:141
#define DTK_STRING
Definition: datetime.h:142
#define DTK_JULIAN
Definition: datetime.h:173
#define DTK_TIME_M
Definition: datetime.h:192
#define DAY
Definition: datetime.h:93
#define ADBC
Definition: datetime.h:108
#define DTK_LATE
Definition: datetime.h:151
#define DTK_DATE
Definition: datetime.h:144
#define RESERV
Definition: datetime.h:90
#define BC
Definition: datetime.h:76
#define HR24
Definition: datetime.h:73
#define DTK_EARLY
Definition: datetime.h:150
#define DTZMOD
Definition: datetime.h:122
#define DTK_TZ
Definition: datetime.h:146
#define DOW
Definition: datetime.h:106
#define ISOTIME
Definition: datetime.h:115
#define AM
Definition: datetime.h:71
#define DTK_YESTERDAY
Definition: datetime.h:154
#define DTK_ZULU
Definition: datetime.h:157
#define UNITS
Definition: datetime.h:107
#define DTK_TODAY
Definition: datetime.h:155
#define DTK_NOW
Definition: datetime.h:153
PGDLLIMPORT pg_tz * session_timezone
Definition: pgtz.c:28
pg_tz * pg_tzset(const char *tzname)
Definition: pgtz.c:234
int strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base)
Definition: string.c:51
Definition: pgtime.h:35
int tm_hour
Definition: pgtime.h:38
int tm_mday
Definition: pgtime.h:39
int tm_min
Definition: pgtime.h:37
int tm_wday
Definition: pgtime.h:42
int tm_isdst
Definition: pgtime.h:44
int tm_year
Definition: pgtime.h:41
Definition: pgtz.h:66
#define INTERVAL_FULL_RANGE
Definition: timestamp.h:76

References ADBC, AM, AMPM, BC, date2j(), DAY, DecodeDate(), DecodeNumber(), DecodeNumberField(), DecodeSpecial(), DecodeTime(), DecodeTimezone(), DecodeTimezoneAbbrev(), DetermineTimeZoneAbbrevOffset(), DetermineTimeZoneOffset(), DOW, dt2time(), DateTimeErrorExtra::dtee_timezone, DTERR_BAD_FORMAT, DTERR_BAD_TIMEZONE, DTERR_FIELD_OVERFLOW, DTK_DATE, DTK_DATE_M, DTK_EARLY, DTK_EPOCH, DTK_JULIAN, DTK_LATE, DTK_M, DTK_NOW, DTK_NUMBER, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TIME_M, DTK_TODAY, DTK_TOMORROW, DTK_TZ, DTK_YESTERDAY, DTK_ZULU, DTZ, DTZMOD, DYNTZ, elog(), ERROR, GetCurrentDateTime(), GetCurrentTimeUsec(), HOURS_PER_DAY, HR24, i, IGNORE_DTF, INTERVAL_FULL_RANGE, ISOTIME, j2date(), MONTH, ParseFraction(), pg_tzset(), PM, RESERV, session_timezone, strtoint(), time_overflows(), tm, 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, type, TZ, UNITS, UNKNOWN_FIELD, USECS_PER_DAY, val, ValidateDate(), and value.

Referenced by check_recovery_target_time(), date_in(), pg_logdir_ls_internal(), PGTYPESdate_from_asc(), PGTYPEStimestamp_from_asc(), timestamp_in(), and timestamptz_in().

◆ DecodeInterval()

int DecodeInterval ( char **  field,
int *  ftype,
int  nf,
int  range,
int *  dtype,
struct pg_itm_in itm_in 
)

Definition at line 3276 of file datetime.c.

3278 {
3279  bool force_negative = false;
3280  bool is_before = false;
3281  bool parsing_unit_val = false;
3282  char *cp;
3283  int fmask = 0,
3284  tmask,
3285  type,
3286  uval;
3287  int i;
3288  int dterr;
3289  int64 val;
3290  double fval;
3291 
3292  *dtype = DTK_DELTA;
3293  type = IGNORE_DTF;
3294  ClearPgItmIn(itm_in);
3295 
3296  /*----------
3297  * The SQL standard defines the interval literal
3298  * '-1 1:00:00'
3299  * to mean "negative 1 days and negative 1 hours", while Postgres
3300  * traditionally treats this as meaning "negative 1 days and positive
3301  * 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign
3302  * to all fields if there are no other explicit signs.
3303  *
3304  * We leave the signs alone if there are additional explicit signs.
3305  * This protects us against misinterpreting postgres-style dump output,
3306  * since the postgres-style output code has always put an explicit sign on
3307  * all fields following a negative field. But note that SQL-spec output
3308  * is ambiguous and can be misinterpreted on load! (So it's best practice
3309  * to dump in postgres style, not SQL style.)
3310  *----------
3311  */
3312  if (IntervalStyle == INTSTYLE_SQL_STANDARD && nf > 0 && *field[0] == '-')
3313  {
3314  force_negative = true;
3315  /* Check for additional explicit signs */
3316  for (i = 1; i < nf; i++)
3317  {
3318  if (*field[i] == '-' || *field[i] == '+')
3319  {
3320  force_negative = false;
3321  break;
3322  }
3323  }
3324  }
3325 
3326  /* read through list backwards to pick up units before values */
3327  for (i = nf - 1; i >= 0; i--)
3328  {
3329  switch (ftype[i])
3330  {
3331  case DTK_TIME:
3332  dterr = DecodeTimeForInterval(field[i], fmask, range,
3333  &tmask, itm_in);
3334  if (dterr)
3335  return dterr;
3336  if (force_negative &&
3337  itm_in->tm_usec > 0)
3338  itm_in->tm_usec = -itm_in->tm_usec;
3339  type = DTK_DAY;
3340  parsing_unit_val = false;
3341  break;
3342 
3343  case DTK_TZ:
3344 
3345  /*
3346  * Timezone means a token with a leading sign character and at
3347  * least one digit; there could be ':', '.', '-' embedded in
3348  * it as well.
3349  */
3350  Assert(*field[i] == '-' || *field[i] == '+');
3351 
3352  /*
3353  * Check for signed hh:mm or hh:mm:ss. If so, process exactly
3354  * like DTK_TIME case above, plus handling the sign.
3355  */
3356  if (strchr(field[i] + 1, ':') != NULL &&
3357  DecodeTimeForInterval(field[i] + 1, fmask, range,
3358  &tmask, itm_in) == 0)
3359  {
3360  if (*field[i] == '-')
3361  {
3362  /* flip the sign on time field */
3363  if (itm_in->tm_usec == PG_INT64_MIN)
3364  return DTERR_FIELD_OVERFLOW;
3365  itm_in->tm_usec = -itm_in->tm_usec;
3366  }
3367 
3368  if (force_negative &&
3369  itm_in->tm_usec > 0)
3370  itm_in->tm_usec = -itm_in->tm_usec;
3371 
3372  /*
3373  * Set the next type to be a day, if units are not
3374  * specified. This handles the case of '1 +02:03' since we
3375  * are reading right to left.
3376  */
3377  type = DTK_DAY;
3378  parsing_unit_val = false;
3379  break;
3380  }
3381 
3382  /*
3383  * Otherwise, fall through to DTK_NUMBER case, which can
3384  * handle signed float numbers and signed year-month values.
3385  */
3386 
3387  /* FALLTHROUGH */
3388 
3389  case DTK_DATE:
3390  case DTK_NUMBER:
3391  if (type == IGNORE_DTF)
3392  {
3393  /* use typmod to decide what rightmost field is */
3394  switch (range)
3395  {
3396  case INTERVAL_MASK(YEAR):
3397  type = DTK_YEAR;
3398  break;
3399  case INTERVAL_MASK(MONTH):
3401  type = DTK_MONTH;
3402  break;
3403  case INTERVAL_MASK(DAY):
3404  type = DTK_DAY;
3405  break;
3406  case INTERVAL_MASK(HOUR):
3408  type = DTK_HOUR;
3409  break;
3410  case INTERVAL_MASK(MINUTE):
3413  type = DTK_MINUTE;
3414  break;
3415  case INTERVAL_MASK(SECOND):
3419  type = DTK_SECOND;
3420  break;
3421  default:
3422  type = DTK_SECOND;
3423  break;
3424  }
3425  }
3426 
3427  errno = 0;
3428  val = strtoi64(field[i], &cp, 10);
3429  if (errno == ERANGE)
3430  return DTERR_FIELD_OVERFLOW;
3431 
3432  if (*cp == '-')
3433  {
3434  /* SQL "years-months" syntax */
3435  int val2;
3436 
3437  val2 = strtoint(cp + 1, &cp, 10);
3438  if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
3439  return DTERR_FIELD_OVERFLOW;
3440  if (*cp != '\0')
3441  return DTERR_BAD_FORMAT;
3442  type = DTK_MONTH;
3443  if (*field[i] == '-')
3444  val2 = -val2;
3446  return DTERR_FIELD_OVERFLOW;
3447  if (pg_add_s64_overflow(val, val2, &val))
3448  return DTERR_FIELD_OVERFLOW;
3449  fval = 0;
3450  }
3451  else if (*cp == '.')
3452  {
3453  dterr = ParseFraction(cp, &fval);
3454  if (dterr)
3455  return dterr;
3456  if (*field[i] == '-')
3457  fval = -fval;
3458  }
3459  else if (*cp == '\0')
3460  fval = 0;
3461  else
3462  return DTERR_BAD_FORMAT;
3463 
3464  tmask = 0; /* DTK_M(type); */
3465 
3466  if (force_negative)
3467  {
3468  /* val and fval should be of same sign, but test anyway */
3469  if (val > 0)
3470  val = -val;
3471  if (fval > 0)
3472  fval = -fval;
3473  }
3474 
3475  switch (type)
3476  {
3477  case DTK_MICROSEC:
3478  if (!AdjustMicroseconds(val, fval, 1, itm_in))
3479  return DTERR_FIELD_OVERFLOW;
3480  tmask = DTK_M(MICROSECOND);
3481  break;
3482 
3483  case DTK_MILLISEC:
3484  if (!AdjustMicroseconds(val, fval, 1000, itm_in))
3485  return DTERR_FIELD_OVERFLOW;
3486  tmask = DTK_M(MILLISECOND);
3487  break;
3488 
3489  case DTK_SECOND:
3490  if (!AdjustMicroseconds(val, fval, USECS_PER_SEC, itm_in))
3491  return DTERR_FIELD_OVERFLOW;
3492 
3493  /*
3494  * If any subseconds were specified, consider this
3495  * microsecond and millisecond input as well.
3496  */
3497  if (fval == 0)
3498  tmask = DTK_M(SECOND);
3499  else
3500  tmask = DTK_ALL_SECS_M;
3501  break;
3502 
3503  case DTK_MINUTE:
3504  if (!AdjustMicroseconds(val, fval, USECS_PER_MINUTE, itm_in))
3505  return DTERR_FIELD_OVERFLOW;
3506  tmask = DTK_M(MINUTE);
3507  break;
3508 
3509  case DTK_HOUR:
3510  if (!AdjustMicroseconds(val, fval, USECS_PER_HOUR, itm_in))
3511  return DTERR_FIELD_OVERFLOW;
3512  tmask = DTK_M(HOUR);
3513  type = DTK_DAY; /* set for next field */
3514  break;
3515 
3516  case DTK_DAY:
3517  if (!AdjustDays(val, 1, itm_in) ||
3518  !AdjustFractMicroseconds(fval, USECS_PER_DAY, itm_in))
3519  return DTERR_FIELD_OVERFLOW;
3520  tmask = DTK_M(DAY);
3521  break;
3522 
3523  case DTK_WEEK:
3524  if (!AdjustDays(val, 7, itm_in) ||
3525  !AdjustFractDays(fval, 7, itm_in))
3526  return DTERR_FIELD_OVERFLOW;
3527  tmask = DTK_M(WEEK);
3528  break;
3529 
3530  case DTK_MONTH:
3531  if (!AdjustMonths(val, itm_in) ||
3532  !AdjustFractDays(fval, DAYS_PER_MONTH, itm_in))
3533  return DTERR_FIELD_OVERFLOW;
3534  tmask = DTK_M(MONTH);
3535  break;
3536 
3537  case DTK_YEAR:
3538  if (!AdjustYears(val, 1, itm_in) ||
3539  !AdjustFractYears(fval, 1, itm_in))
3540  return DTERR_FIELD_OVERFLOW;
3541  tmask = DTK_M(YEAR);
3542  break;
3543 
3544  case DTK_DECADE:
3545  if (!AdjustYears(val, 10, itm_in) ||
3546  !AdjustFractYears(fval, 10, itm_in))
3547  return DTERR_FIELD_OVERFLOW;
3548  tmask = DTK_M(DECADE);
3549  break;
3550 
3551  case DTK_CENTURY:
3552  if (!AdjustYears(val, 100, itm_in) ||
3553  !AdjustFractYears(fval, 100, itm_in))
3554  return DTERR_FIELD_OVERFLOW;
3555  tmask = DTK_M(CENTURY);
3556  break;
3557 
3558  case DTK_MILLENNIUM:
3559  if (!AdjustYears(val, 1000, itm_in) ||
3560  !AdjustFractYears(fval, 1000, itm_in))
3561  return DTERR_FIELD_OVERFLOW;
3562  tmask = DTK_M(MILLENNIUM);
3563  break;
3564 
3565  default:
3566  return DTERR_BAD_FORMAT;
3567  }
3568  parsing_unit_val = false;
3569  break;
3570 
3571  case DTK_STRING:
3572  case DTK_SPECIAL:
3573  /* reject consecutive unhandled units */
3574  if (parsing_unit_val)
3575  return DTERR_BAD_FORMAT;
3576  type = DecodeUnits(i, field[i], &uval);
3577  if (type == IGNORE_DTF)
3578  continue;
3579 
3580  tmask = 0; /* DTK_M(type); */
3581  switch (type)
3582  {
3583  case UNITS:
3584  type = uval;
3585  parsing_unit_val = true;
3586  break;
3587 
3588  case AGO:
3589 
3590  /*
3591  * "ago" is only allowed to appear at the end of the
3592  * interval.
3593  */
3594  if (i != nf - 1)
3595  return DTERR_BAD_FORMAT;
3596  is_before = true;
3597  type = uval;
3598  break;
3599 
3600  default:
3601  return DTERR_BAD_FORMAT;
3602  }
3603  break;
3604 
3605  default:
3606  return DTERR_BAD_FORMAT;
3607  }
3608 
3609  if (tmask & fmask)
3610  return DTERR_BAD_FORMAT;
3611  fmask |= tmask;
3612  }
3613 
3614  /* ensure that at least one time field has been found */
3615  if (fmask == 0)
3616  return DTERR_BAD_FORMAT;
3617 
3618  /* reject if unit appeared and was never handled */
3619  if (parsing_unit_val)
3620  return DTERR_BAD_FORMAT;
3621 
3622  /* finally, AGO negates everything */
3623  if (is_before)
3624  {
3625  if (itm_in->tm_usec == PG_INT64_MIN ||
3626  itm_in->tm_mday == INT_MIN ||
3627  itm_in->tm_mon == INT_MIN ||
3628  itm_in->tm_year == INT_MIN)
3629  return DTERR_FIELD_OVERFLOW;
3630 
3631  itm_in->tm_usec = -itm_in->tm_usec;
3632  itm_in->tm_mday = -itm_in->tm_mday;
3633  itm_in->tm_mon = -itm_in->tm_mon;
3634  itm_in->tm_year = -itm_in->tm_year;
3635  }
3636 
3637  return 0;
3638 }
int DecodeUnits(int field, const char *lowtoken, int *val)
Definition: datetime.c:3936
static bool AdjustDays(int64 val, int scale, struct pg_itm_in *itm_in)
Definition: datetime.c:635
static bool AdjustFractYears(double frac, int scale, struct pg_itm_in *itm_in)
Definition: datetime.c:603
static bool AdjustMicroseconds(int64 val, double fval, int64 scale, struct pg_itm_in *itm_in)
Definition: datetime.c:620
static int DecodeTimeForInterval(char *str, int fmask, int range, int *tmask, struct pg_itm_in *itm_in)
Definition: datetime.c:2692
static bool AdjustYears(int64 val, int scale, struct pg_itm_in *itm_in)
Definition: datetime.c:663
static bool AdjustMonths(int64 val, struct pg_itm_in *itm_in)
Definition: datetime.c:651
static bool AdjustFractDays(double frac, int scale, struct pg_itm_in *itm_in)
Definition: datetime.c:571
static void ClearPgItmIn(struct pg_itm_in *itm_in)
Definition: datetime.c:3255
#define strtoi64(str, endptr, base)
Definition: c.h:1307
#define PG_INT64_MIN
Definition: c.h:580
#define USECS_PER_HOUR
Definition: timestamp.h:131
#define USECS_PER_SEC
Definition: timestamp.h:133
#define USECS_PER_MINUTE
Definition: timestamp.h:132
#define DAYS_PER_MONTH
Definition: timestamp.h:116
int IntervalStyle
Definition: globals.c:121
#define MILLENNIUM
Definition: datetime.h:120
#define DTK_DECADE
Definition: datetime.h:168
#define DTK_SECOND
Definition: datetime.h:160
#define DTK_DELTA
Definition: datetime.h:159
#define MICROSECOND
Definition: datetime.h:104
#define HOUR
Definition: datetime.h:100
#define WEEK
Definition: datetime.h:117
#define DECADE
Definition: datetime.h:118
#define YEAR
Definition: datetime.h:92
#define DTK_CENTURY
Definition: datetime.h:169
#define MILLISECOND
Definition: datetime.h:103
#define DTK_DAY
Definition: datetime.h:163
#define CENTURY
Definition: datetime.h:119
#define DTK_MILLENNIUM
Definition: datetime.h:170
#define SECOND
Definition: datetime.h:102
#define DTK_ALL_SECS_M
Definition: datetime.h:190
#define DTK_HOUR
Definition: datetime.h:162
#define DTK_WEEK
Definition: datetime.h:164
#define MINUTE
Definition: datetime.h:101
#define DTK_MICROSEC
Definition: datetime.h:172
#define DTK_YEAR
Definition: datetime.h:167
#define AGO
Definition: datetime.h:110
#define DTK_MILLISEC
Definition: datetime.h:171
#define DTK_MONTH
Definition: datetime.h:165
#define DTK_MINUTE
Definition: datetime.h:161
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:215
#define INTSTYLE_SQL_STANDARD
Definition: miscadmin.h:252
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
#define INTERVAL_MASK(b)
Definition: timestamp.h:73

References AdjustDays(), AdjustFractDays(), AdjustFractMicroseconds(), AdjustFractYears(), AdjustMicroseconds(), AdjustMonths(), AdjustYears(), AGO, Assert(), CENTURY, ClearPgItmIn(), DAY, DAYS_PER_MONTH, DECADE, DecodeTimeForInterval(), DecodeUnits(), DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_ALL_SECS_M, DTK_CENTURY, DTK_DATE, 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_TZ, DTK_WEEK, DTK_YEAR, HOUR, i, IGNORE_DTF, INTERVAL_MASK, IntervalStyle, INTSTYLE_SQL_STANDARD, MICROSECOND, MILLENNIUM, MILLISECOND, MINUTE, MONTH, MONTHS_PER_YEAR, ParseFraction(), pg_add_s64_overflow(), PG_INT64_MIN, pg_mul_s64_overflow(), range(), SECOND, strtoi64, strtoint(), pg_itm_in::tm_mday, pg_itm_in::tm_mon, pg_itm_in::tm_usec, pg_itm_in::tm_year, type, UNITS, USECS_PER_DAY, USECS_PER_HOUR, USECS_PER_MINUTE, USECS_PER_SEC, val, WEEK, and YEAR.

Referenced by interval_in().

◆ DecodeISO8601Interval()

int DecodeISO8601Interval ( char *  str,
int *  dtype,
struct pg_itm_in itm_in 
)

Definition at line 3718 of file datetime.c.

3720 {
3721  bool datepart = true;
3722  bool havefield = false;
3723 
3724  *dtype = DTK_DELTA;
3725  ClearPgItmIn(itm_in);
3726 
3727  if (strlen(str) < 2 || str[0] != 'P')
3728  return DTERR_BAD_FORMAT;
3729 
3730  str++;
3731  while (*str)
3732  {
3733  char *fieldstart;
3734  int64 val;
3735  double fval;
3736  char unit;
3737  int dterr;
3738 
3739  if (*str == 'T') /* T indicates the beginning of the time part */
3740  {
3741  datepart = false;
3742  havefield = false;
3743  str++;
3744  continue;
3745  }
3746 
3747  fieldstart = str;
3748  dterr = ParseISO8601Number(str, &str, &val, &fval);
3749  if (dterr)
3750  return dterr;
3751 
3752  /*
3753  * Note: we could step off the end of the string here. Code below
3754  * *must* exit the loop if unit == '\0'.
3755  */
3756  unit = *str++;
3757 
3758  if (datepart)
3759  {
3760  switch (unit) /* before T: Y M W D */
3761  {
3762  case 'Y':
3763  if (!AdjustYears(val, 1, itm_in) ||
3764  !AdjustFractYears(fval, 1, itm_in))
3765  return DTERR_FIELD_OVERFLOW;
3766  break;
3767  case 'M':
3768  if (!AdjustMonths(val, itm_in) ||
3769  !AdjustFractDays(fval, DAYS_PER_MONTH, itm_in))
3770  return DTERR_FIELD_OVERFLOW;
3771  break;
3772  case 'W':
3773  if (!AdjustDays(val, 7, itm_in) ||
3774  !AdjustFractDays(fval, 7, itm_in))
3775  return DTERR_FIELD_OVERFLOW;
3776  break;
3777  case 'D':
3778  if (!AdjustDays(val, 1, itm_in) ||
3779  !AdjustFractMicroseconds(fval, USECS_PER_DAY, itm_in))
3780  return DTERR_FIELD_OVERFLOW;
3781  break;
3782  case 'T': /* ISO 8601 4.4.3.3 Alternative Format / Basic */
3783  case '\0':
3784  if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
3785  {
3786  if (!AdjustYears(val / 10000, 1, itm_in) ||
3787  !AdjustMonths((val / 100) % 100, itm_in) ||
3788  !AdjustDays(val % 100, 1, itm_in) ||
3789  !AdjustFractMicroseconds(fval, USECS_PER_DAY, itm_in))
3790  return DTERR_FIELD_OVERFLOW;
3791  if (unit == '\0')
3792  return 0;
3793  datepart = false;
3794  havefield = false;
3795  continue;
3796  }
3797  /* Else fall through to extended alternative format */
3798  /* FALLTHROUGH */
3799  case '-': /* ISO 8601 4.4.3.3 Alternative Format,
3800  * Extended */
3801  if (havefield)
3802  return DTERR_BAD_FORMAT;
3803 
3804  if (!AdjustYears(val, 1, itm_in) ||
3805  !AdjustFractYears(fval, 1, itm_in))
3806  return DTERR_FIELD_OVERFLOW;
3807  if (unit == '\0')
3808  return 0;
3809  if (unit == 'T')
3810  {
3811  datepart = false;
3812  havefield = false;
3813  continue;
3814  }
3815 
3816  dterr = ParseISO8601Number(str, &str, &val, &fval);
3817  if (dterr)
3818  return dterr;
3819  if (!AdjustMonths(val, itm_in) ||
3820  !AdjustFractDays(fval, DAYS_PER_MONTH, itm_in))
3821  return DTERR_FIELD_OVERFLOW;
3822  if (*str == '\0')
3823  return 0;
3824  if (*str == 'T')
3825  {
3826  datepart = false;
3827  havefield = false;
3828  continue;
3829  }
3830  if (*str != '-')
3831  return DTERR_BAD_FORMAT;
3832  str++;
3833 
3834  dterr = ParseISO8601Number(str, &str, &val, &fval);
3835  if (dterr)
3836  return dterr;
3837  if (!AdjustDays(val, 1, itm_in) ||
3838  !AdjustFractMicroseconds(fval, USECS_PER_DAY, itm_in))
3839  return DTERR_FIELD_OVERFLOW;
3840  if (*str == '\0')
3841  return 0;
3842  if (*str == 'T')
3843  {
3844  datepart = false;
3845  havefield = false;
3846  continue;
3847  }
3848  return DTERR_BAD_FORMAT;
3849  default:
3850  /* not a valid date unit suffix */
3851  return DTERR_BAD_FORMAT;
3852  }
3853  }
3854  else
3855  {
3856  switch (unit) /* after T: H M S */
3857  {
3858  case 'H':
3859  if (!AdjustMicroseconds(val, fval, USECS_PER_HOUR, itm_in))
3860  return DTERR_FIELD_OVERFLOW;
3861  break;
3862  case 'M':
3863  if (!AdjustMicroseconds(val, fval, USECS_PER_MINUTE, itm_in))
3864  return DTERR_FIELD_OVERFLOW;
3865  break;
3866  case 'S':
3867  if (!AdjustMicroseconds(val, fval, USECS_PER_SEC, itm_in))
3868  return DTERR_FIELD_OVERFLOW;
3869  break;
3870  case '\0': /* ISO 8601 4.4.3.3 Alternative Format */
3871  if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
3872  {
3873  if (!AdjustMicroseconds(val / 10000, 0, USECS_PER_HOUR, itm_in) ||
3874  !AdjustMicroseconds((val / 100) % 100, 0, USECS_PER_MINUTE, itm_in) ||
3875  !AdjustMicroseconds(val % 100, 0, USECS_PER_SEC, itm_in) ||
3876  !AdjustFractMicroseconds(fval, 1, itm_in))
3877  return DTERR_FIELD_OVERFLOW;
3878  return 0;
3879  }
3880  /* Else fall through to extended alternative format */
3881  /* FALLTHROUGH */
3882  case ':': /* ISO 8601 4.4.3.3 Alternative Format,
3883  * Extended */
3884  if (havefield)
3885  return DTERR_BAD_FORMAT;
3886 
3887  if (!AdjustMicroseconds(val, fval, USECS_PER_HOUR, itm_in))
3888  return DTERR_FIELD_OVERFLOW;
3889  if (unit == '\0')
3890  return 0;
3891 
3892  dterr = ParseISO8601Number(str, &str, &val, &fval);
3893  if (dterr)
3894  return dterr;
3895  if (!AdjustMicroseconds(val, fval, USECS_PER_MINUTE, itm_in))
3896  return DTERR_FIELD_OVERFLOW;
3897  if (*str == '\0')
3898  return 0;
3899  if (*str != ':')
3900  return DTERR_BAD_FORMAT;
3901  str++;
3902 
3903  dterr = ParseISO8601Number(str, &str, &val, &fval);
3904  if (dterr)
3905  return dterr;
3906  if (!AdjustMicroseconds(val, fval, USECS_PER_SEC, itm_in))
3907  return DTERR_FIELD_OVERFLOW;
3908  if (*str == '\0')
3909  return 0;
3910  return DTERR_BAD_FORMAT;
3911 
3912  default:
3913  /* not a valid time unit suffix */
3914  return DTERR_BAD_FORMAT;
3915  }
3916  }
3917 
3918  havefield = true;
3919  }
3920 
3921  return 0;
3922 }
static int ISO8601IntegerWidth(char *fieldstart)
Definition: datetime.c:3691
static int ParseISO8601Number(char *str, char **endptr, int64 *ipart, double *fpart)
Definition: datetime.c:3649

References AdjustDays(), AdjustFractDays(), AdjustFractMicroseconds(), AdjustFractYears(), AdjustMicroseconds(), AdjustMonths(), AdjustYears(), ClearPgItmIn(), DAYS_PER_MONTH, DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_DELTA, ISO8601IntegerWidth(), ParseISO8601Number(), generate_unaccent_rules::str, USECS_PER_DAY, USECS_PER_HOUR, USECS_PER_MINUTE, USECS_PER_SEC, and val.

Referenced by interval_in().

◆ DecodeNumber()

static int DecodeNumber ( int  flen,
char *  str,
bool  haveTextMonth,
int  fmask,
int *  tmask,
struct pg_tm tm,
fsec_t fsec,
bool is2digits 
)
static

Definition at line 2718 of file datetime.c.

2720 {
2721  int val;
2722  char *cp;
2723  int dterr;
2724 
2725  *tmask = 0;
2726 
2727  errno = 0;
2728  val = strtoint(str, &cp, 10);
2729  if (errno == ERANGE)
2730  return DTERR_FIELD_OVERFLOW;
2731  if (cp == str)
2732  return DTERR_BAD_FORMAT;
2733 
2734  if (*cp == '.')
2735  {
2736  /*
2737  * More than two digits before decimal point? Then could be a date or
2738  * a run-together time: 2001.360 20011225 040506.789
2739  */
2740  if (cp - str > 2)
2741  {
2742  dterr = DecodeNumberField(flen, str,
2743  (fmask | DTK_DATE_M),
2744  tmask, tm,
2745  fsec, is2digits);
2746  if (dterr < 0)
2747  return dterr;
2748  return 0;
2749  }
2750 
2751  dterr = ParseFractionalSecond(cp, fsec);
2752  if (dterr)
2753  return dterr;
2754  }
2755  else if (*cp != '\0')
2756  return DTERR_BAD_FORMAT;
2757 
2758  /* Special case for day of year */
2759  if (flen == 3 && (fmask & DTK_DATE_M) == DTK_M(YEAR) && val >= 1 &&
2760  val <= 366)
2761  {
2762  *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
2763  tm->tm_yday = val;
2764  /* tm_mon and tm_mday can't actually be set yet ... */
2765  return 0;
2766  }
2767 
2768  /* Switch based on what we have so far */
2769  switch (fmask & DTK_DATE_M)
2770  {
2771  case 0:
2772 
2773  /*
2774  * Nothing so far; make a decision about what we think the input
2775  * is. There used to be lots of heuristics here, but the
2776  * consensus now is to be paranoid. It *must* be either
2777  * YYYY-MM-DD (with a more-than-two-digit year field), or the
2778  * field order defined by DateOrder.
2779  */
2780  if (flen >= 3 || DateOrder == DATEORDER_YMD)
2781  {
2782  *tmask = DTK_M(YEAR);
2783  tm->tm_year = val;
2784  }
2785  else if (DateOrder == DATEORDER_DMY)
2786  {
2787  *tmask = DTK_M(DAY);
2788  tm->tm_mday = val;
2789  }
2790  else
2791  {
2792  *tmask = DTK_M(MONTH);
2793  tm->tm_mon = val;
2794  }
2795  break;
2796 
2797  case (DTK_M(YEAR)):
2798  /* Must be at second field of YY-MM-DD */
2799  *tmask = DTK_M(MONTH);
2800  tm->tm_mon = val;
2801  break;
2802 
2803  case (DTK_M(MONTH)):
2804  if (haveTextMonth)
2805  {
2806  /*
2807  * We are at the first numeric field of a date that included a
2808  * textual month name. We want to support the variants
2809  * MON-DD-YYYY, DD-MON-YYYY, and YYYY-MON-DD as unambiguous
2810  * inputs. We will also accept MON-DD-YY or DD-MON-YY in
2811  * either DMY or MDY modes, as well as YY-MON-DD in YMD mode.
2812  */
2813  if (flen >= 3 || DateOrder == DATEORDER_YMD)
2814  {
2815  *tmask = DTK_M(YEAR);
2816  tm->tm_year = val;
2817  }
2818  else
2819  {
2820  *tmask = DTK_M(DAY);
2821  tm->tm_mday = val;
2822  }
2823  }
2824  else
2825  {
2826  /* Must be at second field of MM-DD-YY */
2827  *tmask = DTK_M(DAY);
2828  tm->tm_mday = val;
2829  }
2830  break;
2831 
2832  case (DTK_M(YEAR) | DTK_M(MONTH)):
2833  if (haveTextMonth)
2834  {
2835  /* Need to accept DD-MON-YYYY even in YMD mode */
2836  if (flen >= 3 && *is2digits)
2837  {
2838  /* Guess that first numeric field is day was wrong */
2839  *tmask = DTK_M(DAY); /* YEAR is already set */
2840  tm->tm_mday = tm->tm_year;
2841  tm->tm_year = val;
2842  *is2digits = false;
2843  }
2844  else
2845  {
2846  *tmask = DTK_M(DAY);
2847  tm->tm_mday = val;
2848  }
2849  }
2850  else
2851  {
2852  /* Must be at third field of YY-MM-DD */
2853  *tmask = DTK_M(DAY);
2854  tm->tm_mday = val;
2855  }
2856  break;
2857 
2858  case (DTK_M(DAY)):
2859  /* Must be at second field of DD-MM-YY */
2860  *tmask = DTK_M(MONTH);
2861  tm->tm_mon = val;
2862  break;
2863 
2864  case (DTK_M(MONTH) | DTK_M(DAY)):
2865  /* Must be at third field of DD-MM-YY or MM-DD-YY */
2866  *tmask = DTK_M(YEAR);
2867  tm->tm_year = val;
2868  break;
2869 
2870  case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)):
2871  /* we have all the date, so it must be a time field */
2872  dterr = DecodeNumberField(flen, str, fmask,
2873  tmask, tm,
2874  fsec, is2digits);
2875  if (dterr < 0)
2876  return dterr;
2877  return 0;
2878 
2879  default:
2880  /* Anything else is bogus input */
2881  return DTERR_BAD_FORMAT;
2882  }
2883 
2884  /*
2885  * When processing a year field, mark it for adjustment if it's only one
2886  * or two digits.
2887  */
2888  if (*tmask == DTK_M(YEAR))
2889  *is2digits = (flen <= 2);
2890 
2891  return 0;
2892 }
static int ParseFractionalSecond(char *cp, fsec_t *fsec)
Definition: datetime.c:711
int DateOrder
Definition: globals.c:120
#define DATEORDER_DMY
Definition: miscadmin.h:237
#define DATEORDER_YMD
Definition: miscadmin.h:236
int tm_yday
Definition: pgtime.h:43

References DateOrder, DATEORDER_DMY, DATEORDER_YMD, DAY, DecodeNumberField(), DOY, DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_DATE_M, DTK_M, MONTH, ParseFractionalSecond(), generate_unaccent_rules::str, strtoint(), tm, 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().

◆ DecodeNumberField()

static int DecodeNumberField ( int  len,
char *  str,
int  fmask,
int *  tmask,
struct pg_tm tm,
fsec_t fsec,
bool is2digits 
)
static

Definition at line 2903 of file datetime.c.

2905 {
2906  char *cp;
2907 
2908  /*
2909  * Have a decimal point? Then this is a date or something with a seconds
2910  * field...
2911  */
2912  if ((cp = strchr(str, '.')) != NULL)
2913  {
2914  /*
2915  * Can we use ParseFractionalSecond here? Not clear whether trailing
2916  * junk should be rejected ...
2917  */
2918  if (cp[1] == '\0')
2919  {
2920  /* avoid assuming that strtod will accept "." */
2921  *fsec = 0;
2922  }
2923  else
2924  {
2925  double frac;
2926 
2927  errno = 0;
2928  frac = strtod(cp, NULL);
2929  if (errno != 0)
2930  return DTERR_BAD_FORMAT;
2931  *fsec = rint(frac * 1000000);
2932  }
2933  /* Now truncate off the fraction for further processing */
2934  *cp = '\0';
2935  len = strlen(str);
2936  }
2937  /* No decimal point and no complete date yet? */
2938  else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2939  {
2940  if (len >= 6)
2941  {
2942  *tmask = DTK_DATE_M;
2943 
2944  /*
2945  * Start from end and consider first 2 as Day, next 2 as Month,
2946  * and the rest as Year.
2947  */
2948  tm->tm_mday = atoi(str + (len - 2));
2949  *(str + (len - 2)) = '\0';
2950  tm->tm_mon = atoi(str + (len - 4));
2951  *(str + (len - 4)) = '\0';
2952  tm->tm_year = atoi(str);
2953  if ((len - 4) == 2)
2954  *is2digits = true;
2955 
2956  return DTK_DATE;
2957  }
2958  }
2959 
2960  /* not all time fields are specified? */
2961  if ((fmask & DTK_TIME_M) != DTK_TIME_M)
2962  {
2963  /* hhmmss */
2964  if (len == 6)
2965  {
2966  *tmask = DTK_TIME_M;
2967  tm->tm_sec = atoi(str + 4);
2968  *(str + 4) = '\0';
2969  tm->tm_min = atoi(str + 2);
2970  *(str + 2) = '\0';
2971  tm->tm_hour = atoi(str);
2972 
2973  return DTK_TIME;
2974  }
2975  /* hhmm? */
2976  else if (len == 4)
2977  {
2978  *tmask = DTK_TIME_M;
2979  tm->tm_sec = 0;
2980  tm->tm_min = atoi(str + 2);
2981  *(str + 2) = '\0';
2982  tm->tm_hour = atoi(str);
2983 
2984  return DTK_TIME;
2985  }
2986  }
2987 
2988  return DTERR_BAD_FORMAT;
2989 }

References DTERR_BAD_FORMAT, DTK_DATE, DTK_DATE_M, DTK_TIME, DTK_TIME_M, len, generate_unaccent_rules::str, tm, 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 DecodeDateTime(), DecodeNumber(), and DecodeTimeOnly().

◆ DecodeSpecial()

int DecodeSpecial ( int  field,
const char *  lowtoken,
int *  val 
)

Definition at line 3139 of file datetime.c.

3140 {
3141  int type;
3142  const datetkn *tp;
3143 
3144  tp = datecache[field];
3145  /* use strncmp so that we match truncated tokens */
3146  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3147  {
3148  tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
3149  }
3150  if (tp == NULL)
3151  {
3152  type = UNKNOWN_FIELD;
3153  *val = 0;
3154  }
3155  else
3156  {
3157  datecache[field] = tp;
3158  type = tp->type;
3159  *val = tp->value;
3160  }
3161 
3162  return type;
3163 }
static const datetkn * datecache[MAXDATEFIELDS]
Definition: datetime.c:260
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:4042

References datebsearch(), datecache, datetktbl, szdatetktbl, datetkn::token, TOKMAXLEN, type, datetkn::type, UNKNOWN_FIELD, val, and datetkn::value.

Referenced by DecodeDate(), DecodeDateTime(), DecodeTimeOnly(), extract_date(), interval_part_common(), time_part_common(), timestamp_part_common(), timestamptz_part_common(), and timetz_part_common().

◆ DecodeTime()

static int DecodeTime ( char *  str,
int  fmask,
int  range,
int *  tmask,
struct pg_tm tm,
fsec_t fsec 
)
static

Definition at line 2663 of file datetime.c.

2665 {
2666  struct pg_itm itm;
2667  int dterr;
2668 
2669  dterr = DecodeTimeCommon(str, fmask, range,
2670  tmask, &itm);
2671  if (dterr)
2672  return dterr;
2673 
2674  if (itm.tm_hour > INT_MAX)
2675  return DTERR_FIELD_OVERFLOW;
2676  tm->tm_hour = (int) itm.tm_hour;
2677  tm->tm_min = itm.tm_min;
2678  tm->tm_sec = itm.tm_sec;
2679  *fsec = itm.tm_usec;
2680 
2681  return 0;
2682 }
static int DecodeTimeCommon(char *str, int fmask, int range, int *tmask, struct pg_itm *itm)
Definition: datetime.c:2581

References DecodeTimeCommon(), DTERR_FIELD_OVERFLOW, range(), generate_unaccent_rules::str, tm, pg_itm::tm_hour, pg_tm::tm_hour, pg_itm::tm_min, pg_tm::tm_min, pg_itm::tm_sec, pg_tm::tm_sec, and pg_itm::tm_usec.

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

◆ DecodeTimeCommon()

static int DecodeTimeCommon ( char *  str,
int  fmask,
int  range,
int *  tmask,
struct pg_itm itm 
)
static

Definition at line 2581 of file datetime.c.

2583 {
2584  char *cp;
2585  int dterr;
2586  fsec_t fsec = 0;
2587 
2588  *tmask = DTK_TIME_M;
2589 
2590  errno = 0;
2591  itm->tm_hour = strtoi64(str, &cp, 10);
2592  if (errno == ERANGE)
2593  return DTERR_FIELD_OVERFLOW;
2594  if (*cp != ':')
2595  return DTERR_BAD_FORMAT;
2596  errno = 0;
2597  itm->tm_min = strtoint(cp + 1, &cp, 10);
2598  if (errno == ERANGE)
2599  return DTERR_FIELD_OVERFLOW;
2600  if (*cp == '\0')
2601  {
2602  itm->tm_sec = 0;
2603  /* If it's a MINUTE TO SECOND interval, take 2 fields as being mm:ss */
2605  {
2606  if (itm->tm_hour > INT_MAX || itm->tm_hour < INT_MIN)
2607  return DTERR_FIELD_OVERFLOW;
2608  itm->tm_sec = itm->tm_min;
2609  itm->tm_min = (int) itm->tm_hour;
2610  itm->tm_hour = 0;
2611  }
2612  }
2613  else if (*cp == '.')
2614  {
2615  /* always assume mm:ss.sss is MINUTE TO SECOND */
2616  dterr = ParseFractionalSecond(cp, &fsec);
2617  if (dterr)
2618  return dterr;
2619  if (itm->tm_hour > INT_MAX || itm->tm_hour < INT_MIN)
2620  return DTERR_FIELD_OVERFLOW;
2621  itm->tm_sec = itm->tm_min;
2622  itm->tm_min = (int) itm->tm_hour;
2623  itm->tm_hour = 0;
2624  }
2625  else if (*cp == ':')
2626  {
2627  errno = 0;
2628  itm->tm_sec = strtoint(cp + 1, &cp, 10);
2629  if (errno == ERANGE)
2630  return DTERR_FIELD_OVERFLOW;
2631  if (*cp == '.')
2632  {
2633  dterr = ParseFractionalSecond(cp, &fsec);
2634  if (dterr)
2635  return dterr;
2636  }
2637  else if (*cp != '\0')
2638  return DTERR_BAD_FORMAT;
2639  }
2640  else
2641  return DTERR_BAD_FORMAT;
2642 
2643  /* do a sanity check; but caller must check the range of tm_hour */
2644  if (itm->tm_hour < 0 ||
2645  itm->tm_min < 0 || itm->tm_min > MINS_PER_HOUR - 1 ||
2646  itm->tm_sec < 0 || itm->tm_sec > SECS_PER_MINUTE ||
2647  fsec < 0 || fsec > USECS_PER_SEC)
2648  return DTERR_FIELD_OVERFLOW;
2649 
2650  itm->tm_usec = (int) fsec;
2651 
2652  return 0;
2653 }
#define MINS_PER_HOUR
Definition: timestamp.h:128
#define SECS_PER_MINUTE
Definition: timestamp.h:127
int64 tm_hour
Definition: timestamp.h:70
int tm_sec
Definition: timestamp.h:68
int tm_min
Definition: timestamp.h:69
int tm_usec
Definition: timestamp.h:67

References DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_TIME_M, INTERVAL_MASK, MINS_PER_HOUR, MINUTE, ParseFractionalSecond(), range(), SECOND, SECS_PER_MINUTE, generate_unaccent_rules::str, strtoi64, strtoint(), pg_itm::tm_hour, pg_itm::tm_min, pg_itm::tm_sec, pg_itm::tm_usec, and USECS_PER_SEC.

Referenced by DecodeTime(), and DecodeTimeForInterval().

◆ DecodeTimeForInterval()

static int DecodeTimeForInterval ( char *  str,
int  fmask,
int  range,
int *  tmask,
struct pg_itm_in itm_in 
)
static

Definition at line 2692 of file datetime.c.

2694 {
2695  struct pg_itm itm;
2696  int dterr;
2697 
2698  dterr = DecodeTimeCommon(str, fmask, range,
2699  tmask, &itm);
2700  if (dterr)
2701  return dterr;
2702 
2703  itm_in->tm_usec = itm.tm_usec;
2704  if (!int64_multiply_add(itm.tm_hour, USECS_PER_HOUR, &itm_in->tm_usec) ||
2705  !int64_multiply_add(itm.tm_min, USECS_PER_MINUTE, &itm_in->tm_usec) ||
2706  !int64_multiply_add(itm.tm_sec, USECS_PER_SEC, &itm_in->tm_usec))
2707  return DTERR_FIELD_OVERFLOW;
2708 
2709  return 0;
2710 }

References DecodeTimeCommon(), DTERR_FIELD_OVERFLOW, int64_multiply_add(), range(), generate_unaccent_rules::str, pg_itm::tm_hour, pg_itm::tm_min, pg_itm::tm_sec, pg_itm::tm_usec, pg_itm_in::tm_usec, USECS_PER_HOUR, USECS_PER_MINUTE, and USECS_PER_SEC.

Referenced by DecodeInterval().

◆ DecodeTimeOnly()

int DecodeTimeOnly ( char **  field,
int *  ftype,
int  nf,
int *  dtype,
struct pg_tm tm,
fsec_t fsec,
int *  tzp,
DateTimeErrorExtra extra 
)

Definition at line 1866 of file datetime.c.

1869 {
1870  int fmask = 0,
1871  tmask,
1872  type;
1873  int ptype = 0; /* "prefix type" for ISO and Julian formats */
1874  int i;
1875  int val;
1876  int dterr;
1877  bool isjulian = false;
1878  bool is2digits = false;
1879  bool bc = false;
1880  int mer = HR24;
1881  pg_tz *namedTz = NULL;
1882  pg_tz *abbrevTz = NULL;
1883  char *abbrev = NULL;
1884  pg_tz *valtz;
1885 
1886  *dtype = DTK_TIME;
1887  tm->tm_hour = 0;
1888  tm->tm_min = 0;
1889  tm->tm_sec = 0;
1890  *fsec = 0;
1891  /* don't know daylight savings time status apriori */
1892  tm->tm_isdst = -1;
1893 
1894  if (tzp != NULL)
1895  *tzp = 0;
1896 
1897  for (i = 0; i < nf; i++)
1898  {
1899  switch (ftype[i])
1900  {
1901  case DTK_DATE:
1902 
1903  /*
1904  * Time zone not allowed? Then should not accept dates or time
1905  * zones no matter what else!
1906  */
1907  if (tzp == NULL)
1908  return DTERR_BAD_FORMAT;
1909 
1910  /* Under limited circumstances, we will accept a date... */
1911  if (i == 0 && nf >= 2 &&
1912  (ftype[nf - 1] == DTK_DATE || ftype[1] == DTK_TIME))
1913  {
1914  dterr = DecodeDate(field[i], fmask,
1915  &tmask, &is2digits, tm);
1916  if (dterr)
1917  return dterr;
1918  }
1919  /* otherwise, this is a time and/or time zone */
1920  else
1921  {
1922  if (isdigit((unsigned char) *field[i]))
1923  {
1924  char *cp;
1925 
1926  /*
1927  * Starts with a digit but we already have a time
1928  * field? Then we are in trouble with time already...
1929  */
1930  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1931  return DTERR_BAD_FORMAT;
1932 
1933  /*
1934  * Should not get here and fail. Sanity check only...
1935  */
1936  if ((cp = strchr(field[i], '-')) == NULL)
1937  return DTERR_BAD_FORMAT;
1938 
1939  /* Get the time zone from the end of the string */
1940  dterr = DecodeTimezone(cp, tzp);
1941  if (dterr)
1942  return dterr;
1943  *cp = '\0';
1944 
1945  /*
1946  * Then read the rest of the field as a concatenated
1947  * time
1948  */
1949  dterr = DecodeNumberField(strlen(field[i]), field[i],
1950  (fmask | DTK_DATE_M),
1951  &tmask, tm,
1952  fsec, &is2digits);
1953  if (dterr < 0)
1954  return dterr;
1955  ftype[i] = dterr;
1956 
1957  tmask |= DTK_M(TZ);
1958  }
1959  else
1960  {
1961  namedTz = pg_tzset(field[i]);
1962  if (!namedTz)
1963  {
1964  extra->dtee_timezone = field[i];
1965  return DTERR_BAD_TIMEZONE;
1966  }
1967  /* we'll apply the zone setting below */
1968  ftype[i] = DTK_TZ;
1969  tmask = DTK_M(TZ);
1970  }
1971  }
1972  break;
1973 
1974  case DTK_TIME:
1975  dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
1977  &tmask, tm, fsec);
1978  if (dterr)
1979  return dterr;
1980  break;
1981 
1982  case DTK_TZ:
1983  {
1984  int tz;
1985 
1986  if (tzp == NULL)
1987  return DTERR_BAD_FORMAT;
1988 
1989  dterr = DecodeTimezone(field[i], &tz);
1990  if (dterr)
1991  return dterr;
1992  *tzp = tz;
1993  tmask = DTK_M(TZ);
1994  }
1995  break;
1996 
1997  case DTK_NUMBER:
1998 
1999  /*
2000  * Deal with cases where previous field labeled this one
2001  */
2002  if (ptype != 0)
2003  {
2004  char *cp;
2005  int value;
2006 
2007  errno = 0;
2008  value = strtoint(field[i], &cp, 10);
2009  if (errno == ERANGE)
2010  return DTERR_FIELD_OVERFLOW;
2011  if (*cp != '.' && *cp != '\0')
2012  return DTERR_BAD_FORMAT;
2013 
2014  switch (ptype)
2015  {
2016  case DTK_JULIAN:
2017  /* previous field was a label for "julian date" */
2018  if (tzp == NULL)
2019  return DTERR_BAD_FORMAT;
2020  if (value < 0)
2021  return DTERR_FIELD_OVERFLOW;
2022  tmask = DTK_DATE_M;
2023  j2date(value, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2024  isjulian = true;
2025 
2026  if (*cp == '.')
2027  {
2028  double time;
2029 
2030  dterr = ParseFraction(cp, &time);
2031  if (dterr)
2032  return dterr;
2033  time *= USECS_PER_DAY;
2034  dt2time(time,
2035  &tm->tm_hour, &tm->tm_min,
2036  &tm->tm_sec, fsec);
2037  tmask |= DTK_TIME_M;
2038  }
2039  break;
2040 
2041  case DTK_TIME:
2042  /* previous field was "t" for ISO time */
2043  dterr = DecodeNumberField(strlen(field[i]), field[i],
2044  (fmask | DTK_DATE_M),
2045  &tmask, tm,
2046  fsec, &is2digits);
2047  if (dterr < 0)
2048  return dterr;
2049  ftype[i] = dterr;
2050 
2051  if (tmask != DTK_TIME_M)
2052  return DTERR_BAD_FORMAT;
2053  break;
2054 
2055  default:
2056  return DTERR_BAD_FORMAT;
2057  break;
2058  }
2059 
2060  ptype = 0;
2061  *dtype = DTK_DATE;
2062  }
2063  else
2064  {
2065  char *cp;
2066  int flen;
2067 
2068  flen = strlen(field[i]);
2069  cp = strchr(field[i], '.');
2070 
2071  /* Embedded decimal? */
2072  if (cp != NULL)
2073  {
2074  /*
2075  * Under limited circumstances, we will accept a
2076  * date...
2077  */
2078  if (i == 0 && nf >= 2 && ftype[nf - 1] == DTK_DATE)
2079  {
2080  dterr = DecodeDate(field[i], fmask,
2081  &tmask, &is2digits, tm);
2082  if (dterr)
2083  return dterr;
2084  }
2085  /* embedded decimal and several digits before? */
2086  else if (flen - strlen(cp) > 2)
2087  {
2088  /*
2089  * Interpret as a concatenated date or time Set
2090  * the type field to allow decoding other fields
2091  * later. Example: 20011223 or 040506
2092  */
2093  dterr = DecodeNumberField(flen, field[i],
2094  (fmask | DTK_DATE_M),
2095  &tmask, tm,
2096  fsec, &is2digits);
2097  if (dterr < 0)
2098  return dterr;
2099  ftype[i] = dterr;
2100  }
2101  else
2102  return DTERR_BAD_FORMAT;
2103  }
2104  else if (flen > 4)
2105  {
2106  dterr = DecodeNumberField(flen, field[i],
2107  (fmask | DTK_DATE_M),
2108  &tmask, tm,
2109  fsec, &is2digits);
2110  if (dterr < 0)
2111  return dterr;
2112  ftype[i] = dterr;
2113  }
2114  /* otherwise it is a single date/time field... */
2115  else
2116  {
2117  dterr = DecodeNumber(flen, field[i],
2118  false,
2119  (fmask | DTK_DATE_M),
2120  &tmask, tm,
2121  fsec, &is2digits);
2122  if (dterr)
2123  return dterr;
2124  }
2125  }
2126  break;
2127 
2128  case DTK_STRING:
2129  case DTK_SPECIAL:
2130  /* timezone abbrevs take precedence over built-in tokens */
2131  dterr = DecodeTimezoneAbbrev(i, field[i],
2132  &type, &val, &valtz, extra);
2133  if (dterr)
2134  return dterr;
2135  if (type == UNKNOWN_FIELD)
2136  type = DecodeSpecial(i, field[i], &val);
2137  if (type == IGNORE_DTF)
2138  continue;
2139 
2140  tmask = DTK_M(type);
2141  switch (type)
2142  {
2143  case RESERV:
2144  switch (val)
2145  {
2146  case DTK_NOW:
2147  tmask = DTK_TIME_M;
2148  *dtype = DTK_TIME;
2149  GetCurrentTimeUsec(tm, fsec, NULL);
2150  break;
2151 
2152  case DTK_ZULU:
2153  tmask = (DTK_TIME_M | DTK_M(TZ));
2154  *dtype = DTK_TIME;
2155  tm->tm_hour = 0;
2156  tm->tm_min = 0;
2157  tm->tm_sec = 0;
2158  tm->tm_isdst = 0;
2159  break;
2160 
2161  default:
2162  return DTERR_BAD_FORMAT;
2163  }
2164 
2165  break;
2166 
2167  case DTZMOD:
2168 
2169  /*
2170  * daylight savings time modifier (solves "MET DST"
2171  * syntax)
2172  */
2173  tmask |= DTK_M(DTZ);
2174  tm->tm_isdst = 1;
2175  if (tzp == NULL)
2176  return DTERR_BAD_FORMAT;
2177  *tzp -= val;
2178  break;
2179 
2180  case DTZ:
2181 
2182  /*
2183  * set mask for TZ here _or_ check for DTZ later when
2184  * getting default timezone
2185  */
2186  tmask |= DTK_M(TZ);
2187  tm->tm_isdst = 1;
2188  if (tzp == NULL)
2189  return DTERR_BAD_FORMAT;
2190  *tzp = -val;
2191  ftype[i] = DTK_TZ;
2192  break;
2193 
2194  case TZ:
2195  tm->tm_isdst = 0;
2196  if (tzp == NULL)
2197  return DTERR_BAD_FORMAT;
2198  *tzp = -val;
2199  ftype[i] = DTK_TZ;
2200  break;
2201 
2202  case DYNTZ:
2203  tmask |= DTK_M(TZ);
2204  if (tzp == NULL)
2205  return DTERR_BAD_FORMAT;
2206  /* we'll determine the actual offset later */
2207  abbrevTz = valtz;
2208  abbrev = field[i];
2209  ftype[i] = DTK_TZ;
2210  break;
2211 
2212  case AMPM:
2213  mer = val;
2214  break;
2215 
2216  case ADBC:
2217  bc = (val == BC);
2218  break;
2219 
2220  case UNITS:
2221  tmask = 0;
2222  /* reject consecutive unhandled units */
2223  if (ptype != 0)
2224  return DTERR_BAD_FORMAT;
2225  ptype = val;
2226  break;
2227 
2228  case ISOTIME:
2229  tmask = 0;
2230  /* reject consecutive unhandled units */
2231  if (ptype != 0)
2232  return DTERR_BAD_FORMAT;
2233  ptype = val;
2234  break;
2235 
2236  case UNKNOWN_FIELD:
2237 
2238  /*
2239  * Before giving up and declaring error, check to see
2240  * if it is an all-alpha timezone name.
2241  */
2242  namedTz = pg_tzset(field[i]);
2243  if (!namedTz)
2244  return DTERR_BAD_FORMAT;
2245  /* we'll apply the zone setting below */
2246  tmask = DTK_M(TZ);
2247  break;
2248 
2249  default:
2250  return DTERR_BAD_FORMAT;
2251  }
2252  break;
2253 
2254  default:
2255  return DTERR_BAD_FORMAT;
2256  }
2257 
2258  if (tmask & fmask)
2259  return DTERR_BAD_FORMAT;
2260  fmask |= tmask;
2261  } /* end loop over fields */
2262 
2263  /* reject if prefix type appeared and was never handled */
2264  if (ptype != 0)
2265  return DTERR_BAD_FORMAT;
2266 
2267  /* do final checking/adjustment of Y/M/D fields */
2268  dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
2269  if (dterr)
2270  return dterr;
2271 
2272  /* handle AM/PM */
2273  if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
2274  return DTERR_FIELD_OVERFLOW;
2275  if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
2276  tm->tm_hour = 0;
2277  else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
2278  tm->tm_hour += HOURS_PER_DAY / 2;
2279 
2280  /* check for time overflow */
2281  if (time_overflows(tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec))
2282  return DTERR_FIELD_OVERFLOW;
2283 
2284  if ((fmask & DTK_TIME_M) != DTK_TIME_M)
2285  return DTERR_BAD_FORMAT;
2286 
2287  /*
2288  * If we had a full timezone spec, compute the offset (we could not do it
2289  * before, because we may need the date to resolve DST status).
2290  */
2291  if (namedTz != NULL)
2292  {
2293  long int gmtoff;
2294 
2295  /* daylight savings time modifier disallowed with full TZ */
2296  if (fmask & DTK_M(DTZMOD))
2297  return DTERR_BAD_FORMAT;
2298 
2299  /* if non-DST zone, we do not need to know the date */
2300  if (pg_get_timezone_offset(namedTz, &gmtoff))
2301  {
2302  *tzp = -(int) gmtoff;
2303  }
2304  else
2305  {
2306  /* a date has to be specified */
2307  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2308  return DTERR_BAD_FORMAT;
2309  *tzp = DetermineTimeZoneOffset(tm, namedTz);
2310  }
2311  }
2312 
2313  /*
2314  * Likewise, if we had a dynamic timezone abbreviation, resolve it now.
2315  */
2316  if (abbrevTz != NULL)
2317  {
2318  struct pg_tm tt,
2319  *tmp = &tt;
2320 
2321  /*
2322  * daylight savings time modifier but no standard timezone? then error
2323  */
2324  if (fmask & DTK_M(DTZMOD))
2325  return DTERR_BAD_FORMAT;
2326 
2327  if ((fmask & DTK_DATE_M) == 0)
2328  GetCurrentDateTime(tmp);
2329  else
2330  {
2331  /* a date has to be specified */
2332  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2333  return DTERR_BAD_FORMAT;
2334  tmp->tm_year = tm->tm_year;
2335  tmp->tm_mon = tm->tm_mon;
2336  tmp->tm_mday = tm->tm_mday;
2337  }
2338  tmp->tm_hour = tm->tm_hour;
2339  tmp->tm_min = tm->tm_min;
2340  tmp->tm_sec = tm->tm_sec;
2341  *tzp = DetermineTimeZoneAbbrevOffset(tmp, abbrev, abbrevTz);
2342  tm->tm_isdst = tmp->tm_isdst;
2343  }
2344 
2345  /* timezone not specified? then use session timezone */
2346  if (tzp != NULL && !(fmask & DTK_M(TZ)))
2347  {
2348  struct pg_tm tt,
2349  *tmp = &tt;
2350 
2351  /*
2352  * daylight savings time modifier but no standard timezone? then error
2353  */
2354  if (fmask & DTK_M(DTZMOD))
2355  return DTERR_BAD_FORMAT;
2356 
2357  if ((fmask & DTK_DATE_M) == 0)
2358  GetCurrentDateTime(tmp);
2359  else
2360  {
2361  /* a date has to be specified */
2362  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2363  return DTERR_BAD_FORMAT;
2364  tmp->tm_year = tm->tm_year;
2365  tmp->tm_mon = tm->tm_mon;
2366  tmp->tm_mday = tm->tm_mday;
2367  }
2368  tmp->tm_hour = tm->tm_hour;
2369  tmp->tm_min = tm->tm_min;
2370  tmp->tm_sec = tm->tm_sec;
2372  tm->tm_isdst = tmp->tm_isdst;
2373  }
2374 
2375  return 0;
2376 }
bool pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff)
Definition: localtime.c:1851

References ADBC, AM, AMPM, BC, DecodeDate(), DecodeNumber(), DecodeNumberField(), DecodeSpecial(), DecodeTime(), DecodeTimezone(), DecodeTimezoneAbbrev(), DetermineTimeZoneAbbrevOffset(), DetermineTimeZoneOffset(), dt2time(), DateTimeErrorExtra::dtee_timezone, DTERR_BAD_FORMAT, DTERR_BAD_TIMEZONE, DTERR_FIELD_OVERFLOW, DTK_DATE, DTK_DATE_M, DTK_JULIAN, DTK_M, DTK_NOW, DTK_NUMBER, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TIME_M, DTK_TZ, DTK_ZULU, DTZ, DTZMOD, DYNTZ, GetCurrentDateTime(), GetCurrentTimeUsec(), HOURS_PER_DAY, HR24, i, IGNORE_DTF, INTERVAL_FULL_RANGE, ISOTIME, j2date(), ParseFraction(), pg_get_timezone_offset(), pg_tzset(), PM, RESERV, session_timezone, strtoint(), time_overflows(), tm, 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, type, TZ, UNITS, UNKNOWN_FIELD, USECS_PER_DAY, val, ValidateDate(), and value.

Referenced by time_in(), and timetz_in().

◆ DecodeTimezone()

int DecodeTimezone ( const char *  str,
int *  tzp 
)

Definition at line 2998 of file datetime.c.

2999 {
3000  int tz;
3001  int hr,
3002  min,
3003  sec = 0;
3004  char *cp;
3005 
3006  /* leading character must be "+" or "-" */
3007  if (*str != '+' && *str != '-')
3008  return DTERR_BAD_FORMAT;
3009 
3010  errno = 0;
3011  hr = strtoint(str + 1, &cp, 10);
3012  if (errno == ERANGE)
3013  return DTERR_TZDISP_OVERFLOW;
3014 
3015  /* explicit delimiter? */
3016  if (*cp == ':')
3017  {
3018  errno = 0;
3019  min = strtoint(cp + 1, &cp, 10);
3020  if (errno == ERANGE)
3021  return DTERR_TZDISP_OVERFLOW;
3022  if (*cp == ':')
3023  {
3024  errno = 0;
3025  sec = strtoint(cp + 1, &cp, 10);
3026  if (errno == ERANGE)
3027  return DTERR_TZDISP_OVERFLOW;
3028  }
3029  }
3030  /* otherwise, might have run things together... */
3031  else if (*cp == '\0' && strlen(str) > 3)
3032  {
3033  min = hr % 100;
3034  hr = hr / 100;
3035  /* we could, but don't, support a run-together hhmmss format */
3036  }
3037  else
3038  min = 0;
3039 
3040  /* Range-check the values; see notes in datatype/timestamp.h */
3041  if (hr < 0 || hr > MAX_TZDISP_HOUR)
3042  return DTERR_TZDISP_OVERFLOW;
3043  if (min < 0 || min >= MINS_PER_HOUR)
3044  return DTERR_TZDISP_OVERFLOW;
3045  if (sec < 0 || sec >= SECS_PER_MINUTE)
3046  return DTERR_TZDISP_OVERFLOW;
3047 
3048  tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec;
3049  if (*str == '-')
3050  tz = -tz;
3051 
3052  *tzp = -tz;
3053 
3054  if (*cp != '\0')
3055  return DTERR_BAD_FORMAT;
3056 
3057  return 0;
3058 }
#define MAX_TZDISP_HOUR
Definition: timestamp.h:142

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

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

◆ DecodeTimezoneAbbrev()

int DecodeTimezoneAbbrev ( int  field,
const char *  lowtoken,
int *  ftype,
int *  offset,
pg_tz **  tz,
DateTimeErrorExtra extra 
)

Definition at line 3082 of file datetime.c.

3085 {
3086  const datetkn *tp;
3087 
3088  tp = abbrevcache[field];
3089  /* use strncmp so that we match truncated tokens */
3090  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3091  {
3092  if (zoneabbrevtbl)
3093  tp = datebsearch(lowtoken, zoneabbrevtbl->abbrevs,
3095  else
3096  tp = NULL;
3097  }
3098  if (tp == NULL)
3099  {
3100  *ftype = UNKNOWN_FIELD;
3101  *offset = 0;
3102  *tz = NULL;
3103  }
3104  else
3105  {
3106  abbrevcache[field] = tp;
3107  *ftype = tp->type;
3108  if (tp->type == DYNTZ)
3109  {
3110  *offset = 0;
3111  *tz = FetchDynamicTimeZone(zoneabbrevtbl, tp, extra);
3112  if (*tz == NULL)
3113  return DTERR_BAD_ZONE_ABBREV;
3114  }
3115  else
3116  {
3117  *offset = tp->value;
3118  *tz = NULL;
3119  }
3120  }
3121 
3122  return 0;
3123 }
static const datetkn * abbrevcache[MAXDATEFIELDS]
Definition: datetime.c:264
static TimeZoneAbbrevTable * zoneabbrevtbl
Definition: datetime.c:256
static pg_tz * FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp, DateTimeErrorExtra *extra)
Definition: datetime.c:4859

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

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

◆ DecodeTimezoneName()

int DecodeTimezoneName ( const char *  tzname,
int *  offset,
pg_tz **  tz 
)

Definition at line 3181 of file datetime.c.

3182 {
3183  char *lowzone;
3184  int dterr,
3185  type;
3186  DateTimeErrorExtra extra;
3187 
3188  /*
3189  * First we look in the timezone abbreviation table (to handle cases like
3190  * "EST"), and if that fails, we look in the timezone database (to handle
3191  * cases like "America/New_York"). This matches the order in which
3192  * timestamp input checks the cases; it's important because the timezone
3193  * database unwisely uses a few zone names that are identical to offset
3194  * abbreviations.
3195  */
3196 
3197  /* DecodeTimezoneAbbrev requires lowercase input */
3198  lowzone = downcase_truncate_identifier(tzname,
3199  strlen(tzname),
3200  false);
3201 
3202  dterr = DecodeTimezoneAbbrev(0, lowzone, &type, offset, tz, &extra);
3203  if (dterr)
3204  DateTimeParseError(dterr, &extra, NULL, NULL, NULL);
3205 
3206  if (type == TZ || type == DTZ)
3207  {
3208  /* fixed-offset abbreviation, return the offset */
3209  return TZNAME_FIXED_OFFSET;
3210  }
3211  else if (type == DYNTZ)
3212  {
3213  /* dynamic-offset abbreviation, return its referenced timezone */
3214  return TZNAME_DYNTZ;
3215  }
3216  else
3217  {
3218  /* try it as a full zone name */
3219  *tz = pg_tzset(tzname);
3220  if (*tz == NULL)
3221  ereport(ERROR,
3222  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3223  errmsg("time zone \"%s\" not recognized", tzname)));
3224  return TZNAME_ZONE;
3225  }
3226 }
void DateTimeParseError(int dterr, DateTimeErrorExtra *extra, const char *str, const char *datatype, Node *escontext)
Definition: datetime.c:3981
#define ereport(elevel,...)
Definition: elog.h:149
#define TZNAME_ZONE
Definition: datetime.h:301
#define TZNAME_FIXED_OFFSET
Definition: datetime.h:299
#define TZNAME_DYNTZ
Definition: datetime.h:300
char * downcase_truncate_identifier(const char *ident, int len, bool warn)
Definition: scansup.c:37

References DateTimeParseError(), DecodeTimezoneAbbrev(), downcase_truncate_identifier(), DTZ, DYNTZ, ereport, errcode(), errmsg(), ERROR, pg_tzset(), type, TZ, TZNAME_DYNTZ, TZNAME_FIXED_OFFSET, and TZNAME_ZONE.

Referenced by DecodeTimezoneNameToTz(), parse_sane_timezone(), timestamp_zone(), timestamptz_zone(), and timetz_zone().

◆ DecodeTimezoneNameToTz()

pg_tz* DecodeTimezoneNameToTz ( const char *  tzname)

Definition at line 3236 of file datetime.c.

3237 {
3238  pg_tz *result;
3239  int offset;
3240 
3241  if (DecodeTimezoneName(tzname, &offset, &result) == TZNAME_FIXED_OFFSET)
3242  {
3243  /* fixed-offset abbreviation, get a pg_tz descriptor for that */
3244  result = pg_tzset_offset(-offset); /* flip to POSIX sign convention */
3245  }
3246  return result;
3247 }
int DecodeTimezoneName(const char *tzname, int *offset, pg_tz **tz)
Definition: datetime.c:3181
pg_tz * pg_tzset_offset(long gmtoffset)
Definition: pgtz.c:320

References DecodeTimezoneName(), pg_tzset_offset(), and TZNAME_FIXED_OFFSET.

Referenced by lookup_timezone().

◆ DecodeUnits()

int DecodeUnits ( int  field,
const char *  lowtoken,
int *  val 
)

Definition at line 3936 of file datetime.c.

3937 {
3938  int type;
3939  const datetkn *tp;
3940 
3941  tp = deltacache[field];
3942  /* use strncmp so that we match truncated tokens */
3943  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3944  {
3945  tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
3946  }
3947  if (tp == NULL)
3948  {
3949  type = UNKNOWN_FIELD;
3950  *val = 0;
3951  }
3952  else
3953  {
3954  deltacache[field] = tp;
3955  type = tp->type;
3956  *val = tp->value;
3957  }
3958 
3959  return type;
3960 } /* DecodeUnits() */
static const datetkn * deltacache[MAXDATEFIELDS]
Definition: datetime.c:262

References datebsearch(), deltacache, deltatktbl, szdeltatktbl, datetkn::token, TOKMAXLEN, type, datetkn::type, UNKNOWN_FIELD, val, and datetkn::value.

Referenced by DecodeInterval(), extract_date(), interval_part_common(), interval_trunc(), time_part_common(), timestamp_part_common(), timestamp_trunc(), timestamptz_part_common(), timestamptz_trunc_internal(), and timetz_part_common().

◆ DetermineTimeZoneAbbrevOffset()

int DetermineTimeZoneAbbrevOffset ( struct pg_tm tm,
const char *  abbr,
pg_tz tzp 
)

Definition at line 1748 of file datetime.c.

1749 {
1750  pg_time_t t;
1751  int zone_offset;
1752  int abbr_offset;
1753  int abbr_isdst;
1754 
1755  /*
1756  * Compute the UTC time we want to probe at. (In event of overflow, we'll
1757  * probe at the epoch, which is a bit random but probably doesn't matter.)
1758  */
1759  zone_offset = DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1760 
1761  /*
1762  * Try to match the abbreviation to something in the zone definition.
1763  */
1764  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1765  &abbr_offset, &abbr_isdst))
1766  {
1767  /* Success, so use the abbrev-specific answers. */
1768  tm->tm_isdst = abbr_isdst;
1769  return abbr_offset;
1770  }
1771 
1772  /*
1773  * No match, so use the answers we already got from
1774  * DetermineTimeZoneOffsetInternal.
1775  */
1776  return zone_offset;
1777 }
static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp, pg_time_t *tp)
Definition: datetime.c:1609
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, int *offset, int *isdst)
Definition: datetime.c:1823
int64 pg_time_t
Definition: pgtime.h:23

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

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

◆ DetermineTimeZoneAbbrevOffsetInternal()

static bool DetermineTimeZoneAbbrevOffsetInternal ( pg_time_t  t,
const char *  abbr,
pg_tz tzp,
int *  offset,
int *  isdst 
)
static

Definition at line 1823 of file datetime.c.

1825 {
1826  char upabbr[TZ_STRLEN_MAX + 1];
1827  unsigned char *p;
1828  long int gmtoff;
1829 
1830  /* We need to force the abbrev to upper case */
1831  strlcpy(upabbr, abbr, sizeof(upabbr));
1832  for (p = (unsigned char *) upabbr; *p; p++)
1833  *p = pg_toupper(*p);
1834 
1835  /* Look up the abbrev's meaning at this time in this zone */
1836  if (pg_interpret_timezone_abbrev(upabbr,
1837  &t,
1838  &gmtoff,
1839  isdst,
1840  tzp))
1841  {
1842  /* Change sign to agree with DetermineTimeZoneOffset() */
1843  *offset = (int) -gmtoff;
1844  return true;
1845  }
1846  return false;
1847 }
#define TZ_STRLEN_MAX
Definition: pgtime.h:54
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:1757
unsigned char pg_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:105

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

Referenced by DetermineTimeZoneAbbrevOffset(), and DetermineTimeZoneAbbrevOffsetTS().

◆ DetermineTimeZoneAbbrevOffsetTS()

int DetermineTimeZoneAbbrevOffsetTS ( TimestampTz  ts,
const char *  abbr,
pg_tz tzp,
int *  isdst 
)

Definition at line 1786 of file datetime.c.

1788 {
1790  int zone_offset;
1791  int abbr_offset;
1792  int tz;
1793  struct pg_tm tm;
1794  fsec_t fsec;
1795 
1796  /*
1797  * If the abbrev matches anything in the zone data, this is pretty easy.
1798  */
1799  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1800  &abbr_offset, isdst))
1801  return abbr_offset;
1802 
1803  /*
1804  * Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1805  */
1806  if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0)
1807  ereport(ERROR,
1808  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1809  errmsg("timestamp out of range")));
1810 
1811  zone_offset = DetermineTimeZoneOffset(&tm, tzp);
1812  *isdst = tm.tm_isdst;
1813  return zone_offset;
1814 }
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1830
pg_time_t timestamptz_to_time_t(TimestampTz t)
Definition: timestamp.c:1762

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

Referenced by pg_timezone_abbrevs(), timestamptz_zone(), and timetz_zone().

◆ DetermineTimeZoneOffset()

◆ DetermineTimeZoneOffsetInternal()

static int DetermineTimeZoneOffsetInternal ( struct pg_tm tm,
pg_tz tzp,
pg_time_t tp 
)
static

Definition at line 1609 of file datetime.c.

1610 {
1611  int date,
1612  sec;
1613  pg_time_t day,
1614  mytime,
1615  prevtime,
1616  boundary,
1617  beforetime,
1618  aftertime;
1619  long int before_gmtoff,
1620  after_gmtoff;
1621  int before_isdst,
1622  after_isdst;
1623  int res;
1624 
1625  /*
1626  * First, generate the pg_time_t value corresponding to the given
1627  * y/m/d/h/m/s taken as GMT time. If this overflows, punt and decide the
1628  * timezone is GMT. (For a valid Julian date, integer overflow should be
1629  * impossible with 64-bit pg_time_t, but let's check for safety.)
1630  */
1632  goto overflow;
1634 
1635  day = ((pg_time_t) date) * SECS_PER_DAY;
1636  if (day / SECS_PER_DAY != date)
1637  goto overflow;
1639  mytime = day + sec;
1640  /* since sec >= 0, overflow could only be from +day to -mytime */
1641  if (mytime < 0 && day > 0)
1642  goto overflow;
1643 
1644  /*
1645  * Find the DST time boundary just before or following the target time. We
1646  * assume that all zones have GMT offsets less than 24 hours, and that DST
1647  * boundaries can't be closer together than 48 hours, so backing up 24
1648  * hours and finding the "next" boundary will work.
1649  */
1650  prevtime = mytime - SECS_PER_DAY;
1651  if (mytime < 0 && prevtime > 0)
1652  goto overflow;
1653 
1654  res = pg_next_dst_boundary(&prevtime,
1655  &before_gmtoff, &before_isdst,
1656  &boundary,
1657  &after_gmtoff, &after_isdst,
1658  tzp);
1659  if (res < 0)
1660  goto overflow; /* failure? */
1661 
1662  if (res == 0)
1663  {
1664  /* Non-DST zone, life is simple */
1665  tm->tm_isdst = before_isdst;
1666  *tp = mytime - before_gmtoff;
1667  return -(int) before_gmtoff;
1668  }
1669 
1670  /*
1671  * Form the candidate pg_time_t values with local-time adjustment
1672  */
1673  beforetime = mytime - before_gmtoff;
1674  if ((before_gmtoff > 0 &&
1675  mytime < 0 && beforetime > 0) ||
1676  (before_gmtoff <= 0 &&
1677  mytime > 0 && beforetime < 0))
1678  goto overflow;
1679  aftertime = mytime - after_gmtoff;
1680  if ((after_gmtoff > 0 &&
1681  mytime < 0 && aftertime > 0) ||
1682  (after_gmtoff <= 0 &&
1683  mytime > 0 && aftertime < 0))
1684  goto overflow;
1685 
1686  /*
1687  * If both before or both after the boundary time, we know what to do. The
1688  * boundary time itself is considered to be after the transition, which
1689  * means we can accept aftertime == boundary in the second case.
1690  */
1691  if (beforetime < boundary && aftertime < boundary)
1692  {
1693  tm->tm_isdst = before_isdst;
1694  *tp = beforetime;
1695  return -(int) before_gmtoff;
1696  }
1697  if (beforetime > boundary && aftertime >= boundary)
1698  {
1699  tm->tm_isdst = after_isdst;
1700  *tp = aftertime;
1701  return -(int) after_gmtoff;
1702  }
1703 
1704  /*
1705  * It's an invalid or ambiguous time due to timezone transition. In a
1706  * spring-forward transition, prefer the "before" interpretation; in a
1707  * fall-back transition, prefer "after". (We used to define and implement
1708  * this test as "prefer the standard-time interpretation", but that rule
1709  * does not help to resolve the behavior when both times are reported as
1710  * standard time; which does happen, eg Europe/Moscow in Oct 2014. Also,
1711  * in some zones such as Europe/Dublin, there is widespread confusion
1712  * about which time offset is "standard" time, so it's fortunate that our
1713  * behavior doesn't depend on that.)
1714  */
1715  if (beforetime > aftertime)
1716  {
1717  tm->tm_isdst = before_isdst;
1718  *tp = beforetime;
1719  return -(int) before_gmtoff;
1720  }
1721  tm->tm_isdst = after_isdst;
1722  *tp = aftertime;
1723  return -(int) after_gmtoff;
1724 
1725 overflow:
1726  /* Given date is out of range, so assume UTC */
1727  tm->tm_isdst = 0;
1728  *tp = 0;
1729  return 0;
1730 }
#define IS_VALID_JULIAN(y, m, d)
Definition: timestamp.h:201
#define SECS_PER_DAY
Definition: timestamp.h:125
int pg_next_dst_boundary(const pg_time_t *timep, long int *before_gmtoff, int *before_isdst, pg_time_t *boundary, long int *after_gmtoff, int *after_isdst, const pg_tz *tz)
Definition: localtime.c:1610
long date
Definition: pgtypes_date.h:9

References date2j(), IS_VALID_JULIAN, MINS_PER_HOUR, pg_next_dst_boundary(), res, SECS_PER_DAY, SECS_PER_MINUTE, tm, 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().

◆ EncodeDateOnly()

void EncodeDateOnly ( struct pg_tm tm,
int  style,
char *  str 
)

Definition at line 4116 of file datetime.c.

4117 {
4118  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
4119 
4120  switch (style)
4121  {
4122  case USE_ISO_DATES:
4123  case USE_XSD_DATES:
4124  /* compatible with ISO date formats */
4126  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4127  *str++ = '-';
4129  *str++ = '-';
4131  break;
4132 
4133  case USE_SQL_DATES:
4134  /* compatible with Oracle/Ingres date formats */
4135  if (DateOrder == DATEORDER_DMY)
4136  {
4138  *str++ = '/';
4140  }
4141  else
4142  {
4144  *str++ = '/';
4146  }
4147  *str++ = '/';
4149  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4150  break;
4151 
4152  case USE_GERMAN_DATES:
4153  /* German-style date format */
4155  *str++ = '.';
4157  *str++ = '.';
4159  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4160  break;
4161 
4162  case USE_POSTGRES_DATES:
4163  default:
4164  /* traditional date-only style for Postgres */
4165  if (DateOrder == DATEORDER_DMY)
4166  {
4168  *str++ = '-';
4170  }
4171  else
4172  {
4174  *str++ = '-';
4176  }
4177  *str++ = '-';
4179  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4180  break;
4181  }
4182 
4183  if (tm->tm_year <= 0)
4184  {
4185  memcpy(str, " BC", 3); /* Don't copy NUL */
4186  str += 3;
4187  }
4188  *str = '\0';
4189 }
#define USE_SQL_DATES
Definition: miscadmin.h:231
#define USE_POSTGRES_DATES
Definition: miscadmin.h:229
#define USE_ISO_DATES
Definition: miscadmin.h:230
#define USE_XSD_DATES
Definition: miscadmin.h:233
#define USE_GERMAN_DATES
Definition: miscadmin.h:232

References Assert(), DateOrder, DATEORDER_DMY, MONTHS_PER_YEAR, pg_ultostr_zeropad(), generate_unaccent_rules::str, tm, 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(), JsonEncodeDateTime(), map_sql_value_to_xml_value(), and PGTYPESdate_to_asc().

◆ EncodeDateTime()

void EncodeDateTime ( struct pg_tm tm,
fsec_t  fsec,
bool  print_tz,
int  tz,
const char *  tzn,
int  style,
char *  str 
)

Definition at line 4231 of file datetime.c.

4232 {
4233  int day;
4234 
4235  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
4236 
4237  /*
4238  * Negative tm_isdst means we have no valid time zone translation.
4239  */
4240  if (tm->tm_isdst < 0)
4241  print_tz = false;
4242 
4243  switch (style)
4244  {
4245  case USE_ISO_DATES:
4246  case USE_XSD_DATES:
4247  /* Compatible with ISO-8601 date formats */
4249  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4250  *str++ = '-';
4252  *str++ = '-';
4254  *str++ = (style == USE_ISO_DATES) ? ' ' : 'T';
4256  *str++ = ':';
4258  *str++ = ':';
4259  str = AppendTimestampSeconds(str, tm, fsec);
4260  if (print_tz)
4261  str = EncodeTimezone(str, tz, style);
4262  break;
4263 
4264  case USE_SQL_DATES:
4265  /* Compatible with Oracle/Ingres date formats */
4266  if (DateOrder == DATEORDER_DMY)
4267  {
4269  *str++ = '/';
4271  }
4272  else
4273  {
4275  *str++ = '/';
4277  }
4278  *str++ = '/';
4280  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4281  *str++ = ' ';
4283  *str++ = ':';
4285  *str++ = ':';
4286  str = AppendTimestampSeconds(str, tm, fsec);
4287 
4288  /*
4289  * Note: the uses of %.*s in this function would be risky if the
4290  * timezone names ever contain non-ASCII characters, since we are
4291  * not being careful to do encoding-aware clipping. However, all
4292  * TZ abbreviations in the IANA database are plain ASCII.
4293  */
4294  if (print_tz)
4295  {
4296  if (tzn)
4297  {
4298  sprintf(str, " %.*s", MAXTZLEN, tzn);
4299  str += strlen(str);
4300  }
4301  else
4302  str = EncodeTimezone(str, tz, style);
4303  }
4304  break;
4305 
4306  case USE_GERMAN_DATES:
4307  /* German variant on European style */
4309  *str++ = '.';
4311  *str++ = '.';
4313  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4314  *str++ = ' ';
4316  *str++ = ':';
4318  *str++ = ':';
4319  str = AppendTimestampSeconds(str, tm, fsec);
4320 
4321  if (print_tz)
4322  {
4323  if (tzn)
4324  {
4325  sprintf(str, " %.*s", MAXTZLEN, tzn);
4326  str += strlen(str);
4327  }
4328  else
4329  str = EncodeTimezone(str, tz, style);
4330  }
4331  break;
4332 
4333  case USE_POSTGRES_DATES:
4334  default:
4335  /* Backward-compatible with traditional Postgres abstime dates */
4336  day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4337  tm->tm_wday = j2day(day);
4338  memcpy(str, days[tm->tm_wday], 3);
4339  str += 3;
4340  *str++ = ' ';
4341  if (DateOrder == DATEORDER_DMY)
4342  {
4344  *str++ = ' ';
4345  memcpy(str, months[tm->tm_mon - 1], 3);
4346  str += 3;
4347  }
4348  else
4349  {
4350  memcpy(str, months[tm->tm_mon - 1], 3);
4351  str += 3;
4352  *str++ = ' ';
4354  }
4355  *str++ = ' ';
4357  *str++ = ':';
4359  *str++ = ':';
4360  str = AppendTimestampSeconds(str, tm, fsec);
4361  *str++ = ' ';
4363  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4364 
4365  if (print_tz)
4366  {
4367  if (tzn)
4368  {
4369  sprintf(str, " %.*s", MAXTZLEN, tzn);
4370  str += strlen(str);
4371  }
4372  else
4373  {
4374  /*
4375  * We have a time zone, but no string version. Use the
4376  * numeric form, but be sure to include a leading space to
4377  * avoid formatting something which would be rejected by
4378  * the date/time parser later. - thomas 2001-10-19
4379  */
4380  *str++ = ' ';
4381  str = EncodeTimezone(str, tz, style);
4382  }
4383  }
4384  break;
4385  }
4386 
4387  if (tm->tm_year <= 0)
4388  {
4389  memcpy(str, " BC", 3); /* Don't copy NUL */
4390  str += 3;
4391  }
4392  *str = '\0';
4393 }
static char * EncodeTimezone(char *str, int tz, int style)
Definition: datetime.c:4078
int j2day(int date)
Definition: datetime.c:346
const char *const months[]
Definition: datetime.c:83
static char * AppendTimestampSeconds(char *cp, struct pg_tm *tm, fsec_t fsec)
Definition: datetime.c:513
#define MAXTZLEN
Definition: miscadmin.h:257

References AppendTimestampSeconds(), Assert(), date2j(), DateOrder, DATEORDER_DMY, days, EncodeTimezone(), j2day(), MAXTZLEN, months, MONTHS_PER_YEAR, pg_ultostr_zeropad(), sprintf, generate_unaccent_rules::str, tm, 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 JsonEncodeDateTime(), map_sql_value_to_xml_value(), PGTYPEStimestamp_to_asc(), timestamp_out(), timestamptz_out(), and timestamptz_to_str().

◆ EncodeInterval()

void EncodeInterval ( struct pg_itm itm,
int  style,
char *  str 
)

Definition at line 4474 of file datetime.c.

4475 {
4476  char *cp = str;
4477  int year = itm->tm_year;
4478  int mon = itm->tm_mon;
4479  int64 mday = itm->tm_mday; /* tm_mday could be INT_MIN */
4480  int64 hour = itm->tm_hour;
4481  int min = itm->tm_min;
4482  int sec = itm->tm_sec;
4483  int fsec = itm->tm_usec;
4484  bool is_before = false;
4485  bool is_zero = true;
4486 
4487  /*
4488  * The sign of year and month are guaranteed to match, since they are
4489  * stored internally as "month". But we'll need to check for is_before and
4490  * is_zero when determining the signs of day and hour/minute/seconds
4491  * fields.
4492  */
4493  switch (style)
4494  {
4495  /* SQL Standard interval format */
4496  case INTSTYLE_SQL_STANDARD:
4497  {
4498  bool has_negative = year < 0 || mon < 0 ||
4499  mday < 0 || hour < 0 ||
4500  min < 0 || sec < 0 || fsec < 0;
4501  bool has_positive = year > 0 || mon > 0 ||
4502  mday > 0 || hour > 0 ||
4503  min > 0 || sec > 0 || fsec > 0;
4504  bool has_year_month = year != 0 || mon != 0;
4505  bool has_day_time = mday != 0 || hour != 0 ||
4506  min != 0 || sec != 0 || fsec != 0;
4507  bool has_day = mday != 0;
4508  bool sql_standard_value = !(has_negative && has_positive) &&
4509  !(has_year_month && has_day_time);
4510 
4511  /*
4512  * SQL Standard wants only 1 "<sign>" preceding the whole
4513  * interval ... but can't do that if mixed signs.
4514  */
4515  if (has_negative && sql_standard_value)
4516  {
4517  *cp++ = '-';
4518  year = -year;
4519  mon = -mon;
4520  mday = -mday;
4521  hour = -hour;
4522  min = -min;
4523  sec = -sec;
4524  fsec = -fsec;
4525  }
4526 
4527  if (!has_negative && !has_positive)
4528  {
4529  sprintf(cp, "0");
4530  }
4531  else if (!sql_standard_value)
4532  {
4533  /*
4534  * For non sql-standard interval values, force outputting
4535  * the signs to avoid ambiguities with intervals with
4536  * mixed sign components.
4537  */
4538  char year_sign = (year < 0 || mon < 0) ? '-' : '+';
4539  char day_sign = (mday < 0) ? '-' : '+';
4540  char sec_sign = (hour < 0 || min < 0 ||
4541  sec < 0 || fsec < 0) ? '-' : '+';
4542 
4543  sprintf(cp, "%c%d-%d %c%lld %c%lld:%02d:",
4544  year_sign, abs(year), abs(mon),
4545  day_sign, (long long) i64abs(mday),
4546  sec_sign, (long long) i64abs(hour), abs(min));
4547  cp += strlen(cp);
4548  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4549  *cp = '\0';
4550  }
4551  else if (has_year_month)
4552  {
4553  sprintf(cp, "%d-%d", year, mon);
4554  }
4555  else if (has_day)
4556  {
4557  sprintf(cp, "%lld %lld:%02d:",
4558  (long long) mday, (long long) hour, min);
4559  cp += strlen(cp);
4560  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4561  *cp = '\0';
4562  }
4563  else
4564  {
4565  sprintf(cp, "%lld:%02d:", (long long) hour, min);
4566  cp += strlen(cp);
4567  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4568  *cp = '\0';
4569  }
4570  }
4571  break;
4572 
4573  /* ISO 8601 "time-intervals by duration only" */
4574  case INTSTYLE_ISO_8601:
4575  /* special-case zero to avoid printing nothing */
4576  if (year == 0 && mon == 0 && mday == 0 &&
4577  hour == 0 && min == 0 && sec == 0 && fsec == 0)
4578  {
4579  sprintf(cp, "PT0S");
4580  break;
4581  }
4582  *cp++ = 'P';
4583  cp = AddISO8601IntPart(cp, year, 'Y');
4584  cp = AddISO8601IntPart(cp, mon, 'M');
4585  cp = AddISO8601IntPart(cp, mday, 'D');
4586  if (hour != 0 || min != 0 || sec != 0 || fsec != 0)
4587  *cp++ = 'T';
4588  cp = AddISO8601IntPart(cp, hour, 'H');
4589  cp = AddISO8601IntPart(cp, min, 'M');
4590  if (sec != 0 || fsec != 0)
4591  {
4592  if (sec < 0 || fsec < 0)
4593  *cp++ = '-';
4594  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4595  *cp++ = 'S';
4596  *cp++ = '\0';
4597  }
4598  break;
4599 
4600  /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
4601  case INTSTYLE_POSTGRES:
4602  cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before);
4603 
4604  /*
4605  * Ideally we should spell out "month" like we do for "year" and
4606  * "day". However, for backward compatibility, we can't easily
4607  * fix this. bjm 2011-05-24
4608  */
4609  cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before);
4610  cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before);
4611  if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0)
4612  {
4613  bool minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
4614 
4615  sprintf(cp, "%s%s%02lld:%02d:",
4616  is_zero ? "" : " ",
4617  (minus ? "-" : (is_before ? "+" : "")),
4618  (long long) i64abs(hour), abs(min));
4619  cp += strlen(cp);
4620  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4621  *cp = '\0';
4622  }
4623  break;
4624 
4625  /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
4627  default:
4628  strcpy(cp, "@");
4629  cp++;
4630  cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
4631  cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
4632  cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
4633  cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
4634  cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
4635  if (sec != 0 || fsec != 0)
4636  {
4637  *cp++ = ' ';
4638  if (sec < 0 || (sec == 0 && fsec < 0))
4639  {
4640  if (is_zero)
4641  is_before = true;
4642  else if (!is_before)
4643  *cp++ = '-';
4644  }
4645  else if (is_before)
4646  *cp++ = '-';
4647  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4648  /* We output "ago", not negatives, so use abs(). */
4649  sprintf(cp, " sec%s",
4650  (abs(sec) != 1 || fsec != 0) ? "s" : "");
4651  is_zero = false;
4652  }
4653  /* identically zero? then put in a unitless zero... */
4654  if (is_zero)
4655  strcat(cp, " 0");
4656  if (is_before)
4657  strcat(cp, " ago");
4658  break;
4659  }
4660 }
static char * AddVerboseIntPart(char *cp, int64 value, const char *units, bool *is_zero, bool *is_before)
Definition: datetime.c:4435
static char * AddPostgresIntPart(char *cp, int64 value, const char *units, bool *is_zero, bool *is_before)
Definition: datetime.c:4412
static char * AddISO8601IntPart(char *cp, int64 value, char units)
Definition: datetime.c:4402
#define MAX_INTERVAL_PRECISION
Definition: timestamp.h:93
#define INTSTYLE_POSTGRES_VERBOSE
Definition: miscadmin.h:251
#define INTSTYLE_ISO_8601
Definition: miscadmin.h:253
#define INTSTYLE_POSTGRES
Definition: miscadmin.h:250
int tm_year
Definition: timestamp.h:73
int tm_mon
Definition: timestamp.h:72
int tm_mday
Definition: timestamp.h:71

References AddISO8601IntPart(), AddPostgresIntPart(), AddVerboseIntPart(), AppendSeconds(), i64abs, INTSTYLE_ISO_8601, INTSTYLE_POSTGRES, INTSTYLE_POSTGRES_VERBOSE, INTSTYLE_SQL_STANDARD, MAX_INTERVAL_PRECISION, sprintf, generate_unaccent_rules::str, pg_itm::tm_hour, pg_itm::tm_mday, pg_itm::tm_min, pg_itm::tm_mon, pg_itm::tm_sec, pg_itm::tm_usec, and pg_itm::tm_year.

Referenced by interval_out().

◆ EncodeTimeOnly()

void EncodeTimeOnly ( struct pg_tm tm,
fsec_t  fsec,
bool  print_tz,
int  tz,
int  style,
char *  str 
)

Definition at line 4201 of file datetime.c.

4202 {
4204  *str++ = ':';
4206  *str++ = ':';
4207  str = AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
4208  if (print_tz)
4209  str = EncodeTimezone(str, tz, style);
4210  *str = '\0';
4211 }
#define MAX_TIME_PRECISION
Definition: date.h:45

References AppendSeconds(), EncodeTimezone(), MAX_TIME_PRECISION, pg_ultostr_zeropad(), generate_unaccent_rules::str, tm, pg_tm::tm_hour, pg_tm::tm_min, and pg_tm::tm_sec.

Referenced by JsonEncodeDateTime(), time_out(), and timetz_out().

◆ EncodeTimezone()

static char* EncodeTimezone ( char *  str,
int  tz,
int  style 
)
static

Definition at line 4078 of file datetime.c.

4079 {
4080  int hour,
4081  min,
4082  sec;
4083 
4084  sec = abs(tz);
4085  min = sec / SECS_PER_MINUTE;
4086  sec -= min * SECS_PER_MINUTE;
4087  hour = min / MINS_PER_HOUR;
4088  min -= hour * MINS_PER_HOUR;
4089 
4090  /* TZ is negated compared to sign we wish to display ... */
4091  *str++ = (tz <= 0 ? '+' : '-');
4092 
4093  if (sec != 0)
4094  {
4095  str = pg_ultostr_zeropad(str, hour, 2);
4096  *str++ = ':';
4097  str = pg_ultostr_zeropad(str, min, 2);
4098  *str++ = ':';
4099  str = pg_ultostr_zeropad(str, sec, 2);
4100  }
4101  else if (min != 0 || style == USE_XSD_DATES)
4102  {
4103  str = pg_ultostr_zeropad(str, hour, 2);
4104  *str++ = ':';
4105  str = pg_ultostr_zeropad(str, min, 2);
4106  }
4107  else
4108  str = pg_ultostr_zeropad(str, hour, 2);
4109  return str;
4110 }

References MINS_PER_HOUR, pg_ultostr_zeropad(), SECS_PER_MINUTE, generate_unaccent_rules::str, and USE_XSD_DATES.

Referenced by EncodeDateTime(), and EncodeTimeOnly().

◆ FetchDynamicTimeZone()

static pg_tz * FetchDynamicTimeZone ( TimeZoneAbbrevTable tbl,
const datetkn tp,
DateTimeErrorExtra extra 
)
static

Definition at line 4859 of file datetime.c.

4861 {
4862  DynamicZoneAbbrev *dtza;
4863 
4864  /* Just some sanity checks to prevent indexing off into nowhere */
4865  Assert(tp->type == DYNTZ);
4866  Assert(tp->value > 0 && tp->value < tbl->tblsize);
4867 
4868  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tp->value);
4869 
4870  /* Look up the underlying zone if we haven't already */
4871  if (dtza->tz == NULL)
4872  {
4873  dtza->tz = pg_tzset(dtza->zone);
4874  if (dtza->tz == NULL)
4875  {
4876  /* Ooops, bogus zone name in config file entry */
4877  extra->dtee_timezone = dtza->zone;
4878  extra->dtee_abbrev = tp->token;
4879  }
4880  }
4881  return dtza->tz;
4882 }

References Assert(), DateTimeErrorExtra::dtee_abbrev, DateTimeErrorExtra::dtee_timezone, DYNTZ, pg_tzset(), TimeZoneAbbrevTable::tblsize, datetkn::token, datetkn::type, DynamicZoneAbbrev::tz, datetkn::value, and DynamicZoneAbbrev::zone.

Referenced by DecodeTimezoneAbbrev(), and pg_timezone_abbrevs().

◆ GetCurrentDateTime()

void GetCurrentDateTime ( struct pg_tm tm)

Definition at line 368 of file datetime.c.

369 {
370  fsec_t fsec;
371 
372  GetCurrentTimeUsec(tm, &fsec, NULL);
373 }

References GetCurrentTimeUsec(), and tm.

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

◆ GetCurrentTimeUsec()

void GetCurrentTimeUsec ( struct pg_tm tm,
fsec_t fsec,
int *  tzp 
)

Definition at line 389 of file datetime.c.

390 {
392 
393  /*
394  * The cache key must include both current time and current timezone. By
395  * representing the timezone by just a pointer, we're assuming that
396  * distinct timezone settings could never have the same pointer value.
397  * This is true by virtue of the hashtable used inside pg_tzset();
398  * however, it might need another look if we ever allow entries in that
399  * hash to be recycled.
400  */
401  static TimestampTz cache_ts = 0;
402  static pg_tz *cache_timezone = NULL;
403  static struct pg_tm cache_tm;
404  static fsec_t cache_fsec;
405  static int cache_tz;
406 
407  if (cur_ts != cache_ts || session_timezone != cache_timezone)
408  {
409  /*
410  * Make sure cache is marked invalid in case of error after partial
411  * update within timestamp2tm.
412  */
413  cache_timezone = NULL;
414 
415  /*
416  * Perform the computation, storing results into cache. We do not
417  * really expect any error here, since current time surely ought to be
418  * within range, but check just for sanity's sake.
419  */
420  if (timestamp2tm(cur_ts, &cache_tz, &cache_tm, &cache_fsec,
421  NULL, session_timezone) != 0)
422  ereport(ERROR,
423  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
424  errmsg("timestamp out of range")));
425 
426  /* OK, so mark the cache valid. */
427  cache_ts = cur_ts;
428  cache_timezone = session_timezone;
429  }
430 
431  *tm = cache_tm;
432  *fsec = cache_fsec;
433  if (tzp != NULL)
434  *tzp = cache_tz;
435 }
int64 TimestampTz
Definition: timestamp.h:39
TimestampTz GetCurrentTransactionStartTimestamp(void)
Definition: xact.c:855

References ereport, errcode(), errmsg(), ERROR, GetCurrentTransactionStartTimestamp(), session_timezone, timestamp2tm(), and tm.

Referenced by DecodeDateTime(), DecodeTimeOnly(), GetCurrentDateTime(), GetSQLCurrentTime(), and GetSQLLocalTime().

◆ InstallTimeZoneAbbrevs()

void InstallTimeZoneAbbrevs ( TimeZoneAbbrevTable tbl)

Definition at line 4846 of file datetime.c.

4847 {
4848  zoneabbrevtbl = tbl;
4849  /* reset abbrevcache, which may contain pointers into old table */
4850  memset(abbrevcache, 0, sizeof(abbrevcache));
4851 }

References abbrevcache, and zoneabbrevtbl.

Referenced by assign_timezone_abbreviations().

◆ int64_multiply_add()

static bool int64_multiply_add ( int64  val,
int64  multiplier,
int64 *  sum 
)
static

Definition at line 524 of file datetime.c.

525 {
526  int64 product;
527 
528  if (pg_mul_s64_overflow(val, multiplier, &product) ||
529  pg_add_s64_overflow(*sum, product, sum))
530  return false;
531  return true;
532 }

References pg_add_s64_overflow(), pg_mul_s64_overflow(), and val.

Referenced by AdjustMicroseconds(), and DecodeTimeForInterval().

◆ ISO8601IntegerWidth()

static int ISO8601IntegerWidth ( char *  fieldstart)
static

Definition at line 3691 of file datetime.c.

3692 {
3693  /* We might have had a leading '-' */
3694  if (*fieldstart == '-')
3695  fieldstart++;
3696  return strspn(fieldstart, "0123456789");
3697 }

Referenced by DecodeISO8601Interval().

◆ j2date()

void j2date ( int  jd,
int *  year,
int *  month,
int *  day 
)

Definition at line 313 of file datetime.c.

314 {
315  unsigned int julian;
316  unsigned int quad;
317  unsigned int extra;
318  int y;
319 
320  julian = jd;
321  julian += 32044;
322  quad = julian / 146097;
323  extra = (julian - quad * 146097) * 4 + 3;
324  julian += 60 + quad * 3 + extra / 146097;
325  quad = julian / 1461;
326  julian -= quad * 1461;
327  y = julian * 4 / 1461;
328  julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
329  + 123;
330  y += quad * 4;
331  *year = y - 4800;
332  quad = julian * 2141 / 65536;
333  *day = julian - 7834 * quad / 256;
334  *month = (quad + 10) % MONTHS_PER_YEAR + 1;
335 } /* j2date() */
int y
Definition: isn.c:72

References MONTHS_PER_YEAR, and y.

Referenced by date2timestamptz_opt_overflow(), date_out(), DecodeDateTime(), DecodeTimeOnly(), do_to_timestamp(), extract_date(), isoweek2date(), isoweekdate2date(), JsonEncodeDateTime(), map_sql_value_to_xml_value(), PGTYPESdate_fmt_asc(), PGTYPESdate_julmdy(), PGTYPESdate_to_asc(), timestamp2tm(), timestamp_pl_interval(), timestamptz_pl_interval_internal(), and ValidateDate().

◆ j2day()

int j2day ( int  date)

Definition at line 346 of file datetime.c.

347 {
348  date += 1;
349  date %= 7;
350  /* Cope if division truncates towards zero, as it probably does */
351  if (date < 0)
352  date += 7;
353 
354  return date;
355 } /* j2day() */

Referenced by date2isoweek(), date2isoyear(), EncodeDateTime(), extract_date(), isoweek2j(), timestamp_part_common(), and timestamptz_part_common().

◆ ParseDateTime()

int ParseDateTime ( const char *  timestr,
char *  workbuf,
size_t  buflen,
char **  field,
int *  ftype,
int  maxfields,
int *  numfields 
)

Definition at line 756 of file datetime.c.

758 {
759  int nf = 0;
760  const char *cp = timestr;
761  char *bufp = workbuf;
762  const char *bufend = workbuf + buflen;
763 
764  /*
765  * Set the character pointed-to by "bufptr" to "newchar", and increment
766  * "bufptr". "end" gives the end of the buffer -- we return an error if
767  * there is no space left to append a character to the buffer. Note that
768  * "bufptr" is evaluated twice.
769  */
770 #define APPEND_CHAR(bufptr, end, newchar) \
771  do \
772  { \
773  if (((bufptr) + 1) >= (end)) \
774  return DTERR_BAD_FORMAT; \
775  *(bufptr)++ = newchar; \
776  } while (0)
777 
778  /* outer loop through fields */
779  while (*cp != '\0')
780  {
781  /* Ignore spaces between fields */
782  if (isspace((unsigned char) *cp))
783  {
784  cp++;
785  continue;
786  }
787 
788  /* Record start of current field */
789  if (nf >= maxfields)
790  return DTERR_BAD_FORMAT;
791  field[nf] = bufp;
792 
793  /* leading digit? then date or time */
794  if (isdigit((unsigned char) *cp))
795  {
796  APPEND_CHAR(bufp, bufend, *cp++);
797  while (isdigit((unsigned char) *cp))
798  APPEND_CHAR(bufp, bufend, *cp++);
799 
800  /* time field? */
801  if (*cp == ':')
802  {
803  ftype[nf] = DTK_TIME;
804  APPEND_CHAR(bufp, bufend, *cp++);
805  while (isdigit((unsigned char) *cp) ||
806  (*cp == ':') || (*cp == '.'))
807  APPEND_CHAR(bufp, bufend, *cp++);
808  }
809  /* date field? allow embedded text month */
810  else if (*cp == '-' || *cp == '/' || *cp == '.')
811  {
812  /* save delimiting character to use later */
813  char delim = *cp;
814 
815  APPEND_CHAR(bufp, bufend, *cp++);
816  /* second field is all digits? then no embedded text month */
817  if (isdigit((unsigned char) *cp))
818  {
819  ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
820  while (isdigit((unsigned char) *cp))
821  APPEND_CHAR(bufp, bufend, *cp++);
822 
823  /*
824  * insist that the delimiters match to get a three-field
825  * date.
826  */
827  if (*cp == delim)
828  {
829  ftype[nf] = DTK_DATE;
830  APPEND_CHAR(bufp, bufend, *cp++);
831  while (isdigit((unsigned char) *cp) || *cp == delim)
832  APPEND_CHAR(bufp, bufend, *cp++);
833  }
834  }
835  else
836  {
837  ftype[nf] = DTK_DATE;
838  while (isalnum((unsigned char) *cp) || *cp == delim)
839  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
840  }
841  }
842 
843  /*
844  * otherwise, number only and will determine year, month, day, or
845  * concatenated fields later...
846  */
847  else
848  ftype[nf] = DTK_NUMBER;
849  }
850  /* Leading decimal point? Then fractional seconds... */
851  else if (*cp == '.')
852  {
853  APPEND_CHAR(bufp, bufend, *cp++);
854  while (isdigit((unsigned char) *cp))
855  APPEND_CHAR(bufp, bufend, *cp++);
856 
857  ftype[nf] = DTK_NUMBER;
858  }
859 
860  /*
861  * text? then date string, month, day of week, special, or timezone
862  */
863  else if (isalpha((unsigned char) *cp))
864  {
865  bool is_date;
866 
867  ftype[nf] = DTK_STRING;
868  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
869  while (isalpha((unsigned char) *cp))
870  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
871 
872  /*
873  * Dates can have embedded '-', '/', or '.' separators. It could
874  * also be a timezone name containing embedded '/', '+', '-', '_',
875  * or ':' (but '_' or ':' can't be the first punctuation). If the
876  * next character is a digit or '+', we need to check whether what
877  * we have so far is a recognized non-timezone keyword --- if so,
878  * don't believe that this is the start of a timezone.
879  */
880  is_date = false;
881  if (*cp == '-' || *cp == '/' || *cp == '.')
882  is_date = true;
883  else if (*cp == '+' || isdigit((unsigned char) *cp))
884  {
885  *bufp = '\0'; /* null-terminate current field value */
886  /* we need search only the core token table, not TZ names */
887  if (datebsearch(field[nf], datetktbl, szdatetktbl) == NULL)
888  is_date = true;
889  }
890  if (is_date)
891  {
892  ftype[nf] = DTK_DATE;
893  do
894  {
895  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
896  } while (*cp == '+' || *cp == '-' ||
897  *cp == '/' || *cp == '_' ||
898  *cp == '.' || *cp == ':' ||
899  isalnum((unsigned char) *cp));
900  }
901  }
902  /* sign? then special or numeric timezone */
903  else if (*cp == '+' || *cp == '-')
904  {
905  APPEND_CHAR(bufp, bufend, *cp++);
906  /* soak up leading whitespace */
907  while (isspace((unsigned char) *cp))
908  cp++;
909  /* numeric timezone? */
910  /* note that "DTK_TZ" could also be a signed float or yyyy-mm */
911  if (isdigit((unsigned char) *cp))
912  {
913  ftype[nf] = DTK_TZ;
914  APPEND_CHAR(bufp, bufend, *cp++);
915  while (isdigit((unsigned char) *cp) ||
916  *cp == ':' || *cp == '.' || *cp == '-')
917  APPEND_CHAR(bufp, bufend, *cp++);
918  }
919  /* special? */
920  else if (isalpha((unsigned char) *cp))
921  {
922  ftype[nf] = DTK_SPECIAL;
923  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
924  while (isalpha((unsigned char) *cp))
925  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
926  }
927  /* otherwise something wrong... */
928  else
929  return DTERR_BAD_FORMAT;
930  }
931  /* ignore other punctuation but use as delimiter */
932  else if (ispunct((unsigned char) *cp))
933  {
934  cp++;
935  continue;
936  }
937  /* otherwise, something is not right... */
938  else
939  return DTERR_BAD_FORMAT;
940 
941  /* force in a delimiter after each field */
942  *bufp++ = '\0';
943  nf++;
944  }
945 
946  *numfields = nf;
947 
948  return 0;
949 }
#define APPEND_CHAR(bufptr, end, newchar)
unsigned char pg_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:122

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

Referenced by check_recovery_target_time(), date_in(), interval_in(), pg_logdir_ls_internal(), PGTYPESdate_from_asc(), PGTYPESinterval_from_asc(), PGTYPEStimestamp_from_asc(), time_in(), timestamp_in(), timestamptz_in(), and timetz_in().

◆ ParseFraction()

static int ParseFraction ( char *  cp,
double *  frac 
)
static

Definition at line 682 of file datetime.c.

683 {
684  /* Caller should always pass the start of the fraction part */
685  Assert(*cp == '.');
686 
687  /*
688  * We want to allow just "." with no digits, but some versions of strtod
689  * will report EINVAL for that, so special-case it.
690  */
691  if (cp[1] == '\0')
692  {
693  *frac = 0;
694  }
695  else
696  {
697  errno = 0;
698  *frac = strtod(cp, &cp);
699  /* check for parse failure */
700  if (*cp != '\0' || errno != 0)
701  return DTERR_BAD_FORMAT;
702  }
703  return 0;
704 }

References Assert(), and DTERR_BAD_FORMAT.

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

◆ ParseFractionalSecond()

static int ParseFractionalSecond ( char *  cp,
fsec_t fsec 
)
static

Definition at line 711 of file datetime.c.

712 {
713  double frac;
714  int dterr;
715 
716  dterr = ParseFraction(cp, &frac);
717  if (dterr)
718  return dterr;
719  *fsec = rint(frac * 1000000);
720  return 0;
721 }

References ParseFraction().

Referenced by DecodeNumber(), and DecodeTimeCommon().

◆ ParseISO8601Number()

static int ParseISO8601Number ( char *  str,
char **  endptr,
int64 *  ipart,
double *  fpart 
)
static

Definition at line 3649 of file datetime.c.

3650 {
3651  double val;
3652 
3653  /*
3654  * Historically this has accepted anything that strtod() would take,
3655  * notably including "e" notation, so continue doing that. This is
3656  * slightly annoying because the precision of double is less than that of
3657  * int64, so we would lose accuracy for inputs larger than 2^53 or so.
3658  * However, historically we rejected inputs outside the int32 range,
3659  * making that concern moot. What we do now is reject abs(val) above
3660  * 1.0e15 (a round number a bit less than 2^50), so that any accepted
3661  * value will have an exact integer part, and thereby a fraction part with
3662  * abs(*fpart) less than 1. In the absence of field complaints it doesn't
3663  * seem worth working harder.
3664  */
3665  if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
3666  return DTERR_BAD_FORMAT;
3667  errno = 0;
3668  val = strtod(str, endptr);
3669  /* did we not see anything that looks like a double? */