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/memutils.h"
#include "utils/tzparser.h"
Include dependency graph for datetime.c:

Go to the source code of this file.

Macros

#define APPEND_CHAR(bufptr, end, newchar)
 

Functions

static int DecodeNumber (int flen, char *field, bool haveTextMonth, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
 
static int DecodeNumberField (int len, char *str, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
 
static int 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 y, int m, int d)
 
void j2date (int jd, int *year, int *month, int *day)
 
int j2day (int date)
 
void GetCurrentDateTime (struct pg_tm *tm)
 
void GetCurrentTimeUsec (struct pg_tm *tm, fsec_t *fsec, int *tzp)
 
static char * AppendTimestampSeconds (char *cp, struct pg_tm *tm, fsec_t fsec)
 
static int 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 4429 of file datetime.c.

4430 {
4431  if (value == 0)
4432  return cp;
4433  sprintf(cp, "%lld%c", (long long) value, units);
4434  return cp + strlen(cp);
4435 }
static struct @151 value
#define sprintf
Definition: port.h:227

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

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

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

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

References Abs, sprintf, and value.

Referenced by EncodeInterval().

◆ AdjustDays()

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

Definition at line 631 of file datetime.c.

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

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

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

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

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

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

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

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

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

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

References Abs, 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 509 of file datetime.c.

510 {
511  return AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
512 }
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:446
#define MAX_TIMESTAMP_PRECISION
Definition: timestamp.h:92
static struct pg_tm tm
Definition: localtime.c:102
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 4695 of file datetime.c.

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

4728 {
4729  bool ok = true;
4730 
4731  Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1));
4732  Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1));
4733 
4734  ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
4735  ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
4736  return ok;
4737 }
static bool CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
Definition: datetime.c:4695
static const datetkn datetktbl[]
Definition: datetime.c:104
int date2j(int y, int m, int d)
Definition: datetime.c:284
static const int szdeltatktbl
Definition: datetime.c:250
static const int szdatetktbl
Definition: datetime.c:179
static const datetkn deltatktbl[]
Definition: datetime.c:185
#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 3312 of file datetime.c.

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

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

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

Definition at line 284 of file datetime.c.

285 {
286  int julian;
287  int century;
288 
289  if (m > 2)
290  {
291  m += 1;
292  y += 4800;
293  }
294  else
295  {
296  m += 13;
297  y += 4799;
298  }
299 
300  century = y / 100;
301  julian = y * 365 - 32167;
302  julian += y / 4 - century + century / 4;
303  julian += 7834 * m / 256 + d;
304 
305  return julian;
306 } /* date2j() */
int y
Definition: isn.c:72

References y.

Referenced by CheckDateTokenTables(), date2isoweek(), date2isoyear(), date2isoyearday(), date_in(), DCH_to_char(), DecodeDateTime(), DetermineTimeZoneOffsetInternal(), EncodeDateTime(), extract_date(), GetSQLCurrentDate(), isoweek2j(), make_date(), make_timestamp_internal(), parse_datetime(), PGTYPESdate_dayofweek(), PGTYPESdate_defmt_asc(), PGTYPESdate_fmt_asc(), PGTYPESdate_from_asc(), PGTYPESdate_julmdy(), PGTYPESdate_mdyjul(), PGTYPESdate_to_asc(), PGTYPESdate_today(), timestamp2tm(), timestamp_date(), timestamp_part_common(), timestamp_pl_interval(), timestamp_to_char(), timestamptz_date(), timestamptz_part_common(), timestamptz_pl_interval(), 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 4069 of file datetime.c.

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

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

4025 {
4026  switch (dterr)
4027  {
4028  case DTERR_FIELD_OVERFLOW:
4029  ereport(ERROR,
4030  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
4031  errmsg("date/time field value out of range: \"%s\"",
4032  str)));
4033  break;
4035  /* <nanny>same as above, but add hint about DateStyle</nanny> */
4036  ereport(ERROR,
4037  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
4038  errmsg("date/time field value out of range: \"%s\"",
4039  str),
4040  errhint("Perhaps you need a different \"datestyle\" setting.")));
4041  break;
4043  ereport(ERROR,
4044  (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
4045  errmsg("interval field value out of range: \"%s\"",
4046  str)));
4047  break;
4048  case DTERR_TZDISP_OVERFLOW:
4049  ereport(ERROR,
4050  (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
4051  errmsg("time zone displacement out of range: \"%s\"",
4052  str)));
4053  break;
4054  case DTERR_BAD_FORMAT:
4055  default:
4056  ereport(ERROR,
4057  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4058  errmsg("invalid input syntax for type %s: \"%s\"",
4059  datatype, str)));
4060  break;
4061  }
4062 }
int errhint(const char *fmt,...)
Definition: elog.c:1151
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
#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 2538 of file datetime.c.

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

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

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(), 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 3333 of file datetime.c.

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

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

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

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 *  field,
bool  haveTextMonth,
int  fmask,
int *  tmask,
struct pg_tm tm,
fsec_t fsec,
bool is2digits 
)
static

Definition at line 2867 of file datetime.c.

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

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

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

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

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

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

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

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

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

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

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

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(), and YEAR.

Referenced by time_in(), and timetz_in().

◆ DecodeTimezone()

int DecodeTimezone ( char *  str,
int *  tzp 
)

Definition at line 3147 of file datetime.c.

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

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

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

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

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

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

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

1848 {
1850  int zone_offset;
1851  int abbr_offset;
1852  int tz;
1853  struct pg_tm tm;
1854  fsec_t fsec;
1855 
1856  /*
1857  * If the abbrev matches anything in the zone data, this is pretty easy.
1858  */
1859  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1860  &abbr_offset, isdst))
1861  return abbr_offset;
1862 
1863  /*
1864  * Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1865  */
1866  if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0)
1867  ereport(ERROR,
1868  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1869  errmsg("timestamp out of range")));
1870 
1871  zone_offset = DetermineTimeZoneOffset(&tm, tzp);
1872  *isdst = tm.tm_isdst;
1873  return zone_offset;
1874 }
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1816
pg_time_t timestamptz_to_time_t(TimestampTz t)
Definition: timestamp.c:1748

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

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

4144 {
4145  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
4146 
4147  switch (style)
4148  {
4149  case USE_ISO_DATES:
4150  case USE_XSD_DATES:
4151  /* compatible with ISO date formats */
4153  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4154  *str++ = '-';
4156  *str++ = '-';
4158  break;
4159 
4160  case USE_SQL_DATES:
4161  /* compatible with Oracle/Ingres date formats */
4162  if (DateOrder == DATEORDER_DMY)
4163  {
4165  *str++ = '/';
4167  }
4168  else
4169  {
4171  *str++ = '/';
4173  }
4174  *str++ = '/';
4176  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4177  break;
4178 
4179  case USE_GERMAN_DATES:
4180  /* German-style date format */
4182  *str++ = '.';
4184  *str++ = '.';
4186  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4187  break;
4188 
4189  case USE_POSTGRES_DATES:
4190  default:
4191  /* traditional date-only style for Postgres */
4192  if (DateOrder == DATEORDER_DMY)
4193  {
4195  *str++ = '-';
4197  }
4198  else
4199  {
4201  *str++ = '-';
4203  }
4204  *str++ = '-';
4206  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4207  break;
4208  }
4209 
4210  if (tm->tm_year <= 0)
4211  {
4212  memcpy(str, " BC", 3); /* Don't copy NUL */
4213  str += 3;
4214  }
4215  *str = '\0';
4216 }
#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 4258 of file datetime.c.

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

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

4229 {
4231  *str++ = ':';
4233  *str++ = ':';
4234  str = AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
4235  if (print_tz)
4236  str = EncodeTimezone(str, tz, style);
4237  *str = '\0';
4238 }
#define MAX_TIME_PRECISION
Definition: date.h:51

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

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

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

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

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

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

References GetCurrentTimeUsec(), and tm.

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

◆ GetCurrentTimeUsec()

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

Definition at line 385 of file datetime.c.

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

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

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

◆ InstallTimeZoneAbbrevs()

void InstallTimeZoneAbbrevs ( TimeZoneAbbrevTable tbl)

Definition at line 4873 of file datetime.c.

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

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

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

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

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

Referenced by DecodeISO8601Interval().

◆ j2date()

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

Definition at line 309 of file datetime.c.

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

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

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

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

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

References Assert(), and DTERR_BAD_FORMAT.

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

◆