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

Go to the source code of this file.

Macros

#define APPEND_CHAR(bufptr, end, newchar)
 

Functions

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

Variables

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

Macro Definition Documentation

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

Referenced by ParseDateTime().

Function Documentation

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

Definition at line 4275 of file datetime.c.

Referenced by EncodeInterval().

4276 {
4277  if (value == 0)
4278  return cp;
4279  sprintf(cp, "%d%c", value, units);
4280  return cp + strlen(cp);
4281 }
static struct @76 value
static char* AddPostgresIntPart ( char *  cp,
int  value,
const char *  units,
bool is_zero,
bool is_before 
)
static

Definition at line 4285 of file datetime.c.

References FALSE.

Referenced by EncodeInterval().

4287 {
4288  if (value == 0)
4289  return cp;
4290  sprintf(cp, "%s%s%d %s%s",
4291  (!*is_zero) ? " " : "",
4292  (*is_before && value > 0) ? "+" : "",
4293  value,
4294  units,
4295  (value != 1) ? "s" : "");
4296 
4297  /*
4298  * Each nonzero field sets is_before for (only) the next one. This is a
4299  * tad bizarre but it's how it worked before...
4300  */
4301  *is_before = (value < 0);
4302  *is_zero = FALSE;
4303  return cp + strlen(cp);
4304 }
static struct @76 value
#define FALSE
Definition: c.h:218
static char* AddVerboseIntPart ( char *  cp,
int  value,
const char *  units,
bool is_zero,
bool is_before 
)
static

Definition at line 4308 of file datetime.c.

References FALSE, and value.

Referenced by EncodeInterval().

4310 {
4311  if (value == 0)
4312  return cp;
4313  /* first nonzero value sets is_before */
4314  if (*is_zero)
4315  {
4316  *is_before = (value < 0);
4317  value = abs(value);
4318  }
4319  else if (*is_before)
4320  value = -value;
4321  sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
4322  *is_zero = FALSE;
4323  return cp + strlen(cp);
4324 }
static struct @76 value
#define FALSE
Definition: c.h:218
static void AdjustFractDays ( double  frac,
struct pg_tm tm,
fsec_t fsec,
int  scale 
)
static

Definition at line 559 of file datetime.c.

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

Referenced by DecodeInterval(), and DecodeISO8601Interval().

560 {
561  int extra_days;
562 
563  if (frac == 0)
564  return;
565  frac *= scale;
566  extra_days = (int) frac;
567  tm->tm_mday += extra_days;
568  frac -= extra_days;
569  AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
570 }
int scale
Definition: pgbench.c:106
static void AdjustFractSeconds(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:540
#define SECS_PER_DAY
Definition: timestamp.h:98
int tm_mday
Definition: pgtime.h:30
static void AdjustFractSeconds ( double  frac,
struct pg_tm tm,
fsec_t fsec,
int  scale 
)
static

Definition at line 540 of file datetime.c.

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

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

541 {
542  int sec;
543 
544  if (frac == 0)
545  return;
546  frac *= scale;
547  sec = (int) frac;
548  tm->tm_sec += sec;
549  frac -= sec;
550 #ifdef HAVE_INT64_TIMESTAMP
551  *fsec += rint(frac * 1000000);
552 #else
553  *fsec += frac;
554 #endif
555 }
int scale
Definition: pgbench.c:106
double rint(double x)
Definition: rint.c:22
int tm_sec
Definition: pgtime.h:27
static char * AppendSeconds ( char *  cp,
int  sec,
fsec_t  fsec,
int  precision,
bool  fillzeros 
)
static

Definition at line 438 of file datetime.c.

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

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

439 {
440  Assert(precision >= 0);
441 
442 #ifdef HAVE_INT64_TIMESTAMP
443  /* fsec_t is just an int32 */
444 
445  if (fillzeros)
446  cp = pg_ltostr_zeropad(cp, Abs(sec), 2);
447  else
448  cp = pg_ltostr(cp, Abs(sec));
449 
450  if (fsec != 0)
451  {
452  int32 value = Abs(fsec);
453  char *end = &cp[precision + 1];
454  bool gotnonzero = false;
455 
456  *cp++ = '.';
457 
458  /*
459  * Append the fractional seconds part. Note that we don't want any
460  * trailing zeros here, so since we're building the number in reverse
461  * we'll skip appending zeros until we've output a non-zero digit.
462  */
463  while (precision--)
464  {
465  int32 oldval = value;
466  int32 remainder;
467 
468  value /= 10;
469  remainder = oldval - value * 10;
470 
471  /* check if we got a non-zero */
472  if (remainder)
473  gotnonzero = true;
474 
475  if (gotnonzero)
476  cp[precision] = '0' + remainder;
477  else
478  end = &cp[precision];
479  }
480 
481  /*
482  * If we still have a non-zero value then precision must have not been
483  * enough to print the number. We punt the problem to pg_ltostr(),
484  * which will generate a correct answer in the minimum valid width.
485  */
486  if (value)
487  return pg_ltostr(cp, Abs(fsec));
488 
489  return end;
490  }
491  else
492  return cp;
493 #else
494  /* fsec_t is a double */
495 
496  if (fsec == 0)
497  {
498  if (fillzeros)
499  return pg_ltostr_zeropad(cp, Abs(sec), 2);
500  else
501  return pg_ltostr(cp, Abs(sec));
502  }
503  else
504  {
505  if (fillzeros)
506  sprintf(cp, "%0*.*f", precision + 3, precision, fabs(sec + fsec));
507  else
508  sprintf(cp, "%.*f", precision, fabs(sec + fsec));
509  return TrimTrailingZeros(cp);
510  }
511 #endif /* HAVE_INT64_TIMESTAMP */
512 }
static struct @76 value
signed int int32
Definition: c.h:253
#define Abs(x)
Definition: c.h:807
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
char * pg_ltostr(char *str, int32 value)
Definition: numutils.c:334
#define Assert(condition)
Definition: c.h:670
static char * TrimTrailingZeros(char *str)
Definition: datetime.c:416
static char* AppendTimestampSeconds ( char *  cp,
struct pg_tm tm,
fsec_t  fsec 
)
static

Definition at line 522 of file datetime.c.

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

Referenced by EncodeDateTime().

523 {
524  /*
525  * In float mode, don't print fractional seconds before 1 AD, since it's
526  * unlikely there's any precision left ...
527  */
528 #ifndef HAVE_INT64_TIMESTAMP
529  if (tm->tm_year <= 0)
530  fsec = 0;
531 #endif
532  return AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
533 }
#define MAX_TIMESTAMP_PRECISION
Definition: timestamp.h:65
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:438
int tm_year
Definition: pgtime.h:32
int tm_sec
Definition: pgtime.h:27
static bool CheckDateTokenTable ( const char *  tablename,
const datetkn base,
int  nel 
)
static

Definition at line 4538 of file datetime.c.

References elog, i, LOG, and TOKMAXLEN.

Referenced by CheckDateTokenTables(), and ConvertTimeZoneAbbrevs().

4539 {
4540  bool ok = true;
4541  int i;
4542 
4543  for (i = 0; i < nel; i++)
4544  {
4545  /* check for token strings that don't fit */
4546  if (strlen(base[i].token) > TOKMAXLEN)
4547  {
4548  /* %.*s is safe since all our tokens are ASCII */
4549  elog(LOG, "token too long in %s table: \"%.*s\"",
4550  tablename,
4551  TOKMAXLEN + 1, base[i].token);
4552  ok = false;
4553  break; /* don't risk applying strcmp */
4554  }
4555  /* check for out of order */
4556  if (i > 0 &&
4557  strcmp(base[i - 1].token, base[i].token) >= 0)
4558  {
4559  elog(LOG, "ordering error in %s table: \"%s\" >= \"%s\"",
4560  tablename,
4561  base[i - 1].token,
4562  base[i].token);
4563  ok = false;
4564  }
4565  }
4566  return ok;
4567 }
#define LOG
Definition: elog.h:26
int i
#define TOKMAXLEN
Definition: datetime.h:207
#define elog
Definition: elog.h:219
bool CheckDateTokenTables ( void  )

Definition at line 4570 of file datetime.c.

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

Referenced by PostmasterMain().

4571 {
4572  bool ok = true;
4573 
4574  Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1));
4575  Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1));
4576 
4577  ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
4578  ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
4579  return ok;
4580 }
static const datetkn datetktbl[]
Definition: datetime.c:95
static int szdatetktbl
Definition: datetime.c:173
static bool CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
Definition: datetime.c:4538
static const datetkn deltatktbl[]
Definition: datetime.c:179
int date2j(int y, int m, int d)
Definition: datetime.c:297
static int szdeltatktbl
Definition: datetime.c:246
#define Assert(condition)
Definition: c.h:670
#define UNIX_EPOCH_JDATE
Definition: timestamp.h:184
#define POSTGRES_EPOCH_JDATE
Definition: timestamp.h:185
static void ClearPgTm ( struct pg_tm tm,
fsec_t fsec 
)
inlinestatic

Definition at line 3161 of file datetime.c.

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

Referenced by DecodeInterval(), and DecodeISO8601Interval().

3162 {
3163  tm->tm_year = 0;
3164  tm->tm_mon = 0;
3165  tm->tm_mday = 0;
3166  tm->tm_hour = 0;
3167  tm->tm_min = 0;
3168  tm->tm_sec = 0;
3169  *fsec = 0;
3170 }
int tm_hour
Definition: pgtime.h:29
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
int tm_year
Definition: pgtime.h:32
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
TimeZoneAbbrevTable* ConvertTimeZoneAbbrevs ( struct tzEntry abbrevs,
int  n 
)

Definition at line 4626 of file datetime.c.

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

Referenced by load_tzoffsets().

4627 {
4628  TimeZoneAbbrevTable *tbl;
4629  Size tbl_size;
4630  int i;
4631 
4632  /* Space for fixed fields and datetkn array */
4633  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4634  n * sizeof(datetkn);
4635  tbl_size = MAXALIGN(tbl_size);
4636  /* Count up space for dynamic abbreviations */
4637  for (i = 0; i < n; i++)
4638  {
4639  struct tzEntry *abbr = abbrevs + i;
4640 
4641  if (abbr->zone != NULL)
4642  {
4643  Size dsize;
4644 
4645  dsize = offsetof(DynamicZoneAbbrev, zone) +
4646  strlen(abbr->zone) + 1;
4647  tbl_size += MAXALIGN(dsize);
4648  }
4649  }
4650 
4651  /* Alloc the result ... */
4652  tbl = malloc(tbl_size);
4653  if (!tbl)
4654  return NULL;
4655 
4656  /* ... and fill it in */
4657  tbl->tblsize = tbl_size;
4658  tbl->numabbrevs = n;
4659  /* in this loop, tbl_size reprises the space calculation above */
4660  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4661  n * sizeof(datetkn);
4662  tbl_size = MAXALIGN(tbl_size);
4663  for (i = 0; i < n; i++)
4664  {
4665  struct tzEntry *abbr = abbrevs + i;
4666  datetkn *dtoken = tbl->abbrevs + i;
4667 
4668  /* use strlcpy to truncate name if necessary */
4669  strlcpy(dtoken->token, abbr->abbrev, TOKMAXLEN + 1);
4670  if (abbr->zone != NULL)
4671  {
4672  /* Allocate a DynamicZoneAbbrev for this abbreviation */
4673  DynamicZoneAbbrev *dtza;
4674  Size dsize;
4675 
4676  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tbl_size);
4677  dtza->tz = NULL;
4678  strcpy(dtza->zone, abbr->zone);
4679 
4680  dtoken->type = DYNTZ;
4681  /* value is offset from table start to DynamicZoneAbbrev */
4682  dtoken->value = (int32) tbl_size;
4683 
4684  dsize = offsetof(DynamicZoneAbbrev, zone) +
4685  strlen(abbr->zone) + 1;
4686  tbl_size += MAXALIGN(dsize);
4687  }
4688  else
4689  {
4690  dtoken->type = abbr->is_dst ? DTZ : TZ;
4691  dtoken->value = abbr->offset;
4692  }
4693  }
4694 
4695  /* Assert the two loops above agreed on size calculations */
4696  Assert(tbl->tblsize == tbl_size);
4697 
4698  /* Check the ordering, if testing */
4699  Assert(CheckDateTokenTable("timezone abbreviations", tbl->abbrevs, n));
4700 
4701  return tbl;
4702 }
int offset
Definition: tzparser.h:29
#define TZ
Definition: datetime.h:96
int32 value
Definition: datetime.h:214
signed int int32
Definition: c.h:253
char * zone
Definition: tzparser.h:27
bool is_dst
Definition: tzparser.h:30
#define malloc(a)
Definition: header.h:45
char token[TOKMAXLEN+1]
Definition: datetime.h:212
static bool CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
Definition: datetime.c:4538
datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:222
char * abbrev
Definition: tzparser.h:26
char zone[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:230
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
size_t Size
Definition: c.h:352
#define MAXALIGN(LEN)
Definition: c.h:583
#define DTZ
Definition: datetime.h:97
Definition: zic.c:91
#define DYNTZ
Definition: datetime.h:98
int i
#define TOKMAXLEN
Definition: datetime.h:207
#define offsetof(type, field)
Definition: c.h:550
int date2j ( int  y,
int  m,
int  d 
)

Definition at line 297 of file datetime.c.

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

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

Definition at line 3916 of file datetime.c.

References NULL, and TOKMAXLEN.

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

3917 {
3918  if (nel > 0)
3919  {
3920  const datetkn *last = base + nel - 1,
3921  *position;
3922  int result;
3923 
3924  while (last >= base)
3925  {
3926  position = base + ((last - base) >> 1);
3927  /* precheck the first character for a bit of extra speed */
3928  result = (int) key[0] - (int) position->token[0];
3929  if (result == 0)
3930  {
3931  /* use strncmp so that we match truncated tokens */
3932  result = strncmp(key, position->token, TOKMAXLEN);
3933  if (result == 0)
3934  return position;
3935  }
3936  if (result < 0)
3937  last = position - 1;
3938  else
3939  base = position + 1;
3940  }
3941  }
3942  return NULL;
3943 }
#define NULL
Definition: c.h:226
#define TOKMAXLEN
Definition: datetime.h:207
void DateTimeParseError ( int  dterr,
const char *  str,
const char *  datatype 
)

Definition at line 3871 of file datetime.c.

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

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

3872 {
3873  switch (dterr)
3874  {
3875  case DTERR_FIELD_OVERFLOW:
3876  ereport(ERROR,
3877  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3878  errmsg("date/time field value out of range: \"%s\"",
3879  str)));
3880  break;
3882  /* <nanny>same as above, but add hint about DateStyle</nanny> */
3883  ereport(ERROR,
3884  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3885  errmsg("date/time field value out of range: \"%s\"",
3886  str),
3887  errhint("Perhaps you need a different \"datestyle\" setting.")));
3888  break;
3890  ereport(ERROR,
3891  (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
3892  errmsg("interval field value out of range: \"%s\"",
3893  str)));
3894  break;
3895  case DTERR_TZDISP_OVERFLOW:
3896  ereport(ERROR,
3897  (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
3898  errmsg("time zone displacement out of range: \"%s\"",
3899  str)));
3900  break;
3901  case DTERR_BAD_FORMAT:
3902  default:
3903  ereport(ERROR,
3904  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3905  errmsg("invalid input syntax for type %s: \"%s\"",
3906  datatype, str)));
3907  break;
3908  }
3909 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:290
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:291
#define DTERR_INTERVAL_OVERFLOW
Definition: datetime.h:293
#define ereport(elevel, rest)
Definition: elog.h:122
#define DTERR_TZDISP_OVERFLOW
Definition: datetime.h:294
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define DTERR_MD_FIELD_OVERFLOW
Definition: datetime.h:292
static int DecodeDate ( char *  str,
int  fmask,
int *  tmask,
bool is2digits,
struct pg_tm tm 
)
static

Definition at line 2448 of file datetime.c.

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

Referenced by DecodeDateTime(), and DecodeTimeOnly().

2450 {
2451  fsec_t fsec;
2452  int nf = 0;
2453  int i,
2454  len;
2455  int dterr;
2456  bool haveTextMonth = FALSE;
2457  int type,
2458  val,
2459  dmask = 0;
2460  char *field[MAXDATEFIELDS];
2461 
2462  *tmask = 0;
2463 
2464  /* parse this string... */
2465  while (*str != '\0' && nf < MAXDATEFIELDS)
2466  {
2467  /* skip field separators */
2468  while (*str != '\0' && !isalnum((unsigned char) *str))
2469  str++;
2470 
2471  if (*str == '\0')
2472  return DTERR_BAD_FORMAT; /* end of string after separator */
2473 
2474  field[nf] = str;
2475  if (isdigit((unsigned char) *str))
2476  {
2477  while (isdigit((unsigned char) *str))
2478  str++;
2479  }
2480  else if (isalpha((unsigned char) *str))
2481  {
2482  while (isalpha((unsigned char) *str))
2483  str++;
2484  }
2485 
2486  /* Just get rid of any non-digit, non-alpha characters... */
2487  if (*str != '\0')
2488  *str++ = '\0';
2489  nf++;
2490  }
2491 
2492  /* look first for text fields, since that will be unambiguous month */
2493  for (i = 0; i < nf; i++)
2494  {
2495  if (isalpha((unsigned char) *field[i]))
2496  {
2497  type = DecodeSpecial(i, field[i], &val);
2498  if (type == IGNORE_DTF)
2499  continue;
2500 
2501  dmask = DTK_M(type);
2502  switch (type)
2503  {
2504  case MONTH:
2505  tm->tm_mon = val;
2506  haveTextMonth = TRUE;
2507  break;
2508 
2509  default:
2510  return DTERR_BAD_FORMAT;
2511  }
2512  if (fmask & dmask)
2513  return DTERR_BAD_FORMAT;
2514 
2515  fmask |= dmask;
2516  *tmask |= dmask;
2517 
2518  /* mark this field as being completed */
2519  field[i] = NULL;
2520  }
2521  }
2522 
2523  /* now pick up remaining numeric fields */
2524  for (i = 0; i < nf; i++)
2525  {
2526  if (field[i] == NULL)
2527  continue;
2528 
2529  if ((len = strlen(field[i])) <= 0)
2530  return DTERR_BAD_FORMAT;
2531 
2532  dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,
2533  &dmask, tm,
2534  &fsec, is2digits);
2535  if (dterr)
2536  return dterr;
2537 
2538  if (fmask & dmask)
2539  return DTERR_BAD_FORMAT;
2540 
2541  fmask |= dmask;
2542  *tmask |= dmask;
2543  }
2544 
2545  if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
2546  return DTERR_BAD_FORMAT;
2547 
2548  /* validation of the field values must wait until ValidateDate() */
2549 
2550  return 0;
2551 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:290
#define IGNORE_DTF
Definition: datetime.h:99
double fsec_t
Definition: timestamp.h:53
#define TZ
Definition: datetime.h:96
#define DTK_DATE_M
Definition: datetime.h:194
#define FALSE
Definition: c.h:218
int tm_mon
Definition: pgtime.h:31
#define MONTH
Definition: datetime.h:92
#define NULL
Definition: c.h:226
#define MAXDATEFIELDS
Definition: datetime.h:205
static int DecodeNumber(int flen, char *field, bool haveTextMonth, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2720
int DecodeSpecial(int field, char *lowtoken, int *val)
Definition: datetime.c:3129
int i
#define DTK_M(t)
Definition: datetime.h:190
#define TRUE
Definition: c.h:214
#define DOY
Definition: datetime.h:106
long val
Definition: informix.c:689
int DecodeDateTime ( char **  field,
int *  ftype,
int  nf,
int *  dtype,
struct pg_tm tm,
fsec_t fsec,
int *  tzp 
)

Definition at line 847 of file datetime.c.

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

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

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

Definition at line 3185 of file datetime.c.

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

Referenced by interval_in(), and reltimein().

3187 {
3188  bool is_before = FALSE;
3189  char *cp;
3190  int fmask = 0,
3191  tmask,
3192  type;
3193  int i;
3194  int dterr;
3195  int val;
3196  double fval;
3197 
3198  *dtype = DTK_DELTA;
3199  type = IGNORE_DTF;
3200  ClearPgTm(tm, fsec);
3201 
3202  /* read through list backwards to pick up units before values */
3203  for (i = nf - 1; i >= 0; i--)
3204  {
3205  switch (ftype[i])
3206  {
3207  case DTK_TIME:
3208  dterr = DecodeTime(field[i], fmask, range,
3209  &tmask, tm, fsec);
3210  if (dterr)
3211  return dterr;
3212  type = DTK_DAY;
3213  break;
3214 
3215  case DTK_TZ:
3216 
3217  /*
3218  * Timezone means a token with a leading sign character and at
3219  * least one digit; there could be ':', '.', '-' embedded in
3220  * it as well.
3221  */
3222  Assert(*field[i] == '-' || *field[i] == '+');
3223 
3224  /*
3225  * Check for signed hh:mm or hh:mm:ss. If so, process exactly
3226  * like DTK_TIME case above, plus handling the sign.
3227  */
3228  if (strchr(field[i] + 1, ':') != NULL &&
3229  DecodeTime(field[i] + 1, fmask, range,
3230  &tmask, tm, fsec) == 0)
3231  {
3232  if (*field[i] == '-')
3233  {
3234  /* flip the sign on all fields */
3235  tm->tm_hour = -tm->tm_hour;
3236  tm->tm_min = -tm->tm_min;
3237  tm->tm_sec = -tm->tm_sec;
3238  *fsec = -(*fsec);
3239  }
3240 
3241  /*
3242  * Set the next type to be a day, if units are not
3243  * specified. This handles the case of '1 +02:03' since we
3244  * are reading right to left.
3245  */
3246  type = DTK_DAY;
3247  break;
3248  }
3249 
3250  /*
3251  * Otherwise, fall through to DTK_NUMBER case, which can
3252  * handle signed float numbers and signed year-month values.
3253  */
3254 
3255  /* FALL THROUGH */
3256 
3257  case DTK_DATE:
3258  case DTK_NUMBER:
3259  if (type == IGNORE_DTF)
3260  {
3261  /* use typmod to decide what rightmost field is */
3262  switch (range)
3263  {
3264  case INTERVAL_MASK(YEAR):
3265  type = DTK_YEAR;
3266  break;
3267  case INTERVAL_MASK(MONTH):
3269  type = DTK_MONTH;
3270  break;
3271  case INTERVAL_MASK(DAY):
3272  type = DTK_DAY;
3273  break;
3274  case INTERVAL_MASK(HOUR):
3276  type = DTK_HOUR;
3277  break;
3278  case INTERVAL_MASK(MINUTE):
3281  type = DTK_MINUTE;
3282  break;
3283  case INTERVAL_MASK(SECOND):
3287  type = DTK_SECOND;
3288  break;
3289  default:
3290  type = DTK_SECOND;
3291  break;
3292  }
3293  }
3294 
3295  errno = 0;
3296  val = strtoint(field[i], &cp, 10);
3297  if (errno == ERANGE)
3298  return DTERR_FIELD_OVERFLOW;
3299 
3300  if (*cp == '-')
3301  {
3302  /* SQL "years-months" syntax */
3303  int val2;
3304 
3305  val2 = strtoint(cp + 1, &cp, 10);
3306  if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
3307  return DTERR_FIELD_OVERFLOW;
3308  if (*cp != '\0')
3309  return DTERR_BAD_FORMAT;
3310  type = DTK_MONTH;
3311  if (*field[i] == '-')
3312  val2 = -val2;
3313  if (((double) val * MONTHS_PER_YEAR + val2) > INT_MAX ||
3314  ((double) val * MONTHS_PER_YEAR + val2) < INT_MIN)
3315  return DTERR_FIELD_OVERFLOW;
3316  val = val * MONTHS_PER_YEAR + val2;
3317  fval = 0;
3318  }
3319  else if (*cp == '.')
3320  {
3321  errno = 0;
3322  fval = strtod(cp, &cp);
3323  if (*cp != '\0' || errno != 0)
3324  return DTERR_BAD_FORMAT;
3325 
3326  if (*field[i] == '-')
3327  fval = -fval;
3328  }
3329  else if (*cp == '\0')
3330  fval = 0;
3331  else
3332  return DTERR_BAD_FORMAT;
3333 
3334  tmask = 0; /* DTK_M(type); */
3335 
3336  switch (type)
3337  {
3338  case DTK_MICROSEC:
3339 #ifdef HAVE_INT64_TIMESTAMP
3340  *fsec += rint(val + fval);
3341 #else
3342  *fsec += (val + fval) * 1e-6;
3343 #endif
3344  tmask = DTK_M(MICROSECOND);
3345  break;
3346 
3347  case DTK_MILLISEC:
3348  /* avoid overflowing the fsec field */
3349  tm->tm_sec += val / 1000;
3350  val -= (val / 1000) * 1000;
3351 #ifdef HAVE_INT64_TIMESTAMP
3352  *fsec += rint((val + fval) * 1000);
3353 #else
3354  *fsec += (val + fval) * 1e-3;
3355 #endif
3356  tmask = DTK_M(MILLISECOND);
3357  break;
3358 
3359  case DTK_SECOND:
3360  tm->tm_sec += val;
3361 #ifdef HAVE_INT64_TIMESTAMP
3362  *fsec += rint(fval * 1000000);
3363 #else
3364  *fsec += fval;
3365 #endif
3366 
3367  /*
3368  * If any subseconds were specified, consider this
3369  * microsecond and millisecond input as well.
3370  */
3371  if (fval == 0)
3372  tmask = DTK_M(SECOND);
3373  else
3374  tmask = DTK_ALL_SECS_M;
3375  break;
3376 
3377  case DTK_MINUTE:
3378  tm->tm_min += val;
3379  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3380  tmask = DTK_M(MINUTE);
3381  break;
3382 
3383  case DTK_HOUR:
3384  tm->tm_hour += val;
3385  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3386  tmask = DTK_M(HOUR);
3387  type = DTK_DAY; /* set for next field */
3388  break;
3389 
3390  case DTK_DAY:
3391  tm->tm_mday += val;
3392  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3393  tmask = DTK_M(DAY);
3394  break;
3395 
3396  case DTK_WEEK:
3397  tm->tm_mday += val * 7;
3398  AdjustFractDays(fval, tm, fsec, 7);
3399  tmask = DTK_M(WEEK);
3400  break;
3401 
3402  case DTK_MONTH:
3403  tm->tm_mon += val;
3404  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3405  tmask = DTK_M(MONTH);
3406  break;
3407 
3408  case DTK_YEAR:
3409  tm->tm_year += val;
3410  if (fval != 0)
3411  tm->tm_mon += fval * MONTHS_PER_YEAR;
3412  tmask = DTK_M(YEAR);
3413  break;
3414 
3415  case DTK_DECADE:
3416  tm->tm_year += val * 10;
3417  if (fval != 0)
3418  tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
3419  tmask = DTK_M(DECADE);
3420  break;
3421 
3422  case DTK_CENTURY:
3423  tm->tm_year += val * 100;
3424  if (fval != 0)
3425  tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
3426  tmask = DTK_M(CENTURY);
3427  break;
3428 
3429  case DTK_MILLENNIUM:
3430  tm->tm_year += val * 1000;
3431  if (fval != 0)
3432  tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
3433  tmask = DTK_M(MILLENNIUM);
3434  break;
3435 
3436  default:
3437  return DTERR_BAD_FORMAT;
3438  }
3439  break;
3440 
3441  case DTK_STRING:
3442  case DTK_SPECIAL:
3443  type = DecodeUnits(i, field[i], &val);
3444  if (type == IGNORE_DTF)
3445  continue;
3446 
3447  tmask = 0; /* DTK_M(type); */
3448  switch (type)
3449  {
3450  case UNITS:
3451  type = val;
3452  break;
3453 
3454  case AGO:
3455  is_before = TRUE;
3456  type = val;
3457  break;
3458 
3459  case RESERV:
3460  tmask = (DTK_DATE_M | DTK_TIME_M);
3461  *dtype = val;
3462  break;
3463 
3464  default:
3465  return DTERR_BAD_FORMAT;
3466  }
3467  break;
3468 
3469  default:
3470  return DTERR_BAD_FORMAT;
3471  }
3472 
3473  if (tmask & fmask)
3474  return DTERR_BAD_FORMAT;
3475  fmask |= tmask;
3476  }
3477 
3478  /* ensure that at least one time field has been found */
3479  if (fmask == 0)
3480  return DTERR_BAD_FORMAT;
3481 
3482  /* ensure fractional seconds are fractional */
3483  if (*fsec != 0)
3484  {
3485  int sec;
3486 
3487 #ifdef HAVE_INT64_TIMESTAMP
3488  sec = *fsec / USECS_PER_SEC;
3489  *fsec -= sec * USECS_PER_SEC;
3490 #else
3491  TMODULO(*fsec, sec, 1.0);
3492 #endif
3493  tm->tm_sec += sec;
3494  }
3495 
3496  /*----------
3497  * The SQL standard defines the interval literal
3498  * '-1 1:00:00'
3499  * to mean "negative 1 days and negative 1 hours", while Postgres
3500  * traditionally treats this as meaning "negative 1 days and positive
3501  * 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign
3502  * to all fields if there are no other explicit signs.
3503  *
3504  * We leave the signs alone if there are additional explicit signs.
3505  * This protects us against misinterpreting postgres-style dump output,
3506  * since the postgres-style output code has always put an explicit sign on
3507  * all fields following a negative field. But note that SQL-spec output
3508  * is ambiguous and can be misinterpreted on load! (So it's best practice
3509  * to dump in postgres style, not SQL style.)
3510  *----------
3511  */
3512  if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
3513  {
3514  /* Check for additional explicit signs */
3515  bool more_signs = false;
3516 
3517  for (i = 1; i < nf; i++)
3518  {
3519  if (*field[i] == '-' || *field[i] == '+')
3520  {
3521  more_signs = true;
3522  break;
3523  }
3524  }
3525 
3526  if (!more_signs)
3527  {
3528  /*
3529  * Rather than re-determining which field was field[0], just force
3530  * 'em all negative.
3531  */
3532  if (*fsec > 0)
3533  *fsec = -(*fsec);
3534  if (tm->tm_sec > 0)
3535  tm->tm_sec = -tm->tm_sec;
3536  if (tm->tm_min > 0)
3537  tm->tm_min = -tm->tm_min;
3538  if (tm->tm_hour > 0)
3539  tm->tm_hour = -tm->tm_hour;
3540  if (tm->tm_mday > 0)
3541  tm->tm_mday = -tm->tm_mday;
3542  if (tm->tm_mon > 0)
3543  tm->tm_mon = -tm->tm_mon;
3544  if (tm->tm_year > 0)
3545  tm->tm_year = -tm->tm_year;
3546  }
3547  }
3548 
3549  /* finally, AGO negates everything */
3550  if (is_before)
3551  {
3552  *fsec = -(*fsec);
3553  tm->tm_sec = -tm->tm_sec;
3554  tm->tm_min = -tm->tm_min;
3555  tm->tm_hour = -tm->tm_hour;
3556  tm->tm_mday = -tm->tm_mday;
3557  tm->tm_mon = -tm->tm_mon;
3558  tm->tm_year = -tm->tm_year;
3559  }
3560 
3561  return 0;
3562 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:290
#define DTK_CENTURY
Definition: datetime.h:172
#define DAY
Definition: datetime.h:94
#define UNITS
Definition: datetime.h:108
#define IGNORE_DTF
Definition: datetime.h:99
#define DTK_WEEK
Definition: datetime.h:167
#define DTK_YEAR
Definition: datetime.h:170
#define MILLENNIUM
Definition: datetime.h:121
#define USECS_PER_SEC
Definition: timestamp.h:106
#define YEAR
Definition: datetime.h:93
#define CENTURY
Definition: datetime.h:120
#define DTK_DELTA
Definition: datetime.h:162
int tm_hour
Definition: pgtime.h:29
#define DECADE
Definition: datetime.h:119
#define AGO
Definition: datetime.h:111
#define DTK_TIME_M
Definition: datetime.h:195
#define DTK_MILLENNIUM
Definition: datetime.h:173
int IntervalStyle
Definition: globals.c:108
#define SECOND
Definition: datetime.h:103
int DecodeUnits(int field, char *lowtoken, int *val)
Definition: datetime.c:3834
static void AdjustFractSeconds(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:540
#define DTK_DATE_M
Definition: datetime.h:194
#define DTK_MONTH
Definition: datetime.h:168
#define DTK_MILLISEC
Definition: datetime.h:174
#define MONTHS_PER_YEAR
Definition: timestamp.h:81
#define DTK_DECADE
Definition: datetime.h:171
#define DTK_TZ
Definition: datetime.h:147
#define DTK_HOUR
Definition: datetime.h:165
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:291
#define MILLISECOND
Definition: datetime.h:104
#define SECS_PER_DAY
Definition: timestamp.h:98
#define FALSE
Definition: c.h:218
#define DTK_SECOND
Definition: datetime.h:163
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:100
#define DTK_NUMBER
Definition: datetime.h:142
#define MINUTE
Definition: datetime.h:102
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:416
double rint(double x)
Definition: rint.c:22
#define SECS_PER_HOUR
Definition: timestamp.h:99
#define MONTH
Definition: datetime.h:92
#define DTK_MINUTE
Definition: datetime.h:164
#define DTK_MICROSEC
Definition: datetime.h:175
#define DAYS_PER_MONTH
Definition: timestamp.h:89
static void AdjustFractDays(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:559
#define WEEK
Definition: datetime.h:118
#define DTK_TIME
Definition: datetime.h:146
static int DecodeTime(char *str, int fmask, int range, int *tmask, struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:2637
static void ClearPgTm(struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:3161
static int strtoint(const char *nptr, char **endptr, int base)
Definition: datetime.c:263
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
#define DTK_STRING
Definition: datetime.h:143
#define DTK_DAY
Definition: datetime.h:166
#define RESERV
Definition: datetime.h:91
#define DTK_ALL_SECS_M
Definition: datetime.h:193
#define INTERVAL_MASK(b)
Definition: timestamp.h:66
#define INTSTYLE_SQL_STANDARD
Definition: miscadmin.h:232
e
Definition: preproc-init.c:82
int tm_year
Definition: pgtime.h:32
int i
#define DTK_M(t)
Definition: datetime.h:190
#define TRUE
Definition: c.h:214
#define HOUR
Definition: datetime.h:101
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
long val
Definition: informix.c:689
#define DTK_DATE
Definition: datetime.h:145
#define DTK_SPECIAL
Definition: datetime.h:150
#define TMODULO(t, q, u)
Definition: datetime.h:258
#define MICROSECOND
Definition: datetime.h:105
int DecodeISO8601Interval ( char *  str,
int *  dtype,
struct pg_tm tm,
fsec_t fsec 
)

Definition at line 3627 of file datetime.c.

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

Referenced by interval_in(), and reltimein().

3629 {
3630  bool datepart = true;
3631  bool havefield = false;
3632 
3633  *dtype = DTK_DELTA;
3634  ClearPgTm(tm, fsec);
3635 
3636  if (strlen(str) < 2 || str[0] != 'P')
3637  return DTERR_BAD_FORMAT;
3638 
3639  str++;
3640  while (*str)
3641  {
3642  char *fieldstart;
3643  int val;
3644  double fval;
3645  char unit;
3646  int dterr;
3647 
3648  if (*str == 'T') /* T indicates the beginning of the time part */
3649  {
3650  datepart = false;
3651  havefield = false;
3652  str++;
3653  continue;
3654  }
3655 
3656  fieldstart = str;
3657  dterr = ParseISO8601Number(str, &str, &val, &fval);
3658  if (dterr)
3659  return dterr;
3660 
3661  /*
3662  * Note: we could step off the end of the string here. Code below
3663  * *must* exit the loop if unit == '\0'.
3664  */
3665  unit = *str++;
3666 
3667  if (datepart)
3668  {
3669  switch (unit) /* before T: Y M W D */
3670  {
3671  case 'Y':
3672  tm->tm_year += val;
3673  tm->tm_mon += (fval * MONTHS_PER_YEAR);
3674  break;
3675  case 'M':
3676  tm->tm_mon += val;
3677  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3678  break;
3679  case 'W':
3680  tm->tm_mday += val * 7;
3681  AdjustFractDays(fval, tm, fsec, 7);
3682  break;
3683  case 'D':
3684  tm->tm_mday += val;
3685  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3686  break;
3687  case 'T': /* ISO 8601 4.4.3.3 Alternative Format / Basic */
3688  case '\0':
3689  if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
3690  {
3691  tm->tm_year += val / 10000;
3692  tm->tm_mon += (val / 100) % 100;
3693  tm->tm_mday += val % 100;
3694  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3695  if (unit == '\0')
3696  return 0;
3697  datepart = false;
3698  havefield = false;
3699  continue;
3700  }
3701  /* Else fall through to extended alternative format */
3702  case '-': /* ISO 8601 4.4.3.3 Alternative Format,
3703  * Extended */
3704  if (havefield)
3705  return DTERR_BAD_FORMAT;
3706 
3707  tm->tm_year += val;
3708  tm->tm_mon += (fval * MONTHS_PER_YEAR);
3709  if (unit == '\0')
3710  return 0;
3711  if (unit == 'T')
3712  {
3713  datepart = false;
3714  havefield = false;
3715  continue;
3716  }
3717 
3718  dterr = ParseISO8601Number(str, &str, &val, &fval);
3719  if (dterr)
3720  return dterr;
3721  tm->tm_mon += val;
3722  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3723  if (*str == '\0')
3724  return 0;
3725  if (*str == 'T')
3726  {
3727  datepart = false;
3728  havefield = false;
3729  continue;
3730  }
3731  if (*str != '-')
3732  return DTERR_BAD_FORMAT;
3733  str++;
3734 
3735  dterr = ParseISO8601Number(str, &str, &val, &fval);
3736  if (dterr)
3737  return dterr;
3738  tm->tm_mday += val;
3739  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3740  if (*str == '\0')
3741  return 0;
3742  if (*str == 'T')
3743  {
3744  datepart = false;
3745  havefield = false;
3746  continue;
3747  }
3748  return DTERR_BAD_FORMAT;
3749  default:
3750  /* not a valid date unit suffix */
3751  return DTERR_BAD_FORMAT;
3752  }
3753  }
3754  else
3755  {
3756  switch (unit) /* after T: H M S */
3757  {
3758  case 'H':
3759  tm->tm_hour += val;
3760  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3761  break;
3762  case 'M':
3763  tm->tm_min += val;
3764  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3765  break;
3766  case 'S':
3767  tm->tm_sec += val;
3768  AdjustFractSeconds(fval, tm, fsec, 1);
3769  break;
3770  case '\0': /* ISO 8601 4.4.3.3 Alternative Format */
3771  if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
3772  {
3773  tm->tm_hour += val / 10000;
3774  tm->tm_min += (val / 100) % 100;
3775  tm->tm_sec += val % 100;
3776  AdjustFractSeconds(fval, tm, fsec, 1);
3777  return 0;
3778  }
3779  /* Else fall through to extended alternative format */
3780  case ':': /* ISO 8601 4.4.3.3 Alternative Format,
3781  * Extended */
3782  if (havefield)
3783  return DTERR_BAD_FORMAT;
3784 
3785  tm->tm_hour += val;
3786  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3787  if (unit == '\0')
3788  return 0;
3789 
3790  dterr = ParseISO8601Number(str, &str, &val, &fval);
3791  if (dterr)
3792  return dterr;
3793  tm->tm_min += val;
3794  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3795  if (*str == '\0')
3796  return 0;
3797  if (*str != ':')
3798  return DTERR_BAD_FORMAT;
3799  str++;
3800 
3801  dterr = ParseISO8601Number(str, &str, &val, &fval);
3802  if (dterr)
3803  return dterr;
3804  tm->tm_sec += val;
3805  AdjustFractSeconds(fval, tm, fsec, 1);
3806  if (*str == '\0')
3807  return 0;
3808  return DTERR_BAD_FORMAT;
3809 
3810  default:
3811  /* not a valid time unit suffix */
3812  return DTERR_BAD_FORMAT;
3813  }
3814  }
3815 
3816  havefield = true;
3817  }
3818 
3819  return 0;
3820 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:290
#define DTK_DELTA
Definition: datetime.h:162
int tm_hour
Definition: pgtime.h:29
static void AdjustFractSeconds(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:540
#define MONTHS_PER_YEAR
Definition: timestamp.h:81
#define SECS_PER_DAY
Definition: timestamp.h:98
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:100
#define SECS_PER_HOUR
Definition: timestamp.h:99
#define DAYS_PER_MONTH
Definition: timestamp.h:89
static void AdjustFractDays(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:559
static void ClearPgTm(struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:3161
static int ISO8601IntegerWidth(char *fieldstart)
Definition: datetime.c:3600
int tm_year
Definition: pgtime.h:32
static int ParseISO8601Number(char *str, char **endptr, int *ipart, double *fpart)
Definition: datetime.c:3572
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
long val
Definition: informix.c:689
static int DecodeNumber ( int  flen,
char *  field,
bool  haveTextMonth,
int  fmask,
int *  tmask,
struct pg_tm tm,
fsec_t fsec,
bool is2digits 
)
static

Definition at line 2720 of file datetime.c.

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

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

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

Definition at line 2905 of file datetime.c.

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

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

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

Definition at line 3129 of file datetime.c.

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

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

3130 {
3131  int type;
3132  const datetkn *tp;
3133 
3134  tp = datecache[field];
3135  /* use strncmp so that we match truncated tokens */
3136  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3137  {
3138  tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
3139  }
3140  if (tp == NULL)
3141  {
3142  type = UNKNOWN_FIELD;
3143  *val = 0;
3144  }
3145  else
3146  {
3147  datecache[field] = tp;
3148  type = tp->type;
3149  *val = tp->value;
3150  }
3151 
3152  return type;
3153 }
static const datetkn datetktbl[]
Definition: datetime.c:95
#define UNKNOWN_FIELD
Definition: datetime.h:125
int32 value
Definition: datetime.h:214
static int szdatetktbl
Definition: datetime.c:173
char token[TOKMAXLEN+1]
Definition: datetime.h:212
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:3916
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:226
static const datetkn * datecache[MAXDATEFIELDS]
Definition: datetime.c:252
#define TOKMAXLEN
Definition: datetime.h:207
long val
Definition: informix.c:689
static int DecodeTime ( char *  str,
int  fmask,
int  range,
int *  tmask,
struct pg_tm tm,
fsec_t fsec 
)
static

Definition at line 2637 of file datetime.c.

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

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

2639 {
2640  char *cp;
2641  int dterr;
2642 
2643  *tmask = DTK_TIME_M;
2644 
2645  errno = 0;
2646  tm->tm_hour = strtoint(str, &cp, 10);
2647  if (errno == ERANGE)
2648  return DTERR_FIELD_OVERFLOW;
2649  if (*cp != ':')
2650  return DTERR_BAD_FORMAT;
2651  errno = 0;
2652  tm->tm_min = strtoint(cp + 1, &cp, 10);
2653  if (errno == ERANGE)
2654  return DTERR_FIELD_OVERFLOW;
2655  if (*cp == '\0')
2656  {
2657  tm->tm_sec = 0;
2658  *fsec = 0;
2659  /* If it's a MINUTE TO SECOND interval, take 2 fields as being mm:ss */
2661  {
2662  tm->tm_sec = tm->tm_min;
2663  tm->tm_min = tm->tm_hour;
2664  tm->tm_hour = 0;
2665  }
2666  }
2667  else if (*cp == '.')
2668  {
2669  /* always assume mm:ss.sss is MINUTE TO SECOND */
2670  dterr = ParseFractionalSecond(cp, fsec);
2671  if (dterr)
2672  return dterr;
2673  tm->tm_sec = tm->tm_min;
2674  tm->tm_min = tm->tm_hour;
2675  tm->tm_hour = 0;
2676  }
2677  else if (*cp == ':')
2678  {
2679  errno = 0;
2680  tm->tm_sec = strtoint(cp + 1, &cp, 10);
2681  if (errno == ERANGE)
2682  return DTERR_FIELD_OVERFLOW;
2683  if (*cp == '\0')
2684  *fsec = 0;
2685  else if (*cp == '.')
2686  {
2687  dterr = ParseFractionalSecond(cp, fsec);
2688  if (dterr)
2689  return dterr;
2690  }
2691  else
2692  return DTERR_BAD_FORMAT;
2693  }
2694  else
2695  return DTERR_BAD_FORMAT;
2696 
2697  /* do a sanity check */
2698 #ifdef HAVE_INT64_TIMESTAMP
2699  if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
2700  tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
2701  *fsec < INT64CONST(0) ||
2702  *fsec > USECS_PER_SEC)
2703  return DTERR_FIELD_OVERFLOW;
2704 #else
2705  if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
2706  tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
2707  *fsec < 0 || *fsec > 1)
2708  return DTERR_FIELD_OVERFLOW;
2709 #endif
2710 
2711  return 0;
2712 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:290
#define USECS_PER_SEC
Definition: timestamp.h:106
int tm_hour
Definition: pgtime.h:29
#define DTK_TIME_M
Definition: datetime.h:195
#define SECOND
Definition: datetime.h:103
#define MINS_PER_HOUR
Definition: timestamp.h:101
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:291
#define SECS_PER_MINUTE
Definition: timestamp.h:100
#define MINUTE
Definition: datetime.h:102
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:416
static int ParseFractionalSecond(char *cp, fsec_t *fsec)
Definition: datetime.c:574
static int strtoint(const char *nptr, char **endptr, int base)
Definition: datetime.c:263
#define INT64CONST(x)
Definition: c.h:307
#define INTERVAL_MASK(b)
Definition: timestamp.h:66
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
int DecodeTimeOnly ( char **  field,
int *  ftype,
int  nf,
int *  dtype,
struct pg_tm tm,
fsec_t fsec,
int *  tzp 
)

Definition at line 1813 of file datetime.c.

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

Referenced by time_in(), and timetz_in().

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

Definition at line 2996 of file datetime.c.

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

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

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

Definition at line 3074 of file datetime.c.

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

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

3076 {
3077  int type;
3078  const datetkn *tp;
3079 
3080  tp = abbrevcache[field];
3081  /* use strncmp so that we match truncated tokens */
3082  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3083  {
3084  if (zoneabbrevtbl)
3085  tp = datebsearch(lowtoken, zoneabbrevtbl->abbrevs,
3087  else
3088  tp = NULL;
3089  }
3090  if (tp == NULL)
3091  {
3092  type = UNKNOWN_FIELD;
3093  *offset = 0;
3094  *tz = NULL;
3095  }
3096  else
3097  {
3098  abbrevcache[field] = tp;
3099  type = tp->type;
3100  if (type == DYNTZ)
3101  {
3102  *offset = 0;
3104  }
3105  else
3106  {
3107  *offset = tp->value;
3108  *tz = NULL;
3109  }
3110  }
3111 
3112  return type;
3113 }
static pg_tz * FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp)
Definition: datetime.c:4721
#define UNKNOWN_FIELD
Definition: datetime.h:125
int32 value
Definition: datetime.h:214
char token[TOKMAXLEN+1]
Definition: datetime.h:212
datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:222
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:3916
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:226
static TimeZoneAbbrevTable * zoneabbrevtbl
Definition: datetime.c:248
static const datetkn * abbrevcache[MAXDATEFIELDS]
Definition: datetime.c:256
#define DYNTZ
Definition: datetime.h:98
#define TOKMAXLEN
Definition: datetime.h:207
int DecodeUnits ( int  field,
char *  lowtoken,
int *  val 
)

Definition at line 3834 of file datetime.c.

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

3835 {
3836  int type;
3837  const datetkn *tp;
3838 
3839  tp = deltacache[field];
3840  /* use strncmp so that we match truncated tokens */
3841  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3842  {
3843  tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
3844  }
3845  if (tp == NULL)
3846  {
3847  type = UNKNOWN_FIELD;
3848  *val = 0;
3849  }
3850  else
3851  {
3852  deltacache[field] = tp;
3853  type = tp->type;
3854  *val = tp->value;
3855  }
3856 
3857  return type;
3858 } /* DecodeUnits() */
static const datetkn * deltacache[MAXDATEFIELDS]
Definition: datetime.c:254
#define UNKNOWN_FIELD
Definition: datetime.h:125
int32 value
Definition: datetime.h:214
char token[TOKMAXLEN+1]
Definition: datetime.h:212
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:3916
static const datetkn deltatktbl[]
Definition: datetime.c:179
static int szdeltatktbl
Definition: datetime.c:246
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:226
#define TOKMAXLEN
Definition: datetime.h:207
long val
Definition: informix.c:689
int DetermineTimeZoneAbbrevOffset ( struct pg_tm tm,
const char *  abbr,
pg_tz tzp 
)

Definition at line 1698 of file datetime.c.

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

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

1699 {
1700  pg_time_t t;
1701  int zone_offset;
1702  int abbr_offset;
1703  int abbr_isdst;
1704 
1705  /*
1706  * Compute the UTC time we want to probe at. (In event of overflow, we'll
1707  * probe at the epoch, which is a bit random but probably doesn't matter.)
1708  */
1709  zone_offset = DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1710 
1711  /*
1712  * Try to match the abbreviation to something in the zone definition.
1713  */
1714  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1715  &abbr_offset, &abbr_isdst))
1716  {
1717  /* Success, so use the abbrev-specific answers. */
1718  tm->tm_isdst = abbr_isdst;
1719  return abbr_offset;
1720  }
1721 
1722  /*
1723  * No match, so use the answers we already got from
1724  * DetermineTimeZoneOffsetInternal.
1725  */
1726  return zone_offset;
1727 }
int64 pg_time_t
Definition: pgtime.h:23
int tm_isdst
Definition: pgtime.h:35
static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp, pg_time_t *tp)
Definition: datetime.c:1562
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, int *offset, int *isdst)
Definition: datetime.c:1773
static bool DetermineTimeZoneAbbrevOffsetInternal ( pg_time_t  t,
const char *  abbr,
pg_tz tzp,
int *  offset,
int *  isdst 
)
static

Definition at line 1773 of file datetime.c.

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

Referenced by DetermineTimeZoneAbbrevOffset(), and DetermineTimeZoneAbbrevOffsetTS().

1775 {
1776  char upabbr[TZ_STRLEN_MAX + 1];
1777  unsigned char *p;
1778  long int gmtoff;
1779 
1780  /* We need to force the abbrev to upper case */
1781  strlcpy(upabbr, abbr, sizeof(upabbr));
1782  for (p = (unsigned char *) upabbr; *p; p++)
1783  *p = pg_toupper(*p);
1784 
1785  /* Look up the abbrev's meaning at this time in this zone */
1786  if (pg_interpret_timezone_abbrev(upabbr,
1787  &t,
1788  &gmtoff,
1789  isdst,
1790  tzp))
1791  {
1792  /* Change sign to agree with DetermineTimeZoneOffset() */
1793  *offset = (int) -gmtoff;
1794  return true;
1795  }
1796  return false;
1797 }
#define TZ_STRLEN_MAX
Definition: pgtime.h:44
bool pg_interpret_timezone_abbrev(const char *abbrev, const pg_time_t *timep, long int *gmtoff, int *isdst, const pg_tz *tz)
Definition: localtime.c:1652
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
unsigned char pg_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:105
int DetermineTimeZoneAbbrevOffsetTS ( TimestampTz  ts,
const char *  abbr,
pg_tz tzp,
int *  isdst 
)

Definition at line 1736 of file datetime.c.

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

Referenced by pg_timezone_abbrevs(), and timestamptz_zone().

1738 {
1740  int zone_offset;
1741  int abbr_offset;
1742  int tz;
1743  struct pg_tm tm;
1744  fsec_t fsec;
1745 
1746  /*
1747  * If the abbrev matches anything in the zone data, this is pretty easy.
1748  */
1749  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1750  &abbr_offset, isdst))
1751  return abbr_offset;
1752 
1753  /*
1754  * Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1755  */
1756  if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0)
1757  ereport(ERROR,
1758  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1759  errmsg("timestamp out of range")));
1760 
1761  zone_offset = DetermineTimeZoneOffset(&tm, tzp);
1762  *isdst = tm.tm_isdst;
1763  return zone_offset;
1764 }
int64 pg_time_t
Definition: pgtime.h:23
double fsec_t
Definition: timestamp.h:53
int tm_isdst
Definition: pgtime.h:35
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1951
int errcode(int sqlerrcode)
Definition: elog.c:575
Definition: pgtime.h:25
static struct pg_tm tm
Definition: localtime.c:103
#define ERROR
Definition: elog.h:43
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1540
pg_time_t timestamptz_to_time_t(TimestampTz t)
Definition: timestamp.c:1871
#define ereport(elevel, rest)
Definition: elog.h:122
#define NULL
Definition: c.h:226
int errmsg(const char *fmt,...)
Definition: elog.c:797
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, int *offset, int *isdst)
Definition: datetime.c:1773
int DetermineTimeZoneOffset ( struct pg_tm tm,
pg_tz tzp 
)

Definition at line 1540 of file datetime.c.

References DetermineTimeZoneOffsetInternal().

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

1541 {
1542  pg_time_t t;
1543 
1544  return DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1545 }
int64 pg_time_t
Definition: pgtime.h:23
static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp, pg_time_t *tp)
Definition: datetime.c:1562
static int DetermineTimeZoneOffsetInternal ( struct pg_tm tm,
pg_tz tzp,
pg_time_t tp 
)
static

Definition at line 1562 of file datetime.c.

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

Referenced by DetermineTimeZoneAbbrevOffset(), and DetermineTimeZoneOffset().

1563 {
1564  int date,
1565  sec;
1566  pg_time_t day,
1567  mytime,
1568  prevtime,
1569  boundary,
1570  beforetime,
1571  aftertime;
1572  long int before_gmtoff,
1573  after_gmtoff;
1574  int before_isdst,
1575  after_isdst;
1576  int res;
1577 
1578  /*
1579  * First, generate the pg_time_t value corresponding to the given
1580  * y/m/d/h/m/s taken as GMT time. If this overflows, punt and decide the
1581  * timezone is GMT. (For a valid Julian date, integer overflow should be
1582  * impossible with 64-bit pg_time_t, but let's check for safety.)
1583  */
1584  if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
1585  goto overflow;
1586  date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
1587 
1588  day = ((pg_time_t) date) * SECS_PER_DAY;
1589  if (day / SECS_PER_DAY != date)
1590  goto overflow;
1591  sec = tm->tm_sec + (tm->tm_min + tm->tm_hour * MINS_PER_HOUR) * SECS_PER_MINUTE;
1592  mytime = day + sec;
1593  /* since sec >= 0, overflow could only be from +day to -mytime */
1594  if (mytime < 0 && day > 0)
1595  goto overflow;
1596 
1597  /*
1598  * Find the DST time boundary just before or following the target time. We
1599  * assume that all zones have GMT offsets less than 24 hours, and that DST
1600  * boundaries can't be closer together than 48 hours, so backing up 24
1601  * hours and finding the "next" boundary will work.
1602  */
1603  prevtime = mytime - SECS_PER_DAY;
1604  if (mytime < 0 && prevtime > 0)
1605  goto overflow;
1606 
1607  res = pg_next_dst_boundary(&prevtime,
1608  &before_gmtoff, &before_isdst,
1609  &boundary,
1610  &after_gmtoff, &after_isdst,
1611  tzp);
1612  if (res < 0)
1613  goto overflow; /* failure? */
1614 
1615  if (res == 0)
1616  {
1617  /* Non-DST zone, life is simple */
1618  tm->tm_isdst = before_isdst;
1619  *tp = mytime - before_gmtoff;
1620  return -(int) before_gmtoff;
1621  }
1622 
1623  /*
1624  * Form the candidate pg_time_t values with local-time adjustment
1625  */
1626  beforetime = mytime - before_gmtoff;
1627  if ((before_gmtoff > 0 &&
1628  mytime < 0 && beforetime > 0) ||
1629  (before_gmtoff <= 0 &&
1630  mytime > 0 && beforetime < 0))
1631  goto overflow;
1632  aftertime = mytime - after_gmtoff;
1633  if ((after_gmtoff > 0 &&
1634  mytime < 0 && aftertime > 0) ||
1635  (after_gmtoff <= 0 &&
1636  mytime > 0 && aftertime < 0))
1637  goto overflow;
1638 
1639  /*
1640  * If both before or both after the boundary time, we know what to do. The
1641  * boundary time itself is considered to be after the transition, which
1642  * means we can accept aftertime == boundary in the second case.
1643  */
1644  if (beforetime < boundary && aftertime < boundary)
1645  {
1646  tm->tm_isdst = before_isdst;
1647  *tp = beforetime;
1648  return -(int) before_gmtoff;
1649  }
1650  if (beforetime > boundary && aftertime >= boundary)
1651  {
1652  tm->tm_isdst = after_isdst;
1653  *tp = aftertime;
1654  return -(int) after_gmtoff;
1655  }
1656 
1657  /*
1658  * It's an invalid or ambiguous time due to timezone transition. In a
1659  * spring-forward transition, prefer the "before" interpretation; in a
1660  * fall-back transition, prefer "after". (We used to define and implement
1661  * this test as "prefer the standard-time interpretation", but that rule
1662  * does not help to resolve the behavior when both times are reported as
1663  * standard time; which does happen, eg Europe/Moscow in Oct 2014.)
1664  */
1665  if (beforetime > aftertime)
1666  {
1667  tm->tm_isdst = before_isdst;
1668  *tp = beforetime;
1669  return -(int) before_gmtoff;
1670  }
1671  tm->tm_isdst = after_isdst;
1672  *tp = aftertime;
1673  return -(int) after_gmtoff;
1674 
1675 overflow:
1676  /* Given date is out of range, so assume UTC */
1677  tm->tm_isdst = 0;
1678  *tp = 0;
1679  return 0;
1680 }
int64 pg_time_t
Definition: pgtime.h:23
int pg_next_dst_boundary(const pg_time_t *timep, long int *before_gmtoff, int *before_isdst, pg_time_t *boundary, long int *after_gmtoff, int *after_isdst, const pg_tz *tz)
Definition: localtime.c:1505
int tm_isdst
Definition: pgtime.h:35
int tm_hour
Definition: pgtime.h:29
long date
Definition: pgtypes_date.h:8
#define MINS_PER_HOUR
Definition: timestamp.h:101
#define SECS_PER_DAY
Definition: timestamp.h:98
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:100
#define IS_VALID_JULIAN(y, m, d)
Definition: timestamp.h:177
int date2j(int y, int m, int d)
Definition: datetime.c:297
int tm_year
Definition: pgtime.h:32
#define UNIX_EPOCH_JDATE
Definition: timestamp.h:184
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
void EncodeDateOnly ( struct pg_tm tm,
int  style,
char *  str 
)

Definition at line 3990 of file datetime.c.

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

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

3991 {
3992  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
3993 
3994  switch (style)
3995  {
3996  case USE_ISO_DATES:
3997  case USE_XSD_DATES:
3998  /* compatible with ISO date formats */
3999  str = pg_ltostr_zeropad(str,
4000  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4001  *str++ = '-';
4002  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4003  *str++ = '-';
4004  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4005  break;
4006 
4007  case USE_SQL_DATES:
4008  /* compatible with Oracle/Ingres date formats */
4009  if (DateOrder == DATEORDER_DMY)
4010  {
4011  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4012  *str++ = '/';
4013  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4014  }
4015  else
4016  {
4017  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4018  *str++ = '/';
4019  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4020  }
4021  *str++ = '/';
4022  str = pg_ltostr_zeropad(str,
4023  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4024  break;
4025 
4026  case USE_GERMAN_DATES:
4027  /* German-style date format */
4028  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4029  *str++ = '.';
4030  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4031  *str++ = '.';
4032  str = pg_ltostr_zeropad(str,
4033  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4034  break;
4035 
4036  case USE_POSTGRES_DATES:
4037  default:
4038  /* traditional date-only style for Postgres */
4039  if (DateOrder == DATEORDER_DMY)
4040  {
4041  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4042  *str++ = '-';
4043  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4044  }
4045  else
4046  {
4047  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4048  *str++ = '-';
4049  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4050  }
4051  *str++ = '-';
4052  str = pg_ltostr_zeropad(str,
4053  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4054  break;
4055  }
4056 
4057  if (tm->tm_year <= 0)
4058  {
4059  memcpy(str, " BC", 3); /* Don't copy NUL */
4060  str += 3;
4061  }
4062  *str = '\0';
4063 }
#define USE_SQL_DATES
Definition: miscadmin.h:211
#define USE_ISO_DATES
Definition: miscadmin.h:210
#define MONTHS_PER_YEAR
Definition: timestamp.h:81
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define USE_POSTGRES_DATES
Definition: miscadmin.h:209
int DateOrder
Definition: globals.c:107
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
#define DATEORDER_DMY
Definition: miscadmin.h:217
#define Assert(condition)
Definition: c.h:670
#define USE_XSD_DATES
Definition: miscadmin.h:213
int tm_year
Definition: pgtime.h:32
#define USE_GERMAN_DATES
Definition: miscadmin.h:212
void EncodeDateTime ( struct pg_tm tm,
fsec_t  fsec,
bool  print_tz,
int  tz,
const char *  tzn,
int  style,
char *  str 
)

Definition at line 4105 of file datetime.c.

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

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

4106 {
4107  int day;
4108 
4109  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
4110 
4111  /*
4112  * Negative tm_isdst means we have no valid time zone translation.
4113  */
4114  if (tm->tm_isdst < 0)
4115  print_tz = false;
4116 
4117  switch (style)
4118  {
4119  case USE_ISO_DATES:
4120  case USE_XSD_DATES:
4121  /* Compatible with ISO-8601 date formats */
4122  str = pg_ltostr_zeropad(str,
4123  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4124  *str++ = '-';
4125  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4126  *str++ = '-';
4127  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4128  *str++ = (style == USE_ISO_DATES) ? ' ' : 'T';
4129  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4130  *str++ = ':';
4131  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4132  *str++ = ':';
4133  str = AppendTimestampSeconds(str, tm, fsec);
4134  if (print_tz)
4135  str = EncodeTimezone(str, tz, style);
4136  break;
4137 
4138  case USE_SQL_DATES:
4139  /* Compatible with Oracle/Ingres date formats */
4140  if (DateOrder == DATEORDER_DMY)
4141  {
4142  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4143  *str++ = '/';
4144  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4145  }
4146  else
4147  {
4148  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4149  *str++ = '/';
4150  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4151  }
4152  *str++ = '/';
4153  str = pg_ltostr_zeropad(str,
4154  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4155  *str++ = ' ';
4156  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4157  *str++ = ':';
4158  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4159  *str++ = ':';
4160  str = AppendTimestampSeconds(str, tm, fsec);
4161 
4162  /*
4163  * Note: the uses of %.*s in this function would be risky if the
4164  * timezone names ever contain non-ASCII characters. However, all
4165  * TZ abbreviations in the IANA database are plain ASCII.
4166  */
4167  if (print_tz)
4168  {
4169  if (tzn)
4170  {
4171  sprintf(str, " %.*s", MAXTZLEN, tzn);
4172  str += strlen(str);
4173  }
4174  else
4175  str = EncodeTimezone(str, tz, style);
4176  }
4177  break;
4178 
4179  case USE_GERMAN_DATES:
4180  /* German variant on European style */
4181  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4182  *str++ = '.';
4183  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4184  *str++ = '.';
4185  str = pg_ltostr_zeropad(str,
4186  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4187  *str++ = ' ';
4188  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4189  *str++ = ':';
4190  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4191  *str++ = ':';
4192  str = AppendTimestampSeconds(str, tm, fsec);
4193 
4194  if (print_tz)
4195  {
4196  if (tzn)
4197  {
4198  sprintf(str, " %.*s", MAXTZLEN, tzn);
4199  str += strlen(str);
4200  }
4201  else
4202  str = EncodeTimezone(str, tz, style);
4203  }
4204  break;
4205 
4206  case USE_POSTGRES_DATES:
4207  default:
4208  /* Backward-compatible with traditional Postgres abstime dates */
4209  day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4210  tm->tm_wday = j2day(day);
4211  memcpy(str, days[tm->tm_wday], 3);
4212  str += 3;
4213  *str++ = ' ';
4214  if (DateOrder == DATEORDER_DMY)
4215  {
4216  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4217  *str++ = ' ';
4218  memcpy(str, months[tm->tm_mon - 1], 3);
4219  str += 3;
4220  }
4221  else
4222  {
4223  memcpy(str, months[tm->tm_mon - 1], 3);
4224  str += 3;
4225  *str++ = ' ';
4226  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4227  }
4228  *str++ = ' ';
4229  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4230  *str++ = ':';
4231  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4232  *str++ = ':';
4233  str = AppendTimestampSeconds(str, tm, fsec);
4234  *str++ = ' ';
4235  str = pg_ltostr_zeropad(str,
4236  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4237 
4238  if (print_tz)
4239  {
4240  if (tzn)
4241  {
4242  sprintf(str, " %.*s", MAXTZLEN, tzn);
4243  str += strlen(str);
4244  }
4245  else
4246  {
4247  /*
4248  * We have a time zone, but no string version. Use the
4249  * numeric form, but be sure to include a leading space to
4250  * avoid formatting something which would be rejected by
4251  * the date/time parser later. - thomas 2001-10-19
4252  */
4253  *str++ = ' ';
4254  str = EncodeTimezone(str, tz, style);
4255  }
4256  }
4257  break;
4258  }
4259 
4260  if (tm->tm_year <= 0)
4261  {
4262  memcpy(str, " BC", 3); /* Don't copy NUL */
4263  str += 3;
4264  }
4265  *str = '\0';
4266 }
int tm_wday
Definition: pgtime.h:33
int tm_isdst
Definition: pgtime.h:35
int tm_hour
Definition: pgtime.h:29
static char * EncodeTimezone(char *str, int tz, int style)
Definition: datetime.c:3952
#define USE_SQL_DATES
Definition: miscadmin.h:211
#define MAXTZLEN
Definition: miscadmin.h:237
#define USE_ISO_DATES
Definition: miscadmin.h:210
#define MONTHS_PER_YEAR
Definition: timestamp.h:81
const char *const months[]
Definition: datetime.c:71
int j2day(int date)
Definition: datetime.c:357
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define USE_POSTGRES_DATES
Definition: miscadmin.h:209
const char *const days[]
Definition: datetime.c:74
int DateOrder
Definition: globals.c:107
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
static char * AppendTimestampSeconds(char *cp, struct pg_tm *tm, fsec_t fsec)
Definition: datetime.c:522
#define DATEORDER_DMY
Definition: miscadmin.h:217
int date2j(int y, int m, int d)
Definition: datetime.c:297
#define Assert(condition)
Definition: c.h:670
#define USE_XSD_DATES
Definition: miscadmin.h:213
int tm_year
Definition: pgtime.h:32
#define USE_GERMAN_DATES
Definition: miscadmin.h:212
int tm_min
Definition: pgtime.h:28
void EncodeInterval ( struct pg_tm tm,
fsec_t  fsec,
int  style,
char *  str 
)

Definition at line 4347 of file datetime.c.

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

Referenced by interval_out(), and reltimeout().

4348 {
4349  char *cp = str;
4350  int year = tm->tm_year;
4351  int mon = tm->tm_mon;
4352  int mday = tm->tm_mday;
4353  int hour = tm->tm_hour;
4354  int min = tm->tm_min;
4355  int sec = tm->tm_sec;
4356  bool is_before = FALSE;
4357  bool is_zero = TRUE;
4358 
4359  /*
4360  * The sign of year and month are guaranteed to match, since they are
4361  * stored internally as "month". But we'll need to check for is_before and
4362  * is_zero when determining the signs of day and hour/minute/seconds
4363  * fields.
4364  */
4365  switch (style)
4366  {
4367  /* SQL Standard interval format */
4368  case INTSTYLE_SQL_STANDARD:
4369  {
4370  bool has_negative = year < 0 || mon < 0 ||
4371  mday < 0 || hour < 0 ||
4372  min < 0 || sec < 0 || fsec < 0;
4373  bool has_positive = year > 0 || mon > 0 ||
4374  mday > 0 || hour > 0 ||
4375  min > 0 || sec > 0 || fsec > 0;
4376  bool has_year_month = year != 0 || mon != 0;
4377  bool has_day_time = mday != 0 || hour != 0 ||
4378  min != 0 || sec != 0 || fsec != 0;
4379  bool has_day = mday != 0;
4380  bool sql_standard_value = !(has_negative && has_positive) &&
4381  !(has_year_month && has_day_time);
4382 
4383  /*
4384  * SQL Standard wants only 1 "<sign>" preceding the whole
4385  * interval ... but can't do that if mixed signs.
4386  */
4387  if (has_negative && sql_standard_value)
4388  {
4389  *cp++ = '-';
4390  year = -year;
4391  mon = -mon;
4392  mday = -mday;
4393  hour = -hour;
4394  min = -min;
4395  sec = -sec;
4396  fsec = -fsec;
4397  }
4398 
4399  if (!has_negative && !has_positive)
4400  {
4401  sprintf(cp, "0");
4402  }
4403  else if (!sql_standard_value)
4404  {
4405  /*
4406  * For non sql-standard interval values, force outputting
4407  * the signs to avoid ambiguities with intervals with
4408  * mixed sign components.
4409  */
4410  char year_sign = (year < 0 || mon < 0) ? '-' : '+';
4411  char day_sign = (mday < 0) ? '-' : '+';
4412  char sec_sign = (hour < 0 || min < 0 ||
4413  sec < 0 || fsec < 0) ? '-' : '+';
4414 
4415  sprintf(cp, "%c%d-%d %c%d %c%d:%02d:",
4416  year_sign, abs(year), abs(mon),
4417  day_sign, abs(mday),
4418  sec_sign, abs(hour), abs(min));
4419  cp += strlen(cp);
4420  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4421  *cp = '\0';
4422  }
4423  else if (has_year_month)
4424  {
4425  sprintf(cp, "%d-%d", year, mon);
4426  }
4427  else if (has_day)
4428  {
4429  sprintf(cp, "%d %d:%02d:", mday, hour, min);
4430  cp += strlen(cp);
4431  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4432  *cp = '\0';
4433  }
4434  else
4435  {
4436  sprintf(cp, "%d:%02d:", hour, min);
4437  cp += strlen(cp);
4438  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4439  *cp = '\0';
4440  }
4441  }
4442  break;
4443 
4444  /* ISO 8601 "time-intervals by duration only" */
4445  case INTSTYLE_ISO_8601:
4446  /* special-case zero to avoid printing nothing */
4447  if (year == 0 && mon == 0 && mday == 0 &&
4448  hour == 0 && min == 0 && sec == 0 && fsec == 0)
4449  {
4450  sprintf(cp, "PT0S");
4451  break;
4452  }
4453  *cp++ = 'P';
4454  cp = AddISO8601IntPart(cp, year, 'Y');
4455  cp = AddISO8601IntPart(cp, mon, 'M');
4456  cp = AddISO8601IntPart(cp, mday, 'D');
4457  if (hour != 0 || min != 0 || sec != 0 || fsec != 0)
4458  *cp++ = 'T';
4459  cp = AddISO8601IntPart(cp, hour, 'H');
4460  cp = AddISO8601IntPart(cp, min, 'M');
4461  if (sec != 0 || fsec != 0)
4462  {
4463  if (sec < 0 || fsec < 0)
4464  *cp++ = '-';
4465  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4466  *cp++ = 'S';
4467  *cp++ = '\0';
4468  }
4469  break;
4470 
4471  /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
4472  case INTSTYLE_POSTGRES:
4473  cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before);
4474 
4475  /*
4476  * Ideally we should spell out "month" like we do for "year" and
4477  * "day". However, for backward compatibility, we can't easily
4478  * fix this. bjm 2011-05-24
4479  */
4480  cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before);
4481  cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before);
4482  if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0)
4483  {
4484  bool minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
4485 
4486  sprintf(cp, "%s%s%02d:%02d:",
4487  is_zero ? "" : " ",
4488  (minus ? "-" : (is_before ? "+" : "")),
4489  abs(hour), abs(min));
4490  cp += strlen(cp);
4491  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4492  *cp = '\0';
4493  }
4494  break;
4495 
4496  /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
4498  default:
4499  strcpy(cp, "@");
4500  cp++;
4501  cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
4502  cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
4503  cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
4504  cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
4505  cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
4506  if (sec != 0 || fsec != 0)
4507  {
4508  *cp++ = ' ';
4509  if (sec < 0 || (sec == 0 && fsec < 0))
4510  {
4511  if (is_zero)
4512  is_before = TRUE;
4513  else if (!is_before)
4514  *cp++ = '-';
4515  }
4516  else if (is_before)
4517  *cp++ = '-';
4518  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4519  sprintf(cp, " sec%s",
4520  (abs(sec) != 1 || fsec != 0) ? "s" : "");
4521  is_zero = FALSE;
4522  }
4523  /* identically zero? then put in a unitless zero... */
4524  if (is_zero)
4525  strcat(cp, " 0");
4526  if (is_before)
4527  strcat(cp, " ago");
4528  break;
4529  }
4530 }
#define INTSTYLE_POSTGRES_VERBOSE
Definition: miscadmin.h:231
int tm_hour
Definition: pgtime.h:29
#define MAX_INTERVAL_PRECISION
Definition: timestamp.h:66
static char * AddISO8601IntPart(char *cp, int value, char units)
Definition: datetime.c:4275
#define FALSE
Definition: c.h:218
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
static char * AddPostgresIntPart(char *cp, int value, const char *units, bool *is_zero, bool *is_before)
Definition: datetime.c:4285
#define INTSTYLE_ISO_8601
Definition: miscadmin.h:233
static char * AddVerboseIntPart(char *cp, int value, const char *units, bool *is_zero, bool *is_before)
Definition: datetime.c:4308
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:438
#define INTSTYLE_SQL_STANDARD
Definition: miscadmin.h:232
int tm_year
Definition: pgtime.h:32
#define TRUE
Definition: c.h:214
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
#define INTSTYLE_POSTGRES
Definition: miscadmin.h:230
void EncodeTimeOnly ( struct pg_tm tm,
fsec_t  fsec,
bool  print_tz,
int  tz,
int  style,
char *  str 
)

Definition at line 4075 of file datetime.c.

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

Referenced by time_out(), and timetz_out().

4076 {
4077  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4078  *str++ = ':';
4079  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4080  *str++ = ':';
4081  str = AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
4082  if (print_tz)
4083  str = EncodeTimezone(str, tz, style);
4084  *str = '\0';
4085 }
int tm_hour
Definition: pgtime.h:29
static char * EncodeTimezone(char *str, int tz, int style)
Definition: datetime.c:3952
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:438
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
#define MAX_TIME_PRECISION
Definition: date.h:67
static char* EncodeTimezone ( char *  str,
int  tz,
int  style 
)
static

Definition at line 3952 of file datetime.c.

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

Referenced by EncodeDateTime(), and EncodeTimeOnly().

3953 {
3954  int hour,
3955  min,
3956  sec;
3957 
3958  sec = abs(tz);
3959  min = sec / SECS_PER_MINUTE;
3960  sec -= min * SECS_PER_MINUTE;
3961  hour = min / MINS_PER_HOUR;
3962  min -= hour * MINS_PER_HOUR;
3963 
3964  /* TZ is negated compared to sign we wish to display ... */
3965  *str++ = (tz <= 0 ? '+' : '-');
3966 
3967  if (sec != 0)
3968  {
3969  str = pg_ltostr_zeropad(str, hour, 2);
3970  *str++ = ':';
3971  str = pg_ltostr_zeropad(str, min, 2);
3972  *str++ = ':';
3973  str = pg_ltostr_zeropad(str, sec, 2);
3974  }
3975  else if (min != 0 || style == USE_XSD_DATES)
3976  {
3977  str = pg_ltostr_zeropad(str, hour, 2);
3978  *str++ = ':';
3979  str = pg_ltostr_zeropad(str, min, 2);
3980  }
3981  else
3982  str = pg_ltostr_zeropad(str, hour, 2);
3983  return str;
3984 }
#define MINS_PER_HOUR
Definition: timestamp.h:101
#define SECS_PER_MINUTE
Definition: timestamp.h:100
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
#define USE_XSD_DATES
Definition: miscadmin.h:213
static pg_tz * FetchDynamicTimeZone ( TimeZoneAbbrevTable tbl,
const datetkn tp 
)
static

Definition at line 4721 of file datetime.c.

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

Referenced by DecodeTimezoneAbbrev(), and pg_timezone_abbrevs().

4722 {
4723  DynamicZoneAbbrev *dtza;
4724 
4725  /* Just some sanity checks to prevent indexing off into nowhere */
4726  Assert(tp->type == DYNTZ);
4727  Assert(tp->value > 0 && tp->value < tbl->tblsize);
4728 
4729  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tp->value);
4730 
4731  /* Look up the underlying zone if we haven't already */
4732  if (dtza->tz == NULL)
4733  {
4734  dtza->tz = pg_tzset(dtza->zone);
4735 
4736  /*
4737  * Ideally we'd let the caller ereport instead of doing it here, but
4738  * then there is no way to report the bad time zone name.
4739  */
4740  if (dtza->tz == NULL)
4741  ereport(ERROR,
4742  (errcode(ERRCODE_CONFIG_FILE_ERROR),
4743  errmsg("time zone \"%s\" not recognized",
4744  dtza->zone),
4745  errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".",
4746  tp->token)));
4747  }
4748  return dtza->tz;
4749 }
int errcode(int sqlerrcode)
Definition: elog.c:575
int32 value
Definition: datetime.h:214
pg_tz * pg_tzset(const char *tzname)
Definition: pgtz.c:218
#define ERROR
Definition: elog.h:43
char token[TOKMAXLEN+1]
Definition: datetime.h:212
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
char zone[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:230
char type
Definition: datetime.h:213
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define DYNTZ
Definition: datetime.h:98
void GetCurrentDateTime ( struct pg_tm tm)

Definition at line 375 of file datetime.c.

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

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

376 {
377  int tz;
378  fsec_t fsec;
379 
381  NULL, NULL);
382  /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */
383 }
double fsec_t
Definition: timestamp.h:53
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1951
TimestampTz GetCurrentTransactionStartTimestamp(void)
Definition: xact.c:707
#define NULL
Definition: c.h:226
void GetCurrentTimeUsec ( struct pg_tm tm,
fsec_t fsec,
int *  tzp 
)

Definition at line 392 of file datetime.c.

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

Referenced by DecodeDateTime(), and DecodeTimeOnly().

393 {
394  int tz;
395 
397  NULL, NULL);
398  /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */
399  if (tzp != NULL)
400  *tzp = tz;
401 }
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1951
TimestampTz GetCurrentTransactionStartTimestamp(void)
Definition: xact.c:707
#define NULL
Definition: c.h:226
void InstallTimeZoneAbbrevs ( TimeZoneAbbrevTable tbl)

Definition at line 4710 of file datetime.c.

Referenced by assign_timezone_abbreviations().

4711 {
4712  zoneabbrevtbl = tbl;
4713  /* reset abbrevcache, which may contain pointers into old table */
4714  memset(abbrevcache, 0, sizeof(abbrevcache));
4715 }
static TimeZoneAbbrevTable * zoneabbrevtbl
Definition: datetime.c:248
static const datetkn * abbrevcache[MAXDATEFIELDS]
Definition: datetime.c:256
static int ISO8601IntegerWidth ( char *  fieldstart)
static

Definition at line 3600 of file datetime.c.

Referenced by DecodeISO8601Interval().

3601 {
3602  /* We might have had a leading '-' */
3603  if (*fieldstart == '-')
3604  fieldstart++;
3605  return strspn(fieldstart, "0123456789");
3606 }
void j2date ( int  jd,
int *  year,
int *  month,
int *  day 
)

Definition at line 322 of file datetime.c.

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

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

Definition at line 357 of file datetime.c.

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

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

Definition at line 626 of file datetime.c.

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

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

628 {
629  int nf = 0;
630  const char *cp = timestr;
631  char *bufp = workbuf;
632  const char *bufend = workbuf + buflen;
633 
634  /*
635  * Set the character pointed-to by "bufptr" to "newchar", and increment
636  * "bufptr". "end" gives the end of the buffer -- we return an error if
637  * there is no space left to append a character to the buffer. Note that
638  * "bufptr" is evaluated twice.
639  */
640 #define APPEND_CHAR(bufptr, end, newchar) \
641  do \
642  { \
643  if (((bufptr) + 1) >= (end)) \
644  return DTERR_BAD_FORMAT; \
645  *(bufptr)++ = newchar; \
646  } while (0)
647 
648  /* outer loop through fields */
649  while (*cp != '\0')
650  {
651  /* Ignore spaces between fields */
652  if (isspace((unsigned char) *cp))
653  {
654  cp++;
655  continue;
656  }
657 
658  /* Record start of current field */
659  if (nf >= maxfields)
660  return DTERR_BAD_FORMAT;
661  field[nf] = bufp;
662 
663  /* leading digit? then date or time */
664  if (isdigit((unsigned char) *cp))
665  {
666  APPEND_CHAR(bufp, bufend, *cp++);
667  while (isdigit((unsigned char) *cp))
668  APPEND_CHAR(bufp, bufend, *cp++);
669 
670  /* time field? */
671  if (*cp == ':')
672  {
673  ftype[nf] = DTK_TIME;
674  APPEND_CHAR(bufp, bufend, *cp++);
675  while (isdigit((unsigned char) *cp) ||
676  (*cp == ':') || (*cp == '.'))
677  APPEND_CHAR(bufp, bufend, *cp++);
678  }
679  /* date field? allow embedded text month */
680  else if (*cp == '-' || *cp == '/' || *cp == '.')
681  {
682  /* save delimiting character to use later */
683  char delim = *cp;
684 
685  APPEND_CHAR(bufp, bufend, *cp++);
686  /* second field is all digits? then no embedded text month */
687  if (isdigit((unsigned char) *cp))
688  {
689  ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
690  while (isdigit((unsigned char) *cp))
691  APPEND_CHAR(bufp, bufend, *cp++);
692 
693  /*
694  * insist that the delimiters match to get a three-field
695  * date.
696  */
697  if (*cp == delim)
698  {
699  ftype[nf] = DTK_DATE;
700  APPEND_CHAR(bufp, bufend, *cp++);
701  while (isdigit((unsigned char) *cp) || *cp == delim)
702  APPEND_CHAR(bufp, bufend, *cp++);
703  }
704  }
705  else
706  {
707  ftype[nf] = DTK_DATE;
708  while (isalnum((unsigned char) *cp) || *cp == delim)
709  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
710  }
711  }
712 
713  /*
714  * otherwise, number only and will determine year, month, day, or
715  * concatenated fields later...
716  */
717  else
718  ftype[nf] = DTK_NUMBER;
719  }
720  /* Leading decimal point? Then fractional seconds... */
721  else if (*cp == '.')
722  {
723  APPEND_CHAR(bufp, bufend, *cp++);
724  while (isdigit((unsigned char) *cp))
725  APPEND_CHAR(bufp, bufend, *cp++);
726 
727  ftype[nf] = DTK_NUMBER;
728  }
729 
730  /*
731  * text? then date string, month, day of week, special, or timezone
732  */
733  else if (isalpha((unsigned char) *cp))
734  {
735  bool is_date;
736 
737  ftype[nf] = DTK_STRING;
738  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
739  while (isalpha((unsigned char) *cp))
740  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
741 
742  /*
743  * Dates can have embedded '-', '/', or '.' separators. It could
744  * also be a timezone name containing embedded '/', '+', '-', '_',
745  * or ':' (but '_' or ':' can't be the first punctuation). If the
746  * next character is a digit or '+', we need to check whether what
747  * we have so far is a recognized non-timezone keyword --- if so,
748  * don't believe that this is the start of a timezone.
749  */
750  is_date = false;
751  if (*cp == '-' || *cp == '/' || *cp == '.')
752  is_date = true;
753  else if (*cp == '+' || isdigit((unsigned char) *cp))
754  {
755  *bufp = '\0'; /* null-terminate current field value */
756  /* we need search only the core token table, not TZ names */
757  if (datebsearch(field[nf], datetktbl, szdatetktbl) == NULL)
758  is_date = true;
759  }
760  if (is_date)
761  {
762  ftype[nf] = DTK_DATE;
763  do
764  {
765  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
766  } while (*cp == '+' || *cp == '-' ||
767  *cp == '/' || *cp == '_' ||
768  *cp == '.' || *cp == ':' ||
769  isalnum((unsigned char) *cp));
770  }
771  }
772  /* sign? then special or numeric timezone */
773  else if (*cp == '+' || *cp == '-')
774  {
775  APPEND_CHAR(bufp, bufend, *cp++);
776  /* soak up leading whitespace */
777  while (isspace((unsigned char) *cp))
778  cp++;