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 "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)
 
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)
 
int DetermineTimeZoneOffset (struct pg_tm *tm, pg_tz *tzp)
 
int DetermineTimeZoneAbbrevOffset (struct pg_tm *tm, const char *abbr, pg_tz *tzp)
 
int DetermineTimeZoneAbbrevOffsetTS (TimestampTz ts, const char *abbr, pg_tz *tzp, int *isdst)
 
int DecodeTimeOnly (char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp)
 
int ValidateDate (int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
 
int DecodeTimezone (char *str, int *tzp)
 
int DecodeTimezoneAbbrev (int field, char *lowtoken, int *offset, pg_tz **tz)
 
int DecodeSpecial (int field, char *lowtoken, int *val)
 
static void 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, char *lowtoken, int *val)
 
void DateTimeParseError (int dterr, const char *str, const char *datatype)
 
static char * EncodeTimezone (char *str, int tz, int style)
 
void EncodeDateOnly (struct pg_tm *tm, int style, char *str)
 
void EncodeTimeOnly (struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, int style, char *str)
 
void EncodeDateTime (struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
 
static char * AddISO8601IntPart (char *cp, 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:281

Function Documentation

◆ AddISO8601IntPart()

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

Definition at line 4430 of file datetime.c.

4431 {
4432  if (value == 0)
4433  return cp;
4434  sprintf(cp, "%lld%c", (long long) value, units);
4435  return cp + strlen(cp);
4436 }
static struct @143 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 4440 of file datetime.c.

4442 {
4443  if (value == 0)
4444  return cp;
4445  sprintf(cp, "%s%s%lld %s%s",
4446  (!*is_zero) ? " " : "",
4447  (*is_before && value > 0) ? "+" : "",
4448  (long long) value,
4449  units,
4450  (value != 1) ? "s" : "");
4451 
4452  /*
4453  * Each nonzero field sets is_before for (only) the next one. This is a
4454  * tad bizarre but it's how it worked before...
4455  */
4456  *is_before = (value < 0);
4457  *is_zero = false;
4458  return cp + strlen(cp);
4459 }

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 4463 of file datetime.c.

4465 {
4466  if (value == 0)
4467  return cp;
4468  /* first nonzero value sets is_before */
4469  if (*is_zero)
4470  {
4471  *is_before = (value < 0);
4472  value = i64abs(value);
4473  }
4474  else if (*is_before)
4475  value = -value;
4476  sprintf(cp, " %lld %s%s", (long long) value, units, (value == 1) ? "" : "s");
4477  *is_zero = false;
4478  return cp + strlen(cp);
4479 }
#define i64abs(i)
Definition: c.h:1243

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 632 of file datetime.c.

633 {
634  int days;
635 
636  if (val < INT_MIN || val > INT_MAX)
637  return false;
638  return !pg_mul_s32_overflow((int32) val, scale, &days) &&
639  !pg_add_s32_overflow(itm_in->tm_mday, days, &itm_in->tm_mday);
640 }
const char *const days[]
Definition: datetime.c:84
signed int int32
Definition: c.h:430
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:190
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 568 of file datetime.c.

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

538 {
539  int64 usec;
540 
541  /* Fast path for common case */
542  if (frac == 0)
543  return true;
544 
545  /*
546  * We assume the input frac has abs value less than 1, so overflow of frac
547  * or usec is not an issue for interesting values of scale.
548  */
549  frac *= scale;
550  usec = (int64) frac;
551 
552  /* Round off any fractional microsecond */
553  frac -= usec;
554  if (frac > 0.5)
555  usec++;
556  else if (frac < -0.5)
557  usec--;
558 
559  return !pg_add_s64_overflow(itm_in->tm_usec, usec, &itm_in->tm_usec);
560 }
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 600 of file datetime.c.

602 {
603  /*
604  * As above, we assume abs(frac) < 1, so this can't overflow for any
605  * interesting value of scale.
606  */
607  int extra_months = (int) rint(frac * scale * MONTHS_PER_YEAR);
608 
609  return !pg_add_s32_overflow(itm_in->tm_mon, extra_months, &itm_in->tm_mon);
610 }
#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 617 of file datetime.c.

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

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 648 of file datetime.c.

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

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 660 of file datetime.c.

662 {
663  int years;
664 
665  if (val < INT_MIN || val > INT_MAX)
666  return false;
667  return !pg_mul_s32_overflow((int32) val, scale, &years) &&
668  !pg_add_s32_overflow(itm_in->tm_year, years, &itm_in->tm_year);
669 }
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 447 of file datetime.c.

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

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 510 of file datetime.c.

511 {
512  return AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
513 }
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:447
#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 4696 of file datetime.c.

4697 {
4698  bool ok = true;
4699  int i;
4700 
4701  for (i = 0; i < nel; i++)
4702  {
4703  /* check for token strings that don't fit */
4704  if (strlen(base[i].token) > TOKMAXLEN)
4705  {
4706  /* %.*s is safe since all our tokens are ASCII */
4707  elog(LOG, "token too long in %s table: \"%.*s\"",
4708  tablename,
4709  TOKMAXLEN + 1, base[i].token);
4710  ok = false;
4711  break; /* don't risk applying strcmp */
4712  }
4713  /* check for out of order */
4714  if (i > 0 &&
4715  strcmp(base[i - 1].token, base[i].token) >= 0)
4716  {
4717  elog(LOG, "ordering error in %s table: \"%s\" >= \"%s\"",
4718  tablename,
4719  base[i - 1].token,
4720  base[i].token);
4721  ok = false;
4722  }
4723  }
4724  return ok;
4725 }
#define LOG
Definition: elog.h:27
#define TOKMAXLEN
Definition: datetime.h:205
int i
Definition: isn.c:73

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

Referenced by CheckDateTokenTables(), and ConvertTimeZoneAbbrevs().

◆ CheckDateTokenTables()

bool CheckDateTokenTables ( void  )

Definition at line 4728 of file datetime.c.

4729 {
4730  bool ok = true;
4731 
4732  Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1));
4733  Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1));
4734 
4735  ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
4736  ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
4737  return ok;
4738 }
static bool CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
Definition: datetime.c:4696
static const datetkn datetktbl[]
Definition: datetime.c:105
static const int szdeltatktbl
Definition: datetime.c:251
static const int szdatetktbl
Definition: datetime.c:180
int date2j(int year, int month, int day)
Definition: datetime.c:285
static const datetkn deltatktbl[]
Definition: datetime.c:186
#define UNIX_EPOCH_JDATE
Definition: timestamp.h:201
#define POSTGRES_EPOCH_JDATE
Definition: timestamp.h:202

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 3313 of file datetime.c.

3314 {
3315  itm_in->tm_usec = 0;
3316  itm_in->tm_mday = 0;
3317  itm_in->tm_mon = 0;
3318  itm_in->tm_year = 0;
3319 }

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 4790 of file datetime.c.

4791 {
4792  TimeZoneAbbrevTable *tbl;
4793  Size tbl_size;
4794  int i;
4795 
4796  /* Space for fixed fields and datetkn array */
4797  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4798  n * sizeof(datetkn);
4799  tbl_size = MAXALIGN(tbl_size);
4800  /* Count up space for dynamic abbreviations */
4801  for (i = 0; i < n; i++)
4802  {
4803  struct tzEntry *abbr = abbrevs + i;
4804 
4805  if (abbr->zone != NULL)
4806  {
4807  Size dsize;
4808 
4809  dsize = offsetof(DynamicZoneAbbrev, zone) +
4810  strlen(abbr->zone) + 1;
4811  tbl_size += MAXALIGN(dsize);
4812  }
4813  }
4814 
4815  /* Alloc the result ... */
4816  tbl = guc_malloc(LOG, tbl_size);
4817  if (!tbl)
4818  return NULL;
4819 
4820  /* ... and fill it in */
4821  tbl->tblsize = tbl_size;
4822  tbl->numabbrevs = n;
4823  /* in this loop, tbl_size reprises the space calculation above */
4824  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4825  n * sizeof(datetkn);
4826  tbl_size = MAXALIGN(tbl_size);
4827  for (i = 0; i < n; i++)
4828  {
4829  struct tzEntry *abbr = abbrevs + i;
4830  datetkn *dtoken = tbl->abbrevs + i;
4831 
4832  /* use strlcpy to truncate name if necessary */
4833  strlcpy(dtoken->token, abbr->abbrev, TOKMAXLEN + 1);
4834  if (abbr->zone != NULL)
4835  {
4836  /* Allocate a DynamicZoneAbbrev for this abbreviation */
4837  DynamicZoneAbbrev *dtza;
4838  Size dsize;
4839 
4840  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tbl_size);
4841  dtza->tz = NULL;
4842  strcpy(dtza->zone, abbr->zone);
4843 
4844  dtoken->type = DYNTZ;
4845  /* value is offset from table start to DynamicZoneAbbrev */
4846  dtoken->value = (int32) tbl_size;
4847 
4848  dsize = offsetof(DynamicZoneAbbrev, zone) +
4849  strlen(abbr->zone) + 1;
4850  tbl_size += MAXALIGN(dsize);
4851  }
4852  else
4853  {
4854  dtoken->type = abbr->is_dst ? DTZ : TZ;
4855  dtoken->value = abbr->offset;
4856  }
4857  }
4858 
4859  /* Assert the two loops above agreed on size calculations */
4860  Assert(tbl->tblsize == tbl_size);
4861 
4862  /* Check the ordering, if testing */
4863  Assert(CheckDateTokenTable("timezone abbreviations", tbl->abbrevs, n));
4864 
4865  return tbl;
4866 }
#define MAXALIGN(LEN)
Definition: c.h:747
size_t Size
Definition: c.h:541
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:631
#define TZ
Definition: datetime.h:96
#define DTZ
Definition: datetime.h:97
#define DYNTZ
Definition: datetime.h:98
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char zone[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:228
datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:220
char token[TOKMAXLEN+1]
Definition: datetime.h:210
int32 value
Definition: datetime.h:212
char type
Definition: datetime.h:211
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 285 of file datetime.c.

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

Referenced by CheckDateTokenTables(), current_date(), date2isoweek(), date2isoyear(), date2isoyearday(), date_in(), DCH_to_char(), DecodeDateTime(), DetermineTimeZoneOffsetInternal(), EncodeDateTime(), extract_date(), 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(), 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 4070 of file datetime.c.

4071 {
4072  if (nel > 0)
4073  {
4074  const datetkn *last = base + nel - 1,
4075  *position;
4076  int result;
4077 
4078  while (last >= base)
4079  {
4080  position = base + ((last - base) >> 1);
4081  /* precheck the first character for a bit of extra speed */
4082  result = (int) key[0] - (int) position->token[0];
4083  if (result == 0)
4084  {
4085  /* use strncmp so that we match truncated tokens */
4086  result = strncmp(key, position->token, TOKMAXLEN);
4087  if (result == 0)
4088  return position;
4089  }
4090  if (result < 0)
4091  last = position - 1;
4092  else
4093  base = position + 1;
4094  }
4095  }
4096  return NULL;
4097 }

References sort-test::key, and TOKMAXLEN.

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

◆ DateTimeParseError()

void DateTimeParseError ( int  dterr,
const char *  str,
const char *  datatype 
)

Definition at line 4025 of file datetime.c.

4026 {
4027  switch (dterr)
4028  {
4029  case DTERR_FIELD_OVERFLOW:
4030  ereport(ERROR,
4031  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
4032  errmsg("date/time field value out of range: \"%s\"",
4033  str)));
4034  break;
4036  /* <nanny>same as above, but add hint about DateStyle</nanny> */
4037  ereport(ERROR,
4038  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
4039  errmsg("date/time field value out of range: \"%s\"",
4040  str),
4041  errhint("Perhaps you need a different \"datestyle\" setting.")));
4042  break;
4044  ereport(ERROR,
4045  (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
4046  errmsg("interval field value out of range: \"%s\"",
4047  str)));
4048  break;
4049  case DTERR_TZDISP_OVERFLOW:
4050  ereport(ERROR,
4051  (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
4052  errmsg("time zone displacement out of range: \"%s\"",
4053  str)));
4054  break;
4055  case DTERR_BAD_FORMAT:
4056  default:
4057  ereport(ERROR,
4058  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4059  errmsg("invalid input syntax for type %s: \"%s\"",
4060  datatype, str)));
4061  break;
4062  }
4063 }
int errhint(const char *fmt,...)
Definition: elog.c:1153
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
#define DTERR_INTERVAL_OVERFLOW
Definition: datetime.h:284
#define DTERR_TZDISP_OVERFLOW
Definition: datetime.h:285
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:282
#define DTERR_MD_FIELD_OVERFLOW
Definition: datetime.h:283

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

Referenced by date_in(), do_to_timestamp(), interval_in(), parse_datetime(), 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 2539 of file datetime.c.

2541 {
2542  fsec_t fsec;
2543  int nf = 0;
2544  int i,
2545  len;
2546  int dterr;
2547  bool haveTextMonth = false;
2548  int type,
2549  val,
2550  dmask = 0;
2551  char *field[MAXDATEFIELDS];
2552 
2553  *tmask = 0;
2554 
2555  /* parse this string... */
2556  while (*str != '\0' && nf < MAXDATEFIELDS)
2557  {
2558  /* skip field separators */
2559  while (*str != '\0' && !isalnum((unsigned char) *str))
2560  str++;
2561 
2562  if (*str == '\0')
2563  return DTERR_BAD_FORMAT; /* end of string after separator */
2564 
2565  field[nf] = str;
2566  if (isdigit((unsigned char) *str))
2567  {
2568  while (isdigit((unsigned char) *str))
2569  str++;
2570  }
2571  else if (isalpha((unsigned char) *str))
2572  {
2573  while (isalpha((unsigned char) *str))
2574  str++;
2575  }
2576 
2577  /* Just get rid of any non-digit, non-alpha characters... */
2578  if (*str != '\0')
2579  *str++ = '\0';
2580  nf++;
2581  }
2582 
2583  /* look first for text fields, since that will be unambiguous month */
2584  for (i = 0; i < nf; i++)
2585  {
2586  if (isalpha((unsigned char) *field[i]))
2587  {
2588  type = DecodeSpecial(i, field[i], &val);
2589  if (type == IGNORE_DTF)
2590  continue;
2591 
2592  dmask = DTK_M(type);
2593  switch (type)
2594  {
2595  case MONTH:
2596  tm->tm_mon = val;
2597  haveTextMonth = true;
2598  break;
2599 
2600  default:
2601  return DTERR_BAD_FORMAT;
2602  }
2603  if (fmask & dmask)
2604  return DTERR_BAD_FORMAT;
2605 
2606  fmask |= dmask;
2607  *tmask |= dmask;
2608 
2609  /* mark this field as being completed */
2610  field[i] = NULL;
2611  }
2612  }
2613 
2614  /* now pick up remaining numeric fields */
2615  for (i = 0; i < nf; i++)
2616  {
2617  if (field[i] == NULL)
2618  continue;
2619 
2620  if ((len = strlen(field[i])) <= 0)
2621  return DTERR_BAD_FORMAT;
2622 
2623  dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,
2624  &dmask, tm,
2625  &fsec, is2digits);
2626  if (dterr)
2627  return dterr;
2628 
2629  if (fmask & dmask)
2630  return DTERR_BAD_FORMAT;
2631 
2632  fmask |= dmask;
2633  *tmask |= dmask;
2634  }
2635 
2636  if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
2637  return DTERR_BAD_FORMAT;
2638 
2639  /* validation of the field values must wait until ValidateDate() */
2640 
2641  return 0;
2642 }
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:2868
int DecodeSpecial(int field, char *lowtoken, int *val)
Definition: datetime.c:3281
int32 fsec_t
Definition: timestamp.h:41
#define MAXDATEFIELDS
Definition: datetime.h:203
#define MONTH
Definition: datetime.h:92
#define IGNORE_DTF
Definition: datetime.h:99
#define DTK_M(t)
Definition: datetime.h:188
#define DTK_DATE_M
Definition: datetime.h:192
#define DOY
Definition: datetime.h:106
const void size_t len
int tm_mon
Definition: pgtime.h:40

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, generate_unaccent_rules::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 
)

Definition at line 974 of file datetime.c.

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

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 3334 of file datetime.c.

3336 {
3337  bool force_negative = false;
3338  bool is_before = false;
3339  char *cp;
3340  int fmask = 0,
3341  tmask,
3342  type,
3343  uval;
3344  int i;
3345  int dterr;
3346  int64 val;
3347  double fval;
3348 
3349  *dtype = DTK_DELTA;
3350  type = IGNORE_DTF;
3351  ClearPgItmIn(itm_in);
3352 
3353  /*----------
3354  * The SQL standard defines the interval literal
3355  * '-1 1:00:00'
3356  * to mean "negative 1 days and negative 1 hours", while Postgres
3357  * traditionally treats this as meaning "negative 1 days and positive
3358  * 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign
3359  * to all fields if there are no other explicit signs.
3360  *
3361  * We leave the signs alone if there are additional explicit signs.
3362  * This protects us against misinterpreting postgres-style dump output,
3363  * since the postgres-style output code has always put an explicit sign on
3364  * all fields following a negative field. But note that SQL-spec output
3365  * is ambiguous and can be misinterpreted on load! (So it's best practice
3366  * to dump in postgres style, not SQL style.)
3367  *----------
3368  */
3369  if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
3370  {
3371  force_negative = true;
3372  /* Check for additional explicit signs */
3373  for (i = 1; i < nf; i++)
3374  {
3375  if (*field[i] == '-' || *field[i] == '+')
3376  {
3377  force_negative = false;
3378  break;
3379  }
3380  }
3381  }
3382 
3383  /* read through list backwards to pick up units before values */
3384  for (i = nf - 1; i >= 0; i--)
3385  {
3386  switch (ftype[i])
3387  {
3388  case DTK_TIME:
3389  dterr = DecodeTimeForInterval(field[i], fmask, range,
3390  &tmask, itm_in);
3391  if (dterr)
3392  return dterr;
3393  if (force_negative &&
3394  itm_in->tm_usec > 0)
3395  itm_in->tm_usec = -itm_in->tm_usec;
3396  type = DTK_DAY;
3397  break;
3398 
3399  case DTK_TZ:
3400 
3401  /*
3402  * Timezone means a token with a leading sign character and at
3403  * least one digit; there could be ':', '.', '-' embedded in
3404  * it as well.
3405  */
3406  Assert(*field[i] == '-' || *field[i] == '+');
3407 
3408  /*
3409  * Check for signed hh:mm or hh:mm:ss. If so, process exactly
3410  * like DTK_TIME case above, plus handling the sign.
3411  */
3412  if (strchr(field[i] + 1, ':') != NULL &&
3413  DecodeTimeForInterval(field[i] + 1, fmask, range,
3414  &tmask, itm_in) == 0)
3415  {
3416  if (*field[i] == '-')
3417  {
3418  /* flip the sign on time field */
3419  if (itm_in->tm_usec == PG_INT64_MIN)
3420  return DTERR_FIELD_OVERFLOW;
3421  itm_in->tm_usec = -itm_in->tm_usec;
3422  }
3423 
3424  if (force_negative &&
3425  itm_in->tm_usec > 0)
3426  itm_in->tm_usec = -itm_in->tm_usec;
3427 
3428  /*
3429  * Set the next type to be a day, if units are not
3430  * specified. This handles the case of '1 +02:03' since we
3431  * are reading right to left.
3432  */
3433  type = DTK_DAY;
3434  break;
3435  }
3436 
3437  /*
3438  * Otherwise, fall through to DTK_NUMBER case, which can
3439  * handle signed float numbers and signed year-month values.
3440  */
3441 
3442  /* FALLTHROUGH */
3443 
3444  case DTK_DATE:
3445  case DTK_NUMBER:
3446  if (type == IGNORE_DTF)
3447  {
3448  /* use typmod to decide what rightmost field is */
3449  switch (range)
3450  {
3451  case INTERVAL_MASK(YEAR):
3452  type = DTK_YEAR;
3453  break;
3454  case INTERVAL_MASK(MONTH):
3456  type = DTK_MONTH;
3457  break;
3458  case INTERVAL_MASK(DAY):
3459  type = DTK_DAY;
3460  break;
3461  case INTERVAL_MASK(HOUR):
3463  type = DTK_HOUR;
3464  break;
3465  case INTERVAL_MASK(MINUTE):
3468  type = DTK_MINUTE;
3469  break;
3470  case INTERVAL_MASK(SECOND):
3474  type = DTK_SECOND;
3475  break;
3476  default:
3477  type = DTK_SECOND;
3478  break;
3479  }
3480  }
3481 
3482  errno = 0;
3483  val = strtoi64(field[i], &cp, 10);
3484  if (errno == ERANGE)
3485  return DTERR_FIELD_OVERFLOW;
3486 
3487  if (*cp == '-')
3488  {
3489  /* SQL "years-months" syntax */
3490  int val2;
3491 
3492  val2 = strtoint(cp + 1, &cp, 10);
3493  if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
3494  return DTERR_FIELD_OVERFLOW;
3495  if (*cp != '\0')
3496  return DTERR_BAD_FORMAT;
3497  type = DTK_MONTH;
3498  if (*field[i] == '-')
3499  val2 = -val2;
3501  return DTERR_FIELD_OVERFLOW;
3502  if (pg_add_s64_overflow(val, val2, &val))
3503  return DTERR_FIELD_OVERFLOW;
3504  fval = 0;
3505  }
3506  else if (*cp == '.')
3507  {
3508  dterr = ParseFraction(cp, &fval);
3509  if (dterr)
3510  return dterr;
3511  if (*field[i] == '-')
3512  fval = -fval;
3513  }
3514  else if (*cp == '\0')
3515  fval = 0;
3516  else
3517  return DTERR_BAD_FORMAT;
3518 
3519  tmask = 0; /* DTK_M(type); */
3520 
3521  if (force_negative)
3522  {
3523  /* val and fval should be of same sign, but test anyway */
3524  if (val > 0)
3525  val = -val;
3526  if (fval > 0)
3527  fval = -fval;
3528  }
3529 
3530  switch (type)
3531  {
3532  case DTK_MICROSEC:
3533  if (!AdjustMicroseconds(val, fval, 1, itm_in))
3534  return DTERR_FIELD_OVERFLOW;
3535  tmask = DTK_M(MICROSECOND);
3536  break;
3537 
3538  case DTK_MILLISEC:
3539  if (!AdjustMicroseconds(val, fval, 1000, itm_in))
3540  return DTERR_FIELD_OVERFLOW;
3541  tmask = DTK_M(MILLISECOND);
3542  break;
3543 
3544  case DTK_SECOND:
3545  if (!AdjustMicroseconds(val, fval, USECS_PER_SEC, itm_in))
3546  return DTERR_FIELD_OVERFLOW;
3547 
3548  /*
3549  * If any subseconds were specified, consider this
3550  * microsecond and millisecond input as well.
3551  */
3552  if (fval == 0)
3553  tmask = DTK_M(SECOND);
3554  else
3555  tmask = DTK_ALL_SECS_M;
3556  break;
3557 
3558  case DTK_MINUTE:
3559  if (!AdjustMicroseconds(val, fval, USECS_PER_MINUTE, itm_in))
3560  return DTERR_FIELD_OVERFLOW;
3561  tmask = DTK_M(MINUTE);
3562  break;
3563 
3564  case DTK_HOUR:
3565  if (!AdjustMicroseconds(val, fval, USECS_PER_HOUR, itm_in))
3566  return DTERR_FIELD_OVERFLOW;
3567  tmask = DTK_M(HOUR);
3568  type = DTK_DAY; /* set for next field */
3569  break;
3570 
3571  case DTK_DAY:
3572  if (!AdjustDays(val, 1, itm_in) ||
3573  !AdjustFractMicroseconds(fval, USECS_PER_DAY, itm_in))
3574  return DTERR_FIELD_OVERFLOW;
3575  tmask = DTK_M(DAY);
3576  break;
3577 
3578  case DTK_WEEK:
3579  if (!AdjustDays(val, 7, itm_in) ||
3580  !AdjustFractDays(fval, 7, itm_in))
3581  return DTERR_FIELD_OVERFLOW;
3582  tmask = DTK_M(WEEK);
3583  break;
3584 
3585  case DTK_MONTH:
3586  if (!AdjustMonths(val, itm_in) ||
3587  !AdjustFractDays(fval, DAYS_PER_MONTH, itm_in))
3588  return DTERR_FIELD_OVERFLOW;
3589  tmask = DTK_M(MONTH);
3590  break;
3591 
3592  case DTK_YEAR:
3593  if (!AdjustYears(val, 1, itm_in) ||
3594  !AdjustFractYears(fval, 1, itm_in))
3595  return DTERR_FIELD_OVERFLOW;
3596  tmask = DTK_M(YEAR);
3597  break;
3598 
3599  case DTK_DECADE:
3600  if (!AdjustYears(val, 10, itm_in) ||
3601  !AdjustFractYears(fval, 10, itm_in))
3602  return DTERR_FIELD_OVERFLOW;
3603  tmask = DTK_M(DECADE);
3604  break;
3605 
3606  case DTK_CENTURY:
3607  if (!AdjustYears(val, 100, itm_in) ||
3608  !AdjustFractYears(fval, 100, itm_in))
3609  return DTERR_FIELD_OVERFLOW;
3610  tmask = DTK_M(CENTURY);
3611  break;
3612 
3613  case DTK_MILLENNIUM:
3614  if (!AdjustYears(val, 1000, itm_in) ||
3615  !AdjustFractYears(fval, 1000, itm_in))
3616  return DTERR_FIELD_OVERFLOW;
3617  tmask = DTK_M(MILLENNIUM);
3618  break;
3619 
3620  default:
3621  return DTERR_BAD_FORMAT;
3622  }
3623  break;
3624 
3625  case DTK_STRING:
3626  case DTK_SPECIAL:
3627  type = DecodeUnits(i, field[i], &uval);
3628  if (type == IGNORE_DTF)
3629  continue;
3630 
3631  tmask = 0; /* DTK_M(type); */
3632  switch (type)
3633  {
3634  case UNITS:
3635  type = uval;
3636  break;
3637 
3638  case AGO:
3639  is_before = true;
3640  type = uval;
3641  break;
3642 
3643  case RESERV:
3644  tmask = (DTK_DATE_M | DTK_TIME_M);
3645  *dtype = uval;
3646  break;
3647 
3648  default:
3649  return DTERR_BAD_FORMAT;
3650  }
3651  break;
3652 
3653  default:
3654  return DTERR_BAD_FORMAT;
3655  }
3656 
3657  if (tmask & fmask)
3658  return DTERR_BAD_FORMAT;
3659  fmask |= tmask;
3660  }
3661 
3662  /* ensure that at least one time field has been found */
3663  if (fmask == 0)
3664  return DTERR_BAD_FORMAT;
3665 
3666  /* finally, AGO negates everything */
3667  if (is_before)
3668  {
3669  if (itm_in->tm_usec == PG_INT64_MIN ||
3670  itm_in->tm_mday == INT_MIN ||
3671  itm_in->tm_mon == INT_MIN ||
3672  itm_in->tm_year == INT_MIN)
3673  return DTERR_FIELD_OVERFLOW;
3674 
3675  itm_in->tm_usec = -itm_in->tm_usec;
3676  itm_in->tm_mday = -itm_in->tm_mday;
3677  itm_in->tm_mon = -itm_in->tm_mon;
3678  itm_in->tm_year = -itm_in->tm_year;
3679  }
3680 
3681  return 0;
3682 }
static bool AdjustDays(int64 val, int scale, struct pg_itm_in *itm_in)
Definition: datetime.c:632
static bool AdjustFractYears(double frac, int scale, struct pg_itm_in *itm_in)
Definition: datetime.c:600
static bool AdjustMicroseconds(int64 val, double fval, int64 scale, struct pg_itm_in *itm_in)
Definition: datetime.c:617
static int DecodeTimeForInterval(char *str, int fmask, int range, int *tmask, struct pg_itm_in *itm_in)
Definition: datetime.c:2842
static bool AdjustYears(int64 val, int scale, struct pg_itm_in *itm_in)
Definition: datetime.c:660
static bool AdjustMonths(int64 val, struct pg_itm_in *itm_in)
Definition: datetime.c:648
int DecodeUnits(int field, char *lowtoken, int *val)
Definition: datetime.c:3988
static bool AdjustFractDays(double frac, int scale, struct pg_itm_in *itm_in)
Definition: datetime.c:568
static void ClearPgItmIn(struct pg_itm_in *itm_in)
Definition: datetime.c:3313
#define strtoi64(str, endptr, base)
Definition: c.h:1233
#define PG_INT64_MIN
Definition: c.h:527
#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:121
#define DTK_DECADE
Definition: datetime.h:169
#define DTK_DELTA
Definition: datetime.h:160
#define MICROSECOND
Definition: datetime.h:105
#define WEEK
Definition: datetime.h:118
#define DECADE
Definition: datetime.h:119
#define DTK_CENTURY
Definition: datetime.h:170
#define MILLISECOND
Definition: datetime.h:104
#define CENTURY
Definition: datetime.h:120
#define DTK_MILLENNIUM
Definition: datetime.h:171
#define DTK_WEEK
Definition: datetime.h:165
#define DTK_MICROSEC
Definition: datetime.h:173
#define AGO
Definition: datetime.h:111
#define DTK_MILLISEC
Definition: datetime.h:172
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_DATE_M, DTK_DAY, DTK_DECADE, DTK_DELTA, DTK_HOUR, DTK_M, DTK_MICROSEC, DTK_MILLENNIUM, DTK_MILLISEC, DTK_MINUTE, DTK_MONTH, DTK_NUMBER, DTK_SECOND, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TIME_M, DTK_TZ, DTK_WEEK, DTK_YEAR, 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(), RESERV, SECOND, strtoi64, strtoint(), pg_itm_in::tm_mday, pg_itm_in::tm_mon, pg_itm_in::tm_usec, pg_itm_in::tm_year, generate_unaccent_rules::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 3770 of file datetime.c.

3772 {
3773  bool datepart = true;
3774  bool havefield = false;
3775 
3776  *dtype = DTK_DELTA;
3777  ClearPgItmIn(itm_in);
3778 
3779  if (strlen(str) < 2 || str[0] != 'P')
3780  return DTERR_BAD_FORMAT;
3781 
3782  str++;
3783  while (*str)
3784  {
3785  char *fieldstart;
3786  int64 val;
3787  double fval;
3788  char unit;
3789  int dterr;
3790 
3791  if (*str == 'T') /* T indicates the beginning of the time part */
3792  {
3793  datepart = false;
3794  havefield = false;
3795  str++;
3796  continue;
3797  }
3798 
3799  fieldstart = str;
3800  dterr = ParseISO8601Number(str, &str, &val, &fval);
3801  if (dterr)
3802  return dterr;
3803 
3804  /*
3805  * Note: we could step off the end of the string here. Code below
3806  * *must* exit the loop if unit == '\0'.
3807  */
3808  unit = *str++;
3809 
3810  if (datepart)
3811  {
3812  switch (unit) /* before T: Y M W D */
3813  {
3814  case 'Y':
3815  if (!AdjustYears(val, 1, itm_in) ||
3816  !AdjustFractYears(fval, 1, itm_in))
3817  return DTERR_FIELD_OVERFLOW;
3818  break;
3819  case 'M':
3820  if (!AdjustMonths(val, itm_in) ||
3821  !AdjustFractDays(fval, DAYS_PER_MONTH, itm_in))
3822  return DTERR_FIELD_OVERFLOW;
3823  break;
3824  case 'W':
3825  if (!AdjustDays(val, 7, itm_in) ||
3826  !AdjustFractDays(fval, 7, itm_in))
3827  return DTERR_FIELD_OVERFLOW;
3828  break;
3829  case 'D':
3830  if (!AdjustDays(val, 1, itm_in) ||
3831  !AdjustFractMicroseconds(fval, USECS_PER_DAY, itm_in))
3832  return DTERR_FIELD_OVERFLOW;
3833  break;
3834  case 'T': /* ISO 8601 4.4.3.3 Alternative Format / Basic */
3835  case '\0':
3836  if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
3837  {
3838  if (!AdjustYears(val / 10000, 1, itm_in) ||
3839  !AdjustMonths((val / 100) % 100, itm_in) ||
3840  !AdjustDays(val % 100, 1, itm_in) ||
3841  !AdjustFractMicroseconds(fval, USECS_PER_DAY, itm_in))
3842  return DTERR_FIELD_OVERFLOW;
3843  if (unit == '\0')
3844  return 0;
3845  datepart = false;
3846  havefield = false;
3847  continue;
3848  }
3849  /* Else fall through to extended alternative format */
3850  /* FALLTHROUGH */
3851  case '-': /* ISO 8601 4.4.3.3 Alternative Format,
3852  * Extended */
3853  if (havefield)
3854  return DTERR_BAD_FORMAT;
3855 
3856  if (!AdjustYears(val, 1, itm_in) ||
3857  !AdjustFractYears(fval, 1, itm_in))
3858  return DTERR_FIELD_OVERFLOW;
3859  if (unit == '\0')
3860  return 0;
3861  if (unit == 'T')
3862  {
3863  datepart = false;
3864  havefield = false;
3865  continue;
3866  }
3867 
3868  dterr = ParseISO8601Number(str, &str, &val, &fval);
3869  if (dterr)
3870  return dterr;
3871  if (!AdjustMonths(val, itm_in) ||
3872  !AdjustFractDays(fval, DAYS_PER_MONTH, itm_in))
3873  return DTERR_FIELD_OVERFLOW;
3874  if (*str == '\0')
3875  return 0;
3876  if (*str == 'T')
3877  {
3878  datepart = false;
3879  havefield = false;
3880  continue;
3881  }
3882  if (*str != '-')
3883  return DTERR_BAD_FORMAT;
3884  str++;
3885 
3886  dterr = ParseISO8601Number(str, &str, &val, &fval);
3887  if (dterr)
3888  return dterr;
3889  if (!AdjustDays(val, 1, itm_in) ||
3890  !AdjustFractMicroseconds(fval, USECS_PER_DAY, itm_in))
3891  return DTERR_FIELD_OVERFLOW;
3892  if (*str == '\0')
3893  return 0;
3894  if (*str == 'T')
3895  {
3896  datepart = false;
3897  havefield = false;
3898  continue;
3899  }
3900  return DTERR_BAD_FORMAT;
3901  default:
3902  /* not a valid date unit suffix */
3903  return DTERR_BAD_FORMAT;
3904  }
3905  }
3906  else
3907  {
3908  switch (unit) /* after T: H M S */
3909  {
3910  case 'H':
3911  if (!AdjustMicroseconds(val, fval, USECS_PER_HOUR, itm_in))
3912  return DTERR_FIELD_OVERFLOW;
3913  break;
3914  case 'M':
3915  if (!AdjustMicroseconds(val, fval, USECS_PER_MINUTE, itm_in))
3916  return DTERR_FIELD_OVERFLOW;
3917  break;
3918  case 'S':
3919  if (!AdjustMicroseconds(val, fval, USECS_PER_SEC, itm_in))
3920  return DTERR_FIELD_OVERFLOW;
3921  break;
3922  case '\0': /* ISO 8601 4.4.3.3 Alternative Format */
3923  if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
3924  {
3925  if (!AdjustMicroseconds(val / 10000, 0, USECS_PER_HOUR, itm_in) ||
3926  !AdjustMicroseconds((val / 100) % 100, 0, USECS_PER_MINUTE, itm_in) ||
3927  !AdjustMicroseconds(val % 100, 0, USECS_PER_SEC, itm_in) ||
3928  !AdjustFractMicroseconds(fval, 1, itm_in))
3929  return DTERR_FIELD_OVERFLOW;
3930  return 0;
3931  }
3932  /* Else fall through to extended alternative format */
3933  /* FALLTHROUGH */
3934  case ':': /* ISO 8601 4.4.3.3 Alternative Format,
3935  * Extended */
3936  if (havefield)
3937  return DTERR_BAD_FORMAT;
3938 
3939  if (!AdjustMicroseconds(val, fval, USECS_PER_HOUR, itm_in))
3940  return DTERR_FIELD_OVERFLOW;
3941  if (unit == '\0')
3942  return 0;
3943 
3944  dterr = ParseISO8601Number(str, &str, &val, &fval);
3945  if (dterr)
3946  return dterr;
3947  if (!AdjustMicroseconds(val, fval, USECS_PER_MINUTE, itm_in))
3948  return DTERR_FIELD_OVERFLOW;
3949  if (*str == '\0')
3950  return 0;
3951  if (*str != ':')
3952  return DTERR_BAD_FORMAT;
3953  str++;
3954 
3955  dterr = ParseISO8601Number(str, &str, &val, &fval);
3956  if (dterr)
3957  return dterr;
3958  if (!AdjustMicroseconds(val, fval, USECS_PER_SEC, itm_in))
3959  return DTERR_FIELD_OVERFLOW;
3960  if (*str == '\0')
3961  return 0;
3962  return DTERR_BAD_FORMAT;
3963 
3964  default:
3965  /* not a valid time unit suffix */
3966  return DTERR_BAD_FORMAT;
3967  }
3968  }
3969 
3970  havefield = true;
3971  }
3972 
3973  return 0;
3974 }
static int ISO8601IntegerWidth(char *fieldstart)
Definition: datetime.c:3743
static int ParseISO8601Number(char *str, char **endptr, int64 *ipart, double *fpart)
Definition: datetime.c:3693

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 2868 of file datetime.c.

2870 {
2871  int val;
2872  char *cp;
2873  int dterr;
2874 
2875  *tmask = 0;
2876 
2877  errno = 0;
2878  val = strtoint(str, &cp, 10);
2879  if (errno == ERANGE)
2880  return DTERR_FIELD_OVERFLOW;
2881  if (cp == str)
2882  return DTERR_BAD_FORMAT;
2883 
2884  if (*cp == '.')
2885  {
2886  /*
2887  * More than two digits before decimal point? Then could be a date or
2888  * a run-together time: 2001.360 20011225 040506.789
2889  */
2890  if (cp - str > 2)
2891  {
2892  dterr = DecodeNumberField(flen, str,
2893  (fmask | DTK_DATE_M),
2894  tmask, tm,
2895  fsec, is2digits);
2896  if (dterr < 0)
2897  return dterr;
2898  return 0;
2899  }
2900 
2901  dterr = ParseFractionalSecond(cp, fsec);
2902  if (dterr)
2903  return dterr;
2904  }
2905  else if (*cp != '\0')
2906  return DTERR_BAD_FORMAT;
2907 
2908  /* Special case for day of year */
2909  if (flen == 3 && (fmask & DTK_DATE_M) == DTK_M(YEAR) && val >= 1 &&
2910  val <= 366)
2911  {
2912  *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
2913  tm->tm_yday = val;
2914  /* tm_mon and tm_mday can't actually be set yet ... */
2915  return 0;
2916  }
2917 
2918  /* Switch based on what we have so far */
2919  switch (fmask & DTK_DATE_M)
2920  {
2921  case 0:
2922 
2923  /*
2924  * Nothing so far; make a decision about what we think the input
2925  * is. There used to be lots of heuristics here, but the
2926  * consensus now is to be paranoid. It *must* be either
2927  * YYYY-MM-DD (with a more-than-two-digit year field), or the
2928  * field order defined by DateOrder.
2929  */
2930  if (flen >= 3 || DateOrder == DATEORDER_YMD)
2931  {
2932  *tmask = DTK_M(YEAR);
2933  tm->tm_year = val;
2934  }
2935  else if (DateOrder == DATEORDER_DMY)
2936  {
2937  *tmask = DTK_M(DAY);
2938  tm->tm_mday = val;
2939  }
2940  else
2941  {
2942  *tmask = DTK_M(MONTH);
2943  tm->tm_mon = val;
2944  }
2945  break;
2946 
2947  case (DTK_M(YEAR)):
2948  /* Must be at second field of YY-MM-DD */
2949  *tmask = DTK_M(MONTH);
2950  tm->tm_mon = val;
2951  break;
2952 
2953  case (DTK_M(MONTH)):
2954  if (haveTextMonth)
2955  {
2956  /*
2957  * We are at the first numeric field of a date that included a
2958  * textual month name. We want to support the variants
2959  * MON-DD-YYYY, DD-MON-YYYY, and YYYY-MON-DD as unambiguous
2960  * inputs. We will also accept MON-DD-YY or DD-MON-YY in
2961  * either DMY or MDY modes, as well as YY-MON-DD in YMD mode.
2962  */
2963  if (flen >= 3 || DateOrder == DATEORDER_YMD)
2964  {
2965  *tmask = DTK_M(YEAR);
2966  tm->tm_year = val;
2967  }
2968  else
2969  {
2970  *tmask = DTK_M(DAY);
2971  tm->tm_mday = val;
2972  }
2973  }
2974  else
2975  {
2976  /* Must be at second field of MM-DD-YY */
2977  *tmask = DTK_M(DAY);
2978  tm->tm_mday = val;
2979  }
2980  break;
2981 
2982  case (DTK_M(YEAR) | DTK_M(MONTH)):
2983  if (haveTextMonth)
2984  {
2985  /* Need to accept DD-MON-YYYY even in YMD mode */
2986  if (flen >= 3 && *is2digits)
2987  {
2988  /* Guess that first numeric field is day was wrong */
2989  *tmask = DTK_M(DAY); /* YEAR is already set */
2990  tm->tm_mday = tm->tm_year;
2991  tm->tm_year = val;
2992  *is2digits = false;
2993  }
2994  else
2995  {
2996  *tmask = DTK_M(DAY);
2997  tm->tm_mday = val;
2998  }
2999  }
3000  else
3001  {
3002  /* Must be at third field of YY-MM-DD */
3003  *tmask = DTK_M(DAY);
3004  tm->tm_mday = val;
3005  }
3006  break;
3007 
3008  case (DTK_M(DAY)):
3009  /* Must be at second field of DD-MM-YY */
3010  *tmask = DTK_M(MONTH);
3011  tm->tm_mon = val;
3012  break;
3013 
3014  case (DTK_M(MONTH) | DTK_M(DAY)):
3015  /* Must be at third field of DD-MM-YY or MM-DD-YY */
3016  *tmask = DTK_M(YEAR);
3017  tm->tm_year = val;
3018  break;
3019 
3020  case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)):
3021  /* we have all the date, so it must be a time field */
3022  dterr = DecodeNumberField(flen, str, fmask,
3023  tmask, tm,
3024  fsec, is2digits);
3025  if (dterr < 0)
3026  return dterr;
3027  return 0;
3028 
3029  default:
3030  /* Anything else is bogus input */
3031  return DTERR_BAD_FORMAT;
3032  }
3033 
3034  /*
3035  * When processing a year field, mark it for adjustment if it's only one
3036  * or two digits.
3037  */
3038  if (*tmask == DTK_M(YEAR))
3039  *is2digits = (flen <= 2);
3040 
3041  return 0;
3042 }
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 3053 of file datetime.c.

3055 {
3056  char *cp;
3057 
3058  /*
3059  * Have a decimal point? Then this is a date or something with a seconds
3060  * field...
3061  */
3062  if ((cp = strchr(str, '.')) != NULL)
3063  {
3064  /*
3065  * Can we use ParseFractionalSecond here? Not clear whether trailing
3066  * junk should be rejected ...
3067  */
3068  if (cp[1] == '\0')
3069  {
3070  /* avoid assuming that strtod will accept "." */
3071  *fsec = 0;
3072  }
3073  else
3074  {
3075  double frac;
3076 
3077  errno = 0;
3078  frac = strtod(cp, NULL);
3079  if (errno != 0)
3080  return DTERR_BAD_FORMAT;
3081  *fsec = rint(frac * 1000000);
3082  }
3083  /* Now truncate off the fraction for further processing */
3084  *cp = '\0';
3085  len = strlen(str);
3086  }
3087  /* No decimal point and no complete date yet? */
3088  else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
3089  {
3090  if (len >= 6)
3091  {
3092  *tmask = DTK_DATE_M;
3093 
3094  /*
3095  * Start from end and consider first 2 as Day, next 2 as Month,
3096  * and the rest as Year.
3097  */
3098  tm->tm_mday = atoi(str + (len - 2));
3099  *(str + (len - 2)) = '\0';
3100  tm->tm_mon = atoi(str + (len - 4));
3101  *(str + (len - 4)) = '\0';
3102  tm->tm_year = atoi(str);
3103  if ((len - 4) == 2)
3104  *is2digits = true;
3105 
3106  return DTK_DATE;
3107  }
3108  }
3109 
3110  /* not all time fields are specified? */
3111  if ((fmask & DTK_TIME_M) != DTK_TIME_M)
3112  {
3113  /* hhmmss */
3114  if (len == 6)
3115  {
3116  *tmask = DTK_TIME_M;
3117  tm->tm_sec = atoi(str + 4);
3118  *(str + 4) = '\0';
3119  tm->tm_min = atoi(str + 2);
3120  *(str + 2) = '\0';
3121  tm->tm_hour = atoi(str);
3122 
3123  return DTK_TIME;
3124  }
3125  /* hhmm? */
3126  else if (len == 4)
3127  {
3128  *tmask = DTK_TIME_M;
3129  tm->tm_sec = 0;
3130  tm->tm_min = atoi(str + 2);
3131  *(str + 2) = '\0';
3132  tm->tm_hour = atoi(str);
3133 
3134  return DTK_TIME;
3135  }
3136  }
3137 
3138  return DTERR_BAD_FORMAT;
3139 }

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,
char *  lowtoken,
int *  val 
)

Definition at line 3281 of file datetime.c.

3282 {
3283  int type;
3284  const datetkn *tp;
3285 
3286  tp = datecache[field];
3287  /* use strncmp so that we match truncated tokens */
3288  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3289  {
3290  tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
3291  }
3292  if (tp == NULL)
3293  {
3294  type = UNKNOWN_FIELD;
3295  *val = 0;
3296  }
3297  else
3298  {
3299  datecache[field] = tp;
3300  type = tp->type;
3301  *val = tp->value;
3302  }
3303 
3304  return type;
3305 }
static const datetkn * datecache[MAXDATEFIELDS]
Definition: datetime.c:257
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:4070

References datebsearch(), datecache, datetktbl, szdatetktbl, datetkn::token, TOKMAXLEN, generate_unaccent_rules::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 2813 of file datetime.c.

2815 {
2816  struct pg_itm itm;
2817  int dterr;
2818 
2819  dterr = DecodeTimeCommon(str, fmask, range,
2820  tmask, &itm);
2821  if (dterr)
2822  return dterr;
2823 
2824  if (itm.tm_hour > INT_MAX)
2825  return DTERR_FIELD_OVERFLOW;
2826  tm->tm_hour = (int) itm.tm_hour;
2827  tm->tm_min = itm.tm_min;
2828  tm->tm_sec = itm.tm_sec;
2829  *fsec = itm.tm_usec;
2830 
2831  return 0;
2832 }
static int DecodeTimeCommon(char *str, int fmask, int range, int *tmask, struct pg_itm *itm)
Definition: datetime.c:2731

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 2731 of file datetime.c.

2733 {
2734  char *cp;
2735  int dterr;
2736  fsec_t fsec = 0;
2737 
2738  *tmask = DTK_TIME_M;
2739 
2740  errno = 0;
2741  itm->tm_hour = strtoi64(str, &cp, 10);
2742  if (errno == ERANGE)
2743  return DTERR_FIELD_OVERFLOW;
2744  if (*cp != ':')
2745  return DTERR_BAD_FORMAT;
2746  errno = 0;
2747  itm->tm_min = strtoint(cp + 1, &cp, 10);
2748  if (errno == ERANGE)
2749  return DTERR_FIELD_OVERFLOW;
2750  if (*cp == '\0')
2751  {
2752  itm->tm_sec = 0;
2753  /* If it's a MINUTE TO SECOND interval, take 2 fields as being mm:ss */
2755  {
2756  if (itm->tm_hour > INT_MAX || itm->tm_hour < INT_MIN)
2757  return DTERR_FIELD_OVERFLOW;
2758  itm->tm_sec = itm->tm_min;
2759  itm->tm_min = (int) itm->tm_hour;
2760  itm->tm_hour = 0;
2761  }
2762  }
2763  else if (*cp == '.')
2764  {
2765  /* always assume mm:ss.sss is MINUTE TO SECOND */
2766  dterr = ParseFractionalSecond(cp, &fsec);
2767  if (dterr)
2768  return dterr;
2769  if (itm->tm_hour > INT_MAX || itm->tm_hour < INT_MIN)
2770  return DTERR_FIELD_OVERFLOW;
2771  itm->tm_sec = itm->tm_min;
2772  itm->tm_min = (int) itm->tm_hour;
2773  itm->tm_hour = 0;
2774  }
2775  else if (*cp == ':')
2776  {
2777  errno = 0;
2778  itm->tm_sec = strtoint(cp + 1, &cp, 10);
2779  if (errno == ERANGE)
2780  return DTERR_FIELD_OVERFLOW;
2781  if (*cp == '.')
2782  {
2783  dterr = ParseFractionalSecond(cp, &fsec);
2784  if (dterr)
2785  return dterr;
2786  }
2787  else if (*cp != '\0')
2788  return DTERR_BAD_FORMAT;
2789  }
2790  else
2791  return DTERR_BAD_FORMAT;
2792 
2793  /* do a sanity check; but caller must check the range of tm_hour */
2794  if (itm->tm_hour < 0 ||
2795  itm->tm_min < 0 || itm->tm_min > MINS_PER_HOUR - 1 ||
2796  itm->tm_sec < 0 || itm->tm_sec > SECS_PER_MINUTE ||
2797  fsec < 0 || fsec > USECS_PER_SEC)
2798  return DTERR_FIELD_OVERFLOW;
2799 
2800  itm->tm_usec = (int) fsec;
2801 
2802  return 0;
2803 }
#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 2842 of file datetime.c.

2844 {
2845  struct pg_itm itm;
2846  int dterr;
2847 
2848  dterr = DecodeTimeCommon(str, fmask, range,
2849  tmask, &itm);
2850  if (dterr)
2851  return dterr;
2852 
2853  itm_in->tm_usec = itm.tm_usec;
2854  if (!int64_multiply_add(itm.tm_hour, USECS_PER_HOUR, &itm_in->tm_usec) ||
2855  !int64_multiply_add(itm.tm_min, USECS_PER_MINUTE, &itm_in->tm_usec) ||
2856  !int64_multiply_add(itm.tm_sec, USECS_PER_SEC, &itm_in->tm_usec))
2857  return DTERR_FIELD_OVERFLOW;
2858 
2859  return 0;
2860 }

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 
)

Definition at line 1924 of file datetime.c.

1926 {
1927  int fmask = 0,
1928  tmask,
1929  type;
1930  int ptype = 0; /* "prefix type" for ISO h04mm05s06 format */
1931  int i;
1932  int val;
1933  int dterr;
1934  bool isjulian = false;
1935  bool is2digits = false;
1936  bool bc = false;
1937  int mer = HR24;
1938  pg_tz *namedTz = NULL;
1939  pg_tz *abbrevTz = NULL;
1940  char *abbrev = NULL;
1941  pg_tz *valtz;
1942 
1943  *dtype = DTK_TIME;
1944  tm->tm_hour = 0;
1945  tm->tm_min = 0;
1946  tm->tm_sec = 0;
1947  *fsec = 0;
1948  /* don't know daylight savings time status apriori */
1949  tm->tm_isdst = -1;
1950 
1951  if (tzp != NULL)
1952  *tzp = 0;
1953 
1954  for (i = 0; i < nf; i++)
1955  {
1956  switch (ftype[i])
1957  {
1958  case DTK_DATE:
1959 
1960  /*
1961  * Time zone not allowed? Then should not accept dates or time
1962  * zones no matter what else!
1963  */
1964  if (tzp == NULL)
1965  return DTERR_BAD_FORMAT;
1966 
1967  /* Under limited circumstances, we will accept a date... */
1968  if (i == 0 && nf >= 2 &&
1969  (ftype[nf - 1] == DTK_DATE || ftype[1] == DTK_TIME))
1970  {
1971  dterr = DecodeDate(field[i], fmask,
1972  &tmask, &is2digits, tm);
1973  if (dterr)
1974  return dterr;
1975  }
1976  /* otherwise, this is a time and/or time zone */
1977  else
1978  {
1979  if (isdigit((unsigned char) *field[i]))
1980  {
1981  char *cp;
1982 
1983  /*
1984  * Starts with a digit but we already have a time
1985  * field? Then we are in trouble with time already...
1986  */
1987  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1988  return DTERR_BAD_FORMAT;
1989 
1990  /*
1991  * Should not get here and fail. Sanity check only...
1992  */
1993  if ((cp = strchr(field[i], '-')) == NULL)
1994  return DTERR_BAD_FORMAT;
1995 
1996  /* Get the time zone from the end of the string */
1997  dterr = DecodeTimezone(cp, tzp);
1998  if (dterr)
1999  return dterr;
2000  *cp = '\0';
2001 
2002  /*
2003  * Then read the rest of the field as a concatenated
2004  * time
2005  */
2006  dterr = DecodeNumberField(strlen(field[i]), field[i],
2007  (fmask | DTK_DATE_M),
2008  &tmask, tm,
2009  fsec, &is2digits);
2010  if (dterr < 0)
2011  return dterr;
2012  ftype[i] = dterr;
2013 
2014  tmask |= DTK_M(TZ);
2015  }
2016  else
2017  {
2018  namedTz = pg_tzset(field[i]);
2019  if (!namedTz)
2020  {
2021  /*
2022  * We should return an error code instead of
2023  * ereport'ing directly, but then there is no way
2024  * to report the bad time zone name.
2025  */
2026  ereport(ERROR,
2027  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2028  errmsg("time zone \"%s\" not recognized",
2029  field[i])));
2030  }
2031  /* we'll apply the zone setting below */
2032  ftype[i] = DTK_TZ;
2033  tmask = DTK_M(TZ);
2034  }
2035  }
2036  break;
2037 
2038  case DTK_TIME:
2039  dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
2041  &tmask, tm, fsec);
2042  if (dterr)
2043  return dterr;
2044  break;
2045 
2046  case DTK_TZ:
2047  {
2048  int tz;
2049 
2050  if (tzp == NULL)
2051  return DTERR_BAD_FORMAT;
2052 
2053  dterr = DecodeTimezone(field[i], &tz);
2054  if (dterr)
2055  return dterr;
2056  *tzp = tz;
2057  tmask = DTK_M(TZ);
2058  }
2059  break;
2060 
2061  case DTK_NUMBER:
2062 
2063  /*
2064  * Was this an "ISO time" with embedded field labels? An
2065  * example is "h04mm05s06" - thomas 2001-02-04
2066  */
2067  if (ptype != 0)
2068  {
2069  char *cp;
2070  int value;
2071 
2072  /* Only accept a date under limited circumstances */
2073  switch (ptype)
2074  {
2075  case DTK_JULIAN:
2076  case DTK_YEAR:
2077  case DTK_MONTH:
2078  case DTK_DAY:
2079  if (tzp == NULL)
2080  return DTERR_BAD_FORMAT;
2081  default:
2082  break;
2083  }
2084 
2085  errno = 0;
2086  value = strtoint(field[i], &cp, 10);
2087  if (errno == ERANGE)
2088  return DTERR_FIELD_OVERFLOW;
2089 
2090  /*
2091  * only a few kinds are allowed to have an embedded
2092  * decimal
2093  */
2094  if (*cp == '.')
2095  switch (ptype)
2096  {
2097  case DTK_JULIAN:
2098  case DTK_TIME:
2099  case DTK_SECOND:
2100  break;
2101  default:
2102  return DTERR_BAD_FORMAT;
2103  break;
2104  }
2105  else if (*cp != '\0')
2106  return DTERR_BAD_FORMAT;
2107 
2108  switch (ptype)
2109  {
2110  case DTK_YEAR:
2111  tm->tm_year = value;
2112  tmask = DTK_M(YEAR);
2113  break;
2114 
2115  case DTK_MONTH:
2116 
2117  /*
2118  * already have a month and hour? then assume
2119  * minutes
2120  */
2121  if ((fmask & DTK_M(MONTH)) != 0 &&
2122  (fmask & DTK_M(HOUR)) != 0)
2123  {
2124  tm->tm_min = value;
2125  tmask = DTK_M(MINUTE);
2126  }
2127  else
2128  {
2129  tm->tm_mon = value;
2130  tmask = DTK_M(MONTH);
2131  }
2132  break;
2133 
2134  case DTK_DAY:
2135  tm->tm_mday = value;
2136  tmask = DTK_M(DAY);
2137  break;
2138 
2139  case DTK_HOUR:
2140  tm->tm_hour = value;
2141  tmask = DTK_M(HOUR);
2142  break;
2143 
2144  case DTK_MINUTE:
2145  tm->tm_min = value;
2146  tmask = DTK_M(MINUTE);
2147  break;
2148 
2149  case DTK_SECOND:
2150  tm->tm_sec = value;
2151  tmask = DTK_M(SECOND);
2152  if (*cp == '.')
2153  {
2154  dterr = ParseFractionalSecond(cp, fsec);
2155  if (dterr)
2156  return dterr;
2157  tmask = DTK_ALL_SECS_M;
2158  }
2159  break;
2160 
2161  case DTK_TZ:
2162  tmask = DTK_M(TZ);
2163  dterr = DecodeTimezone(field[i], tzp);
2164  if (dterr)
2165  return dterr;
2166  break;
2167 
2168  case DTK_JULIAN:
2169  /* previous field was a label for "julian date" */
2170  if (value < 0)
2171  return DTERR_FIELD_OVERFLOW;
2172  tmask = DTK_DATE_M;
2173  j2date(value, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2174  isjulian = true;
2175 
2176  if (*cp == '.')
2177  {
2178  double time;
2179 
2180  dterr = ParseFraction(cp, &time);
2181  if (dterr)
2182  return dterr;
2183  time *= USECS_PER_DAY;
2184  dt2time(time,
2185  &tm->tm_hour, &tm->tm_min,
2186  &tm->tm_sec, fsec);
2187  tmask |= DTK_TIME_M;
2188  }
2189  break;
2190 
2191  case DTK_TIME:
2192  /* previous field was "t" for ISO time */
2193  dterr = DecodeNumberField(strlen(field[i]), field[i],
2194  (fmask | DTK_DATE_M),
2195  &tmask, tm,
2196  fsec, &is2digits);
2197  if (dterr < 0)
2198  return dterr;
2199  ftype[i] = dterr;
2200 
2201  if (tmask != DTK_TIME_M)
2202  return DTERR_BAD_FORMAT;
2203  break;
2204 
2205  default:
2206  return DTERR_BAD_FORMAT;
2207  break;
2208  }
2209 
2210  ptype = 0;
2211  *dtype = DTK_DATE;
2212  }
2213  else
2214  {
2215  char *cp;
2216  int flen;
2217 
2218  flen = strlen(field[i]);
2219  cp = strchr(field[i], '.');
2220 
2221  /* Embedded decimal? */
2222  if (cp != NULL)
2223  {
2224  /*
2225  * Under limited circumstances, we will accept a
2226  * date...
2227  */
2228  if (i == 0 && nf >= 2 && ftype[nf - 1] == DTK_DATE)
2229  {
2230  dterr = DecodeDate(field[i], fmask,
2231  &tmask, &is2digits, tm);
2232  if (dterr)
2233  return dterr;
2234  }
2235  /* embedded decimal and several digits before? */
2236  else if (flen - strlen(cp) > 2)
2237  {
2238  /*
2239  * Interpret as a concatenated date or time Set
2240  * the type field to allow decoding other fields
2241  * later. Example: 20011223 or 040506
2242  */
2243  dterr = DecodeNumberField(flen, field[i],
2244  (fmask | DTK_DATE_M),
2245  &tmask, tm,
2246  fsec, &is2digits);
2247  if (dterr < 0)
2248  return dterr;
2249  ftype[i] = dterr;
2250  }
2251  else
2252  return DTERR_BAD_FORMAT;
2253  }
2254  else if (flen > 4)
2255  {
2256  dterr = DecodeNumberField(flen, field[i],
2257  (fmask | DTK_DATE_M),
2258  &tmask, tm,
2259  fsec, &is2digits);
2260  if (dterr < 0)
2261  return dterr;
2262  ftype[i] = dterr;
2263  }
2264  /* otherwise it is a single date/time field... */
2265  else
2266  {
2267  dterr = DecodeNumber(flen, field[i],
2268  false,
2269  (fmask | DTK_DATE_M),
2270  &tmask, tm,
2271  fsec, &is2digits);
2272  if (dterr)
2273  return dterr;
2274  }
2275  }
2276  break;
2277 
2278  case DTK_STRING:
2279  case DTK_SPECIAL:
2280  /* timezone abbrevs take precedence over built-in tokens */
2281  type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
2282  if (type == UNKNOWN_FIELD)
2283  type = DecodeSpecial(i, field[i], &val);
2284  if (type == IGNORE_DTF)
2285  continue;
2286 
2287  tmask = DTK_M(type);
2288  switch (type)
2289  {
2290  case RESERV:
2291  switch (val)
2292  {
2293  case DTK_NOW:
2294  tmask = DTK_TIME_M;
2295  *dtype = DTK_TIME;
2296  GetCurrentTimeUsec(tm, fsec, NULL);
2297  break;
2298 
2299  case DTK_ZULU:
2300  tmask = (DTK_TIME_M | DTK_M(TZ));
2301  *dtype = DTK_TIME;
2302  tm->tm_hour = 0;
2303  tm->tm_min = 0;
2304  tm->tm_sec = 0;
2305  tm->tm_isdst = 0;
2306  break;
2307 
2308  default:
2309  return DTERR_BAD_FORMAT;
2310  }
2311 
2312  break;
2313 
2314  case DTZMOD:
2315 
2316  /*
2317  * daylight savings time modifier (solves "MET DST"
2318  * syntax)
2319  */
2320  tmask |= DTK_M(DTZ);
2321  tm->tm_isdst = 1;
2322  if (tzp == NULL)
2323  return DTERR_BAD_FORMAT;
2324  *tzp -= val;
2325  break;
2326 
2327  case DTZ:
2328 
2329  /*
2330  * set mask for TZ here _or_ check for DTZ later when
2331  * getting default timezone
2332  */
2333  tmask |= DTK_M(TZ);
2334  tm->tm_isdst = 1;
2335  if (tzp == NULL)
2336  return DTERR_BAD_FORMAT;
2337  *tzp = -val;
2338  ftype[i] = DTK_TZ;
2339  break;
2340 
2341  case TZ:
2342  tm->tm_isdst = 0;
2343  if (tzp == NULL)
2344  return DTERR_BAD_FORMAT;
2345  *tzp = -val;
2346  ftype[i] = DTK_TZ;
2347  break;
2348 
2349  case DYNTZ:
2350  tmask |= DTK_M(TZ);
2351  if (tzp == NULL)
2352  return DTERR_BAD_FORMAT;
2353  /* we'll determine the actual offset later */
2354  abbrevTz = valtz;
2355  abbrev = field[i];
2356  ftype[i] = DTK_TZ;
2357  break;
2358 
2359  case AMPM:
2360  mer = val;
2361  break;
2362 
2363  case ADBC:
2364  bc = (val == BC);
2365  break;
2366 
2367  case UNITS:
2368  tmask = 0;
2369  ptype = val;
2370  break;
2371 
2372  case ISOTIME:
2373  tmask = 0;
2374 
2375  /***
2376  * We will need one of the following fields:
2377  * DTK_NUMBER should be hhmmss.fff
2378  * DTK_TIME should be hh:mm:ss.fff
2379  * DTK_DATE should be hhmmss-zz
2380  ***/
2381  if (i >= nf - 1 ||
2382  (ftype[i + 1] != DTK_NUMBER &&
2383  ftype[i + 1] != DTK_TIME &&
2384  ftype[i + 1] != DTK_DATE))
2385  return DTERR_BAD_FORMAT;
2386 
2387  ptype = val;
2388  break;
2389 
2390  case UNKNOWN_FIELD:
2391 
2392  /*
2393  * Before giving up and declaring error, check to see
2394  * if it is an all-alpha timezone name.
2395  */
2396  namedTz = pg_tzset(field[i]);
2397  if (!namedTz)
2398  return DTERR_BAD_FORMAT;
2399  /* we'll apply the zone setting below */
2400  tmask = DTK_M(TZ);
2401  break;
2402 
2403  default:
2404  return DTERR_BAD_FORMAT;
2405  }
2406  break;
2407 
2408  default:
2409  return DTERR_BAD_FORMAT;
2410  }
2411 
2412  if (tmask & fmask)
2413  return DTERR_BAD_FORMAT;
2414  fmask |= tmask;
2415  } /* end loop over fields */
2416 
2417  /* do final checking/adjustment of Y/M/D fields */
2418  dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
2419  if (dterr)
2420  return dterr;
2421 
2422  /* handle AM/PM */
2423  if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
2424  return DTERR_FIELD_OVERFLOW;
2425  if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
2426  tm->tm_hour = 0;
2427  else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
2428  tm->tm_hour += HOURS_PER_DAY / 2;
2429 
2430  /* check for time overflow */
2431  if (time_overflows(tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec))
2432  return DTERR_FIELD_OVERFLOW;
2433 
2434  if ((fmask & DTK_TIME_M) != DTK_TIME_M)
2435  return DTERR_BAD_FORMAT;
2436 
2437  /*
2438  * If we had a full timezone spec, compute the offset (we could not do it
2439  * before, because we may need the date to resolve DST status).
2440  */
2441  if (namedTz != NULL)
2442  {
2443  long int gmtoff;
2444 
2445  /* daylight savings time modifier disallowed with full TZ */
2446  if (fmask & DTK_M(DTZMOD))
2447  return DTERR_BAD_FORMAT;
2448 
2449  /* if non-DST zone, we do not need to know the date */
2450  if (pg_get_timezone_offset(namedTz, &gmtoff))
2451  {
2452  *tzp = -(int) gmtoff;
2453  }
2454  else
2455  {
2456  /* a date has to be specified */
2457  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2458  return DTERR_BAD_FORMAT;
2459  *tzp = DetermineTimeZoneOffset(tm, namedTz);
2460  }
2461  }
2462 
2463  /*
2464  * Likewise, if we had a dynamic timezone abbreviation, resolve it now.
2465  */
2466  if (abbrevTz != NULL)
2467  {
2468  struct pg_tm tt,
2469  *tmp = &tt;
2470 
2471  /*
2472  * daylight savings time modifier but no standard timezone? then error
2473  */
2474  if (fmask & DTK_M(DTZMOD))
2475  return DTERR_BAD_FORMAT;
2476 
2477  if ((fmask & DTK_DATE_M) == 0)
2478  GetCurrentDateTime(tmp);
2479  else
2480  {
2481  /* a date has to be specified */
2482  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2483  return DTERR_BAD_FORMAT;
2484  tmp->tm_year = tm->tm_year;
2485  tmp->tm_mon = tm->tm_mon;
2486  tmp->tm_mday = tm->tm_mday;
2487  }
2488  tmp->tm_hour = tm->tm_hour;
2489  tmp->tm_min = tm->tm_min;
2490  tmp->tm_sec = tm->tm_sec;
2491  *tzp = DetermineTimeZoneAbbrevOffset(tmp, abbrev, abbrevTz);
2492  tm->tm_isdst = tmp->tm_isdst;
2493  }
2494 
2495  /* timezone not specified? then use session timezone */
2496  if (tzp != NULL && !(fmask & DTK_M(TZ)))
2497  {
2498  struct pg_tm tt,
2499  *tmp = &tt;
2500 
2501  /*
2502  * daylight savings time modifier but no standard timezone? then error
2503  */
2504  if (fmask & DTK_M(DTZMOD))
2505  return DTERR_BAD_FORMAT;
2506 
2507  if ((fmask & DTK_DATE_M) == 0)
2508  GetCurrentDateTime(tmp);
2509  else
2510  {
2511  /* a date has to be specified */
2512  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2513  return DTERR_BAD_FORMAT;
2514  tmp->tm_year = tm->tm_year;
2515  tmp->tm_mon = tm->tm_mon;
2516  tmp->tm_mday = tm->tm_mday;
2517  }
2518  tmp->tm_hour = tm->tm_hour;
2519  tmp->tm_min = tm->tm_min;
2520  tmp->tm_sec = tm->tm_sec;
2522  tm->tm_isdst = tmp->tm_isdst;
2523  }
2524 
2525  return 0;
2526 }
bool pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff)
Definition: localtime.c:1851

References ADBC, AM, AMPM, BC, DAY, DecodeDate(), DecodeNumber(), DecodeNumberField(), DecodeSpecial(), DecodeTime(), DecodeTimezone(), DecodeTimezoneAbbrev(), DetermineTimeZoneAbbrevOffset(), DetermineTimeZoneOffset(), dt2time(), DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, DTK_ALL_SECS_M, DTK_DATE, DTK_DATE_M, DTK_DAY, DTK_HOUR, DTK_JULIAN, DTK_M, DTK_MINUTE, DTK_MONTH, DTK_NOW, DTK_NUMBER, DTK_SECOND, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TIME_M, DTK_TZ, DTK_YEAR, DTK_ZULU, DTZ, DTZMOD, DYNTZ, ereport, errcode(), errmsg(), ERROR, GetCurrentDateTime(), GetCurrentTimeUsec(), HOUR, HOURS_PER_DAY, HR24, i, IGNORE_DTF, INTERVAL_FULL_RANGE, ISOTIME, j2date(), MINUTE, MONTH, ParseFraction(), ParseFractionalSecond(), pg_get_timezone_offset(), pg_tzset(), PM, RESERV, SECOND, 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, generate_unaccent_rules::type, TZ, UNITS, UNKNOWN_FIELD, USECS_PER_DAY, val, ValidateDate(), value, and YEAR.

Referenced by time_in(), and timetz_in().

◆ DecodeTimezone()

int DecodeTimezone ( char *  str,
int *  tzp 
)

Definition at line 3148 of file datetime.c.

3149 {
3150  int tz;
3151  int hr,
3152  min,
3153  sec = 0;
3154  char *cp;
3155 
3156  /* leading character must be "+" or "-" */
3157  if (*str != '+' && *str != '-')
3158  return DTERR_BAD_FORMAT;
3159 
3160  errno = 0;
3161  hr = strtoint(str + 1, &cp, 10);
3162  if (errno == ERANGE)
3163  return DTERR_TZDISP_OVERFLOW;
3164 
3165  /* explicit delimiter? */
3166  if (*cp == ':')
3167  {
3168  errno = 0;
3169  min = strtoint(cp + 1, &cp, 10);
3170  if (errno == ERANGE)
3171  return DTERR_TZDISP_OVERFLOW;
3172  if (*cp == ':')
3173  {
3174  errno = 0;
3175  sec = strtoint(cp + 1, &cp, 10);
3176  if (errno == ERANGE)
3177  return DTERR_TZDISP_OVERFLOW;
3178  }
3179  }
3180  /* otherwise, might have run things together... */
3181  else if (*cp == '\0' && strlen(str) > 3)
3182  {
3183  min = hr % 100;
3184  hr = hr / 100;
3185  /* we could, but don't, support a run-together hhmmss format */
3186  }
3187  else
3188  min = 0;
3189 
3190  /* Range-check the values; see notes in datatype/timestamp.h */
3191  if (hr < 0 || hr > MAX_TZDISP_HOUR)
3192  return DTERR_TZDISP_OVERFLOW;
3193  if (min < 0 || min >= MINS_PER_HOUR)
3194  return DTERR_TZDISP_OVERFLOW;
3195  if (sec < 0 || sec >= SECS_PER_MINUTE)
3196  return DTERR_TZDISP_OVERFLOW;
3197 
3198  tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec;
3199  if (*str == '-')
3200  tz = -tz;
3201 
3202  *tzp = -tz;
3203 
3204  if (*cp != '\0')
3205  return DTERR_BAD_FORMAT;
3206 
3207  return 0;
3208 }
#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,
char *  lowtoken,
int *  offset,
pg_tz **  tz 
)

Definition at line 3226 of file datetime.c.

3228 {
3229  int type;
3230  const datetkn *tp;
3231 
3232  tp = abbrevcache[field];
3233  /* use strncmp so that we match truncated tokens */
3234  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3235  {
3236  if (zoneabbrevtbl)
3237  tp = datebsearch(lowtoken, zoneabbrevtbl->abbrevs,
3239  else
3240  tp = NULL;
3241  }
3242  if (tp == NULL)
3243  {
3244  type = UNKNOWN_FIELD;
3245  *offset = 0;
3246  *tz = NULL;
3247  }
3248  else
3249  {
3250  abbrevcache[field] = tp;
3251  type = tp->type;
3252  if (type == DYNTZ)
3253  {
3254  *offset = 0;
3256  }
3257  else
3258  {
3259  *offset = tp->value;
3260  *tz = NULL;
3261  }
3262  }
3263 
3264  return type;
3265 }
static const datetkn * abbrevcache[MAXDATEFIELDS]
Definition: datetime.c:261
static TimeZoneAbbrevTable * zoneabbrevtbl
Definition: datetime.c:253
static pg_tz * FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp)
Definition: datetime.c:4885

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

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

◆ DecodeUnits()

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

Definition at line 3988 of file datetime.c.

3989 {
3990  int type;
3991  const datetkn *tp;
3992 
3993  tp = deltacache[field];
3994  /* use strncmp so that we match truncated tokens */
3995  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3996  {
3997  tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
3998  }
3999  if (tp == NULL)
4000  {
4001  type = UNKNOWN_FIELD;
4002  *val = 0;
4003  }
4004  else
4005  {
4006  deltacache[field] = tp;
4007  type = tp->type;
4008  *val = tp->value;
4009  }
4010 
4011  return type;
4012 } /* DecodeUnits() */
static const datetkn * deltacache[MAXDATEFIELDS]
Definition: datetime.c:259

References datebsearch(), deltacache, deltatktbl, szdeltatktbl, datetkn::token, TOKMAXLEN, generate_unaccent_rules::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 1809 of file datetime.c.

1810 {
1811  pg_time_t t;
1812  int zone_offset;
1813  int abbr_offset;
1814  int abbr_isdst;
1815 
1816  /*
1817  * Compute the UTC time we want to probe at. (In event of overflow, we'll
1818  * probe at the epoch, which is a bit random but probably doesn't matter.)
1819  */
1820  zone_offset = DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1821 
1822  /*
1823  * Try to match the abbreviation to something in the zone definition.
1824  */
1825  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1826  &abbr_offset, &abbr_isdst))
1827  {
1828  /* Success, so use the abbrev-specific answers. */
1829  tm->tm_isdst = abbr_isdst;
1830  return abbr_offset;
1831  }
1832 
1833  /*
1834  * No match, so use the answers we already got from
1835  * DetermineTimeZoneOffsetInternal.
1836  */
1837  return zone_offset;
1838 }
static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp, pg_time_t *tp)
Definition: datetime.c:1670
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, int *offset, int *isdst)
Definition: datetime.c:1884
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 1884 of file datetime.c.

1886 {
1887  char upabbr[TZ_STRLEN_MAX + 1];
1888  unsigned char *p;
1889  long int gmtoff;
1890 
1891  /* We need to force the abbrev to upper case */
1892  strlcpy(upabbr, abbr, sizeof(upabbr));
1893  for (p = (unsigned char *) upabbr; *p; p++)
1894  *p = pg_toupper(*p);
1895 
1896  /* Look up the abbrev's meaning at this time in this zone */
1897  if (pg_interpret_timezone_abbrev(upabbr,
1898  &t,
1899  &gmtoff,
1900  isdst,
1901  tzp))
1902  {
1903  /* Change sign to agree with DetermineTimeZoneOffset() */
1904  *offset = (int) -gmtoff;
1905  return true;
1906  }
1907  return false;
1908 }
#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 1847 of file datetime.c.

1849 {
1851  int zone_offset;
1852  int abbr_offset;
1853  int tz;
1854  struct pg_tm tm;
1855  fsec_t fsec;
1856 
1857  /*
1858  * If the abbrev matches anything in the zone data, this is pretty easy.
1859  */
1860  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1861  &abbr_offset, isdst))
1862  return abbr_offset;
1863 
1864  /*
1865  * Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1866  */
1867  if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0)
1868  ereport(ERROR,
1869  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1870  errmsg("timestamp out of range")));
1871 
1872  zone_offset = DetermineTimeZoneOffset(&tm, tzp);
1873  *isdst = tm.tm_isdst;
1874  return zone_offset;
1875 }
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 1670 of file datetime.c.

1671 {
1672  int date,
1673  sec;
1674  pg_time_t day,
1675  mytime,
1676  prevtime,
1677  boundary,
1678  beforetime,
1679  aftertime;
1680  long int before_gmtoff,
1681  after_gmtoff;
1682  int before_isdst,
1683  after_isdst;
1684  int res;
1685 
1686  /*
1687  * First, generate the pg_time_t value corresponding to the given
1688  * y/m/d/h/m/s taken as GMT time. If this overflows, punt and decide the
1689  * timezone is GMT. (For a valid Julian date, integer overflow should be
1690  * impossible with 64-bit pg_time_t, but let's check for safety.)
1691  */
1693  goto overflow;
1695 
1696  day = ((pg_time_t) date) * SECS_PER_DAY;
1697  if (day / SECS_PER_DAY != date)
1698  goto overflow;
1700  mytime = day + sec;
1701  /* since sec >= 0, overflow could only be from +day to -mytime */
1702  if (mytime < 0 && day > 0)
1703  goto overflow;
1704 
1705  /*
1706  * Find the DST time boundary just before or following the target time. We
1707  * assume that all zones have GMT offsets less than 24 hours, and that DST
1708  * boundaries can't be closer together than 48 hours, so backing up 24
1709  * hours and finding the "next" boundary will work.
1710  */
1711  prevtime = mytime - SECS_PER_DAY;
1712  if (mytime < 0 && prevtime > 0)
1713  goto overflow;
1714 
1715  res = pg_next_dst_boundary(&prevtime,
1716  &before_gmtoff, &before_isdst,
1717  &boundary,
1718  &after_gmtoff, &after_isdst,
1719  tzp);
1720  if (res < 0)
1721  goto overflow; /* failure? */
1722 
1723  if (res == 0)
1724  {
1725  /* Non-DST zone, life is simple */
1726  tm->tm_isdst = before_isdst;
1727  *tp = mytime - before_gmtoff;
1728  return -(int) before_gmtoff;
1729  }
1730 
1731  /*
1732  * Form the candidate pg_time_t values with local-time adjustment
1733  */
1734  beforetime = mytime - before_gmtoff;
1735  if ((before_gmtoff > 0 &&
1736  mytime < 0 && beforetime > 0) ||
1737  (before_gmtoff <= 0 &&
1738  mytime > 0 && beforetime < 0))
1739  goto overflow;
1740  aftertime = mytime - after_gmtoff;
1741  if ((after_gmtoff > 0 &&
1742  mytime < 0 && aftertime > 0) ||
1743  (after_gmtoff <= 0 &&
1744  mytime > 0 && aftertime < 0))
1745  goto overflow;
1746 
1747  /*
1748  * If both before or both after the boundary time, we know what to do. The
1749  * boundary time itself is considered to be after the transition, which
1750  * means we can accept aftertime == boundary in the second case.
1751  */
1752  if (beforetime < boundary && aftertime < boundary)
1753  {
1754  tm->tm_isdst = before_isdst;
1755  *tp = beforetime;
1756  return -(int) before_gmtoff;
1757  }
1758  if (beforetime > boundary && aftertime >= boundary)
1759  {
1760  tm->tm_isdst = after_isdst;
1761  *tp = aftertime;
1762  return -(int) after_gmtoff;
1763  }
1764 
1765  /*
1766  * It's an invalid or ambiguous time due to timezone transition. In a
1767  * spring-forward transition, prefer the "before" interpretation; in a
1768  * fall-back transition, prefer "after". (We used to define and implement
1769  * this test as "prefer the standard-time interpretation", but that rule
1770  * does not help to resolve the behavior when both times are reported as
1771  * standard time; which does happen, eg Europe/Moscow in Oct 2014. Also,
1772  * in some zones such as Europe/Dublin, there is widespread confusion
1773  * about which time offset is "standard" time, so it's fortunate that our
1774  * behavior doesn't depend on that.)
1775  */
1776  if (beforetime > aftertime)
1777  {
1778  tm->tm_isdst = before_isdst;
1779  *tp = beforetime;
1780  return -(int) before_gmtoff;
1781  }
1782  tm->tm_isdst = after_isdst;
1783  *tp = aftertime;
1784  return -(int) after_gmtoff;
1785 
1786 overflow:
1787  /* Given date is out of range, so assume UTC */
1788  tm->tm_isdst = 0;
1789  *tp = 0;
1790  return 0;
1791 }
#define IS_VALID_JULIAN(y, m, d)
Definition: timestamp.h:194
#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 4144 of file datetime.c.

4145 {
4146  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
4147 
4148  switch (style)
4149  {
4150  case USE_ISO_DATES:
4151  case USE_XSD_DATES:
4152  /* compatible with ISO date formats */
4154  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4155  *str++ = '-';
4157  *str++ = '-';
4159  break;
4160 
4161  case USE_SQL_DATES:
4162  /* compatible with Oracle/Ingres date formats */
4163  if (DateOrder == DATEORDER_DMY)
4164  {
4166  *str++ = '/';
4168  }
4169  else
4170  {
4172  *str++ = '/';
4174  }
4175  *str++ = '/';
4177  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4178  break;
4179 
4180  case USE_GERMAN_DATES:
4181  /* German-style date format */
4183  *str++ = '.';
4185  *str++ = '.';
4187  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4188  break;
4189 
4190  case USE_POSTGRES_DATES:
4191  default:
4192  /* traditional date-only style for Postgres */
4193  if (DateOrder == DATEORDER_DMY)
4194  {
4196  *str++ = '-';
4198  }
4199  else
4200  {
4202  *str++ = '-';
4204  }
4205  *str++ = '-';
4207  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4208  break;
4209  }
4210 
4211  if (tm->tm_year <= 0)
4212  {
4213  memcpy(str, " BC", 3); /* Don't copy NUL */
4214  str += 3;
4215  }
4216  *str = '\0';
4217 }
#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 4259 of file datetime.c.

4260 {
4261  int day;
4262 
4263  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
4264 
4265  /*
4266  * Negative tm_isdst means we have no valid time zone translation.
4267  */
4268  if (tm->tm_isdst < 0)
4269  print_tz = false;
4270 
4271  switch (style)
4272  {
4273  case USE_ISO_DATES:
4274  case USE_XSD_DATES:
4275  /* Compatible with ISO-8601 date formats */
4277  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4278  *str++ = '-';
4280  *str++ = '-';
4282  *str++ = (style == USE_ISO_DATES) ? ' ' : 'T';
4284  *str++ = ':';
4286  *str++ = ':';
4287  str = AppendTimestampSeconds(str, tm, fsec);
4288  if (print_tz)
4289  str = EncodeTimezone(str, tz, style);
4290  break;
4291 
4292  case USE_SQL_DATES:
4293  /* Compatible with Oracle/Ingres date formats */
4294  if (DateOrder == DATEORDER_DMY)
4295  {
4297  *str++ = '/';
4299  }
4300  else
4301  {
4303  *str++ = '/';
4305  }
4306  *str++ = '/';
4308  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4309  *str++ = ' ';
4311  *str++ = ':';
4313  *str++ = ':';
4314  str = AppendTimestampSeconds(str, tm, fsec);
4315 
4316  /*
4317  * Note: the uses of %.*s in this function would be risky if the
4318  * timezone names ever contain non-ASCII characters, since we are
4319  * not being careful to do encoding-aware clipping. However, all
4320  * TZ abbreviations in the IANA database are plain ASCII.
4321  */
4322  if (print_tz)
4323  {
4324  if (tzn)
4325  {
4326  sprintf(str, " %.*s", MAXTZLEN, tzn);
4327  str += strlen(str);
4328  }
4329  else
4330  str = EncodeTimezone(str, tz, style);
4331  }
4332  break;
4333 
4334  case USE_GERMAN_DATES:
4335  /* German variant on European style */
4337  *str++ = '.';
4339  *str++ = '.';
4341  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4342  *str++ = ' ';
4344  *str++ = ':';
4346  *str++ = ':';
4347  str = AppendTimestampSeconds(str, tm, fsec);
4348 
4349  if (print_tz)
4350  {
4351  if (tzn)
4352  {
4353  sprintf(str, " %.*s", MAXTZLEN, tzn);
4354  str += strlen(str);
4355  }
4356  else
4357  str = EncodeTimezone(str, tz, style);
4358  }
4359  break;
4360 
4361  case USE_POSTGRES_DATES:
4362  default:
4363  /* Backward-compatible with traditional Postgres abstime dates */
4364  day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4365  tm->tm_wday = j2day(day);
4366  memcpy(str, days[tm->tm_wday], 3);
4367  str += 3;
4368  *str++ = ' ';
4369  if (DateOrder == DATEORDER_DMY)
4370  {
4372  *str++ = ' ';
4373  memcpy(str, months[tm->tm_mon - 1], 3);
4374  str += 3;
4375  }
4376  else
4377  {
4378  memcpy(str, months[tm->tm_mon - 1], 3);
4379  str += 3;
4380  *str++ = ' ';
4382  }
4383  *str++ = ' ';
4385  *str++ = ':';
4387  *str++ = ':';
4388  str = AppendTimestampSeconds(str, tm, fsec);
4389  *str++ = ' ';
4391  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4392 
4393  if (print_tz)
4394  {
4395  if (tzn)
4396  {
4397  sprintf(str, " %.*s", MAXTZLEN, tzn);
4398  str += strlen(str);
4399  }
4400  else
4401  {
4402  /*
4403  * We have a time zone, but no string version. Use the
4404  * numeric form, but be sure to include a leading space to
4405  * avoid formatting something which would be rejected by
4406  * the date/time parser later. - thomas 2001-10-19
4407  */
4408  *str++ = ' ';
4409  str = EncodeTimezone(str, tz, style);
4410  }
4411  }
4412  break;
4413  }
4414 
4415  if (tm->tm_year <= 0)
4416  {
4417  memcpy(str, " BC", 3); /* Don't copy NUL */
4418  str += 3;
4419  }
4420  *str = '\0';
4421 }
static char * EncodeTimezone(char *str, int tz, int style)
Definition: datetime.c:4106
int j2day(int date)
Definition: datetime.c:343
const char *const months[]
Definition: datetime.c:81
static char * AppendTimestampSeconds(char *cp, struct pg_tm *tm, fsec_t fsec)
Definition: datetime.c:510
#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 4502 of file datetime.c.

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

4230 {
4232  *str++ = ':';
4234  *str++ = ':';
4235  str = AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
4236  if (print_tz)
4237  str = EncodeTimezone(str, tz, style);
4238  *str = '\0';
4239 }
#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 4106 of file datetime.c.

4107 {
4108  int hour,
4109  min,
4110  sec;
4111 
4112  sec = abs(tz);
4113  min = sec / SECS_PER_MINUTE;
4114  sec -= min * SECS_PER_MINUTE;
4115  hour = min / MINS_PER_HOUR;
4116  min -= hour * MINS_PER_HOUR;
4117 
4118  /* TZ is negated compared to sign we wish to display ... */
4119  *str++ = (tz <= 0 ? '+' : '-');
4120 
4121  if (sec != 0)
4122  {
4123  str = pg_ultostr_zeropad(str, hour, 2);
4124  *str++ = ':';
4125  str = pg_ultostr_zeropad(str, min, 2);
4126  *str++ = ':';
4127  str = pg_ultostr_zeropad(str, sec, 2);
4128  }
4129  else if (min != 0 || style == USE_XSD_DATES)
4130  {
4131  str = pg_ultostr_zeropad(str, hour, 2);
4132  *str++ = ':';
4133  str = pg_ultostr_zeropad(str, min, 2);
4134  }
4135  else
4136  str = pg_ultostr_zeropad(str, hour, 2);
4137  return str;
4138 }

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 
)
static

Definition at line 4885 of file datetime.c.

4886 {
4887  DynamicZoneAbbrev *dtza;
4888 
4889  /* Just some sanity checks to prevent indexing off into nowhere */
4890  Assert(tp->type == DYNTZ);
4891  Assert(tp->value > 0 && tp->value < tbl->tblsize);
4892 
4893  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tp->value);
4894 
4895  /* Look up the underlying zone if we haven't already */
4896  if (dtza->tz == NULL)
4897  {
4898  dtza->tz = pg_tzset(dtza->zone);
4899 
4900  /*
4901  * Ideally we'd let the caller ereport instead of doing it here, but
4902  * then there is no way to report the bad time zone name.
4903  */
4904  if (dtza->tz == NULL)
4905  ereport(ERROR,
4906  (errcode(ERRCODE_CONFIG_FILE_ERROR),
4907  errmsg("time zone \"%s\" not recognized",
4908  dtza->zone),
4909  errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".",
4910  tp->token)));
4911  }
4912  return dtza->tz;
4913 }
int errdetail(const char *fmt,...)
Definition: elog.c:1039

References Assert(), DYNTZ, ereport, errcode(), errdetail(), errmsg(), ERROR, 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 365 of file datetime.c.

366 {
367  fsec_t fsec;
368 
369  GetCurrentTimeUsec(tm, &fsec, NULL);
370 }

References GetCurrentTimeUsec(), and tm.

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

◆ GetCurrentTimeUsec()

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

Definition at line 386 of file datetime.c.

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

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

Referenced by current_time(), DecodeDateTime(), DecodeTimeOnly(), GetCurrentDateTime(), and sql_localtime().

◆ InstallTimeZoneAbbrevs()

void InstallTimeZoneAbbrevs ( TimeZoneAbbrevTable tbl)

Definition at line 4874 of file datetime.c.

4875 {
4876  zoneabbrevtbl = tbl;
4877  /* reset abbrevcache, which may contain pointers into old table */
4878  memset(abbrevcache, 0, sizeof(abbrevcache));
4879 }

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 521 of file datetime.c.

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

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 3743 of file datetime.c.

3744 {
3745  /* We might have had a leading '-' */
3746  if (*fieldstart == '-')
3747  fieldstart++;
3748  return strspn(fieldstart, "0123456789");
3749 }

Referenced by DecodeISO8601Interval().

◆ j2date()

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

Definition at line 310 of file datetime.c.

311 {
312  unsigned int julian;
313  unsigned int quad;
314  unsigned int extra;
315  int y;
316 
317  julian = jd;
318  julian += 32044;
319  quad = julian / 146097;
320  extra = (julian - quad * 146097) * 4 + 3;
321  julian += 60 + quad * 3 + extra / 146097;
322  quad = julian / 1461;
323  julian -= quad * 1461;
324  y = julian * 4 / 1461;
325  julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
326  + 123;
327  y += quad * 4;
328  *year = y - 4800;
329  quad = julian * 2141 / 65536;
330  *day = julian - 7834 * quad / 256;
331  *month = (quad + 10) % MONTHS_PER_YEAR + 1;
332 } /* 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(), and ValidateDate().

◆ j2day()

int j2day ( int  date)

Definition at line 343 of file datetime.c.

344 {
345  date += 1;
346  date %= 7;
347  /* Cope if division truncates towards zero, as it probably does */
348  if (date < 0)
349  date += 7;
350 
351  return date;
352 } /* 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 753 of file datetime.c.

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

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

References Assert(), and DTERR_BAD_FORMAT.

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

◆ ParseFractionalSecond()

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

Definit