PostgreSQL Source Code  git master
interval.c File Reference
#include "postgres_fe.h"
#include <time.h>
#include <math.h>
#include <limits.h>
#include "common/string.h"
#include "extern.h"
#include "dt.h"
#include "pgtypes_error.h"
#include "pgtypes_interval.h"
Include dependency graph for interval.c:

Go to the source code of this file.

Functions

static void AdjustFractSeconds (double frac, struct tm *tm, fsec_t *fsec, int scale)
 
static void AdjustFractDays (double frac, struct tm *tm, fsec_t *fsec, int scale)
 
static int ParseISO8601Number (const char *str, char **endptr, int *ipart, double *fpart)
 
static int ISO8601IntegerWidth (const char *fieldstart)
 
static void ClearPgTm (struct tm *tm, fsec_t *fsec)
 
static int DecodeISO8601Interval (char *str, int *dtype, struct tm *tm, fsec_t *fsec)
 
int DecodeInterval (char **field, int *ftype, int nf, int *dtype, struct tm *tm, fsec_t *fsec)
 
static char * AddVerboseIntPart (char *cp, int value, const char *units, bool *is_zero, bool *is_before)
 
static char * AddPostgresIntPart (char *cp, int value, const char *units, bool *is_zero, bool *is_before)
 
static char * AddISO8601IntPart (char *cp, int value, char units)
 
static void AppendSeconds (char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
 
void EncodeInterval (struct tm *tm, fsec_t fsec, int style, char *str)
 
static int interval2tm (interval span, struct tm *tm, fsec_t *fsec)
 
static int tm2interval (struct tm *tm, fsec_t fsec, interval *span)
 
intervalPGTYPESinterval_new (void)
 
void PGTYPESinterval_free (interval *intvl)
 
intervalPGTYPESinterval_from_asc (char *str, char **endptr)
 
char * PGTYPESinterval_to_asc (interval *span)
 
int PGTYPESinterval_copy (interval *intvlsrc, interval *intvldest)
 

Function Documentation

◆ AddISO8601IntPart()

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

Definition at line 727 of file interval.c.

Referenced by EncodeInterval().

728 {
729  if (value == 0)
730  return cp;
731  sprintf(cp, "%d%c", value, units);
732  return cp + strlen(cp);
733 }
static struct @131 value

◆ AddPostgresIntPart()

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

Definition at line 704 of file interval.c.

Referenced by EncodeInterval().

706 {
707  if (value == 0)
708  return cp;
709  sprintf(cp, "%s%s%d %s%s",
710  (!*is_zero) ? " " : "",
711  (*is_before && value > 0) ? "+" : "",
712  value,
713  units,
714  (value != 1) ? "s" : "");
715 
716  /*
717  * Each nonzero field sets is_before for (only) the next one. This is a
718  * tad bizarre but it's how it worked before...
719  */
720  *is_before = (value < 0);
721  *is_zero = false;
722  return cp + strlen(cp);
723 }
static struct @131 value

◆ AddVerboseIntPart()

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

Definition at line 684 of file interval.c.

References value.

Referenced by EncodeInterval().

686 {
687  if (value == 0)
688  return cp;
689  /* first nonzero value sets is_before */
690  if (*is_zero)
691  {
692  *is_before = (value < 0);
693  value = abs(value);
694  }
695  else if (*is_before)
696  value = -value;
697  sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
698  *is_zero = false;
699  return cp + strlen(cp);
700 }
static struct @131 value

◆ AdjustFractDays()

static void AdjustFractDays ( double  frac,
struct tm tm,
fsec_t fsec,
int  scale 
)
static

Definition at line 41 of file interval.c.

References AdjustFractSeconds(), scale, and SECS_PER_DAY.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

42 {
43  int extra_days;
44 
45  if (frac == 0)
46  return;
47  frac *= scale;
48  extra_days = (int) frac;
49  tm->tm_mday += extra_days;
50  frac -= extra_days;
51  AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
52 }
int scale
Definition: pgbench.c:121
static struct pg_tm tm
Definition: localtime.c:106
#define SECS_PER_DAY
Definition: timestamp.h:86
int tm_mday
Definition: pgtime.h:30
static void AdjustFractSeconds(double frac, struct tm *tm, fsec_t *fsec, int scale)
Definition: interval.c:23

◆ AdjustFractSeconds()

static void AdjustFractSeconds ( double  frac,
struct tm tm,
fsec_t fsec,
int  scale 
)
static

Definition at line 23 of file interval.c.

References rint(), and scale.

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

24 {
25  int sec;
26 
27  if (frac == 0)
28  return;
29  frac *= scale;
30  sec = (int) frac;
31  tm->tm_sec += sec;
32  frac -= sec;
33  *fsec += rint(frac * 1000000);
34 }
int scale
Definition: pgbench.c:121
static struct pg_tm tm
Definition: localtime.c:106
double rint(double x)
Definition: rint.c:22
int tm_sec
Definition: pgtime.h:27

◆ AppendSeconds()

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

Definition at line 737 of file interval.c.

References Abs, and TrimTrailingZeros().

Referenced by EncodeInterval().

738 {
739  if (fsec == 0)
740  {
741  if (fillzeros)
742  sprintf(cp, "%02d", abs(sec));
743  else
744  sprintf(cp, "%d", abs(sec));
745  }
746  else
747  {
748  if (fillzeros)
749  sprintf(cp, "%02d.%0*d", abs(sec), precision, (int) Abs(fsec));
750  else
751  sprintf(cp, "%d.%0*d", abs(sec), precision, (int) Abs(fsec));
752  TrimTrailingZeros(cp);
753  }
754 }
#define Abs(x)
Definition: c.h:863
void TrimTrailingZeros(char *)
Definition: dt_common.c:728

◆ ClearPgTm()

static void ClearPgTm ( struct tm tm,
fsec_t fsec 
)
inlinestatic

Definition at line 94 of file interval.c.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

95 {
96  tm->tm_year = 0;
97  tm->tm_mon = 0;
98  tm->tm_mday = 0;
99  tm->tm_hour = 0;
100  tm->tm_min = 0;
101  tm->tm_sec = 0;
102  *fsec = 0;
103 }
int tm_hour
Definition: pgtime.h:29
static struct pg_tm tm
Definition: localtime.c:106
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

◆ DecodeInterval()

int DecodeInterval ( char **  field,
int *  ftype,
int  nf,
int *  dtype,
struct tm tm,
fsec_t fsec 
)

Definition at line 326 of file interval.c.

References AdjustFractDays(), AdjustFractSeconds(), AGO, Assert, ClearPgTm(), DAY, DAYS_PER_MONTH, 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, HOUR, i, IGNORE_DTF, INTERVAL_FULL_RANGE, INTERVAL_MASK, IntervalStyle, INTSTYLE_POSTGRES_VERBOSE, INTSTYLE_SQL_STANDARD, MICROSECOND, MILLISECOND, MINUTE, MONTH, MONTHS_PER_YEAR, range(), RESERV, rint(), SECOND, SECS_PER_DAY, SECS_PER_HOUR, SECS_PER_MINUTE, strtoint(), generate_unaccent_rules::type, TZ, UNITS, USECS_PER_SEC, val, and YEAR.

Referenced by PGTYPESinterval_from_asc().

328 {
331  bool is_before = false;
332  char *cp;
333  int fmask = 0,
334  tmask,
335  type;
336  int i;
337  int dterr;
338  int val;
339  double fval;
340 
341  *dtype = DTK_DELTA;
342  type = IGNORE_DTF;
343  ClearPgTm(tm, fsec);
344 
345  /* read through list backwards to pick up units before values */
346  for (i = nf - 1; i >= 0; i--)
347  {
348  switch (ftype[i])
349  {
350  case DTK_TIME:
351  dterr = DecodeTime(field[i], /* range, */
352  &tmask, tm, fsec);
353  if (dterr)
354  return dterr;
355  type = DTK_DAY;
356  break;
357 
358  case DTK_TZ:
359 
360  /*
361  * Timezone is a token with a leading sign character and at
362  * least one digit; there could be ':', '.', '-' embedded in
363  * it as well.
364  */
365  Assert(*field[i] == '-' || *field[i] == '+');
366 
367  /*
368  * Try for hh:mm or hh:mm:ss. If not, fall through to
369  * DTK_NUMBER case, which can handle signed float numbers and
370  * signed year-month values.
371  */
372  if (strchr(field[i] + 1, ':') != NULL &&
373  DecodeTime(field[i] + 1, /* INTERVAL_FULL_RANGE, */
374  &tmask, tm, fsec) == 0)
375  {
376  if (*field[i] == '-')
377  {
378  /* flip the sign on all fields */
379  tm->tm_hour = -tm->tm_hour;
380  tm->tm_min = -tm->tm_min;
381  tm->tm_sec = -tm->tm_sec;
382  *fsec = -(*fsec);
383  }
384 
385  /*
386  * Set the next type to be a day, if units are not
387  * specified. This handles the case of '1 +02:03' since we
388  * are reading right to left.
389  */
390  type = DTK_DAY;
391  tmask = DTK_M(TZ);
392  break;
393  }
394  /* FALL THROUGH */
395 
396  case DTK_DATE:
397  case DTK_NUMBER:
398  if (type == IGNORE_DTF)
399  {
400  /* use typmod to decide what rightmost field is */
401  switch (range)
402  {
403  case INTERVAL_MASK(YEAR):
404  type = DTK_YEAR;
405  break;
406  case INTERVAL_MASK(MONTH):
408  type = DTK_MONTH;
409  break;
410  case INTERVAL_MASK(DAY):
411  type = DTK_DAY;
412  break;
413  case INTERVAL_MASK(HOUR):
417  type = DTK_HOUR;
418  break;
419  case INTERVAL_MASK(MINUTE):
421  type = DTK_MINUTE;
422  break;
423  case INTERVAL_MASK(SECOND):
426  type = DTK_SECOND;
427  break;
428  default:
429  type = DTK_SECOND;
430  break;
431  }
432  }
433 
434  errno = 0;
435  val = strtoint(field[i], &cp, 10);
436  if (errno == ERANGE)
437  return DTERR_FIELD_OVERFLOW;
438 
439  if (*cp == '-')
440  {
441  /* SQL "years-months" syntax */
442  int val2;
443 
444  val2 = strtoint(cp + 1, &cp, 10);
445  if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
446  return DTERR_FIELD_OVERFLOW;
447  if (*cp != '\0')
448  return DTERR_BAD_FORMAT;
449  type = DTK_MONTH;
450  if (*field[i] == '-')
451  val2 = -val2;
452  val = val * MONTHS_PER_YEAR + val2;
453  fval = 0;
454  }
455  else if (*cp == '.')
456  {
457  errno = 0;
458  fval = strtod(cp, &cp);
459  if (*cp != '\0' || errno != 0)
460  return DTERR_BAD_FORMAT;
461 
462  if (*field[i] == '-')
463  fval = -fval;
464  }
465  else if (*cp == '\0')
466  fval = 0;
467  else
468  return DTERR_BAD_FORMAT;
469 
470  tmask = 0; /* DTK_M(type); */
471 
472  switch (type)
473  {
474  case DTK_MICROSEC:
475  *fsec += rint(val + fval);
476  tmask = DTK_M(MICROSECOND);
477  break;
478 
479  case DTK_MILLISEC:
480  *fsec += rint((val + fval) * 1000);
481  tmask = DTK_M(MILLISECOND);
482  break;
483 
484  case DTK_SECOND:
485  tm->tm_sec += val;
486  *fsec += rint(fval * 1000000);
487 
488  /*
489  * If any subseconds were specified, consider this
490  * microsecond and millisecond input as well.
491  */
492  if (fval == 0)
493  tmask = DTK_M(SECOND);
494  else
495  tmask = DTK_ALL_SECS_M;
496  break;
497 
498  case DTK_MINUTE:
499  tm->tm_min += val;
500  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
501  tmask = DTK_M(MINUTE);
502  break;
503 
504  case DTK_HOUR:
505  tm->tm_hour += val;
506  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
507  tmask = DTK_M(HOUR);
508  type = DTK_DAY;
509  break;
510 
511  case DTK_DAY:
512  tm->tm_mday += val;
513  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
514  tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
515  break;
516 
517  case DTK_WEEK:
518  tm->tm_mday += val * 7;
519  AdjustFractDays(fval, tm, fsec, 7);
520  tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
521  break;
522 
523  case DTK_MONTH:
524  tm->tm_mon += val;
525  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
526  tmask = DTK_M(MONTH);
527  break;
528 
529  case DTK_YEAR:
530  tm->tm_year += val;
531  if (fval != 0)
532  tm->tm_mon += fval * MONTHS_PER_YEAR;
533  tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
534  break;
535 
536  case DTK_DECADE:
537  tm->tm_year += val * 10;
538  if (fval != 0)
539  tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
540  tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
541  break;
542 
543  case DTK_CENTURY:
544  tm->tm_year += val * 100;
545  if (fval != 0)
546  tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
547  tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
548  break;
549 
550  case DTK_MILLENNIUM:
551  tm->tm_year += val * 1000;
552  if (fval != 0)
553  tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
554  tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
555  break;
556 
557  default:
558  return DTERR_BAD_FORMAT;
559  }
560  break;
561 
562  case DTK_STRING:
563  case DTK_SPECIAL:
564  type = DecodeUnits(i, field[i], &val);
565  if (type == IGNORE_DTF)
566  continue;
567 
568  tmask = 0; /* DTK_M(type); */
569  switch (type)
570  {
571  case UNITS:
572  type = val;
573  break;
574 
575  case AGO:
576  is_before = true;
577  type = val;
578  break;
579 
580  case RESERV:
581  tmask = (DTK_DATE_M | DTK_TIME_M);
582  *dtype = val;
583  break;
584 
585  default:
586  return DTERR_BAD_FORMAT;
587  }
588  break;
589 
590  default:
591  return DTERR_BAD_FORMAT;
592  }
593 
594  if (tmask & fmask)
595  return DTERR_BAD_FORMAT;
596  fmask |= tmask;
597  }
598 
599  /* ensure that at least one time field has been found */
600  if (fmask == 0)
601  return DTERR_BAD_FORMAT;
602 
603  /* ensure fractional seconds are fractional */
604  if (*fsec != 0)
605  {
606  int sec;
607 
608  sec = *fsec / USECS_PER_SEC;
609  *fsec -= sec * USECS_PER_SEC;
610  tm->tm_sec += sec;
611  }
612 
613  /*----------
614  * The SQL standard defines the interval literal
615  * '-1 1:00:00'
616  * to mean "negative 1 days and negative 1 hours", while Postgres
617  * traditionally treats this as meaning "negative 1 days and positive
618  * 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign
619  * to all fields if there are no other explicit signs.
620  *
621  * We leave the signs alone if there are additional explicit signs.
622  * This protects us against misinterpreting postgres-style dump output,
623  * since the postgres-style output code has always put an explicit sign on
624  * all fields following a negative field. But note that SQL-spec output
625  * is ambiguous and can be misinterpreted on load! (So it's best practice
626  * to dump in postgres style, not SQL style.)
627  *----------
628  */
629  if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
630  {
631  /* Check for additional explicit signs */
632  bool more_signs = false;
633 
634  for (i = 1; i < nf; i++)
635  {
636  if (*field[i] == '-' || *field[i] == '+')
637  {
638  more_signs = true;
639  break;
640  }
641  }
642 
643  if (!more_signs)
644  {
645  /*
646  * Rather than re-determining which field was field[0], just force
647  * 'em all negative.
648  */
649  if (*fsec > 0)
650  *fsec = -(*fsec);
651  if (tm->tm_sec > 0)
652  tm->tm_sec = -tm->tm_sec;
653  if (tm->tm_min > 0)
654  tm->tm_min = -tm->tm_min;
655  if (tm->tm_hour > 0)
656  tm->tm_hour = -tm->tm_hour;
657  if (tm->tm_mday > 0)
658  tm->tm_mday = -tm->tm_mday;
659  if (tm->tm_mon > 0)
660  tm->tm_mon = -tm->tm_mon;
661  if (tm->tm_year > 0)
662  tm->tm_year = -tm->tm_year;
663  }
664  }
665 
666  /* finally, AGO negates everything */
667  if (is_before)
668  {
669  *fsec = -(*fsec);
670  tm->tm_sec = -tm->tm_sec;
671  tm->tm_min = -tm->tm_min;
672  tm->tm_hour = -tm->tm_hour;
673  tm->tm_mday = -tm->tm_mday;
674  tm->tm_mon = -tm->tm_mon;
675  tm->tm_year = -tm->tm_year;
676  }
677 
678  return 0;
679 }
#define INTSTYLE_POSTGRES_VERBOSE
Definition: miscadmin.h:233
static void AdjustFractDays(double frac, struct tm *tm, fsec_t *fsec, int scale)
Definition: interval.c:41
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define DTK_CENTURY
Definition: datetime.h:172
#define DAY
Definition: datetime.h:94
#define UNITS
Definition: datetime.h:108
#define IGNORE_DTF
Definition: datetime.h:99
#define DTK_WEEK
Definition: datetime.h:167
#define DTK_YEAR
Definition: datetime.h:170
#define USECS_PER_SEC
Definition: timestamp.h:94
#define YEAR
Definition: datetime.h:93
#define DTK_DELTA
Definition: datetime.h:162
int tm_hour
Definition: pgtime.h:29
#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:116
#define TZ
Definition: datetime.h:96
#define SECOND
Definition: datetime.h:103
int DecodeUnits(int field, char *lowtoken, int *val)
Definition: datetime.c:3717
#define INTERVAL_FULL_RANGE
Definition: timestamp.h:48
#define DTK_DATE_M
Definition: datetime.h:194
static struct pg_tm tm
Definition: localtime.c:106
static void ClearPgTm(struct tm *tm, fsec_t *fsec)
Definition: interval.c:94
#define DTK_MONTH
Definition: datetime.h:168
#define DTK_MILLISEC
Definition: datetime.h:174
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
#define DTK_DECADE
Definition: datetime.h:171
#define DTK_TZ
Definition: datetime.h:147
#define DTK_HOUR
Definition: datetime.h:165
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
#define MILLISECOND
Definition: datetime.h:104
#define SECS_PER_DAY
Definition: timestamp.h:86
#define DTK_SECOND
Definition: datetime.h:163
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:88
int strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base)
Definition: string.c:50
#define DTK_NUMBER
Definition: datetime.h:142
#define MINUTE
Definition: datetime.h:102
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:416
double rint(double x)
Definition: rint.c:22
#define SECS_PER_HOUR
Definition: timestamp.h:87
#define MONTH
Definition: datetime.h:92
#define DTK_MINUTE
Definition: datetime.h:164
#define DTK_MICROSEC
Definition: datetime.h:175
#define DAYS_PER_MONTH
Definition: timestamp.h:77
#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:2545
static void AdjustFractSeconds(double frac, struct tm *tm, fsec_t *fsec, int scale)
Definition: interval.c:23
#define Assert(condition)
Definition: c.h:699
#define DTK_STRING
Definition: datetime.h:143
#define DTK_DAY
Definition: datetime.h:166
#define RESERV
Definition: datetime.h:91
#define DTK_ALL_SECS_M
Definition: datetime.h:193
#define INTERVAL_MASK(b)
Definition: timestamp.h:45
#define INTSTYLE_SQL_STANDARD
Definition: miscadmin.h:234
int tm_year
Definition: pgtime.h:32
int i
#define DTK_M(t)
Definition: datetime.h:190
#define HOUR
Definition: datetime.h:101
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
long val
Definition: informix.c:689
#define DTK_DATE
Definition: datetime.h:145
#define DTK_SPECIAL
Definition: datetime.h:150
#define MICROSECOND
Definition: datetime.h:105

◆ DecodeISO8601Interval()

static int DecodeISO8601Interval ( char *  str,
int *  dtype,
struct tm tm,
fsec_t fsec 
)
static

Definition at line 112 of file interval.c.

References AdjustFractDays(), AdjustFractSeconds(), ClearPgTm(), DAYS_PER_MONTH, DTERR_BAD_FORMAT, DTK_DELTA, ISO8601IntegerWidth(), ParseISO8601Number(), SECS_PER_DAY, SECS_PER_HOUR, SECS_PER_MINUTE, generate_unaccent_rules::str, and val.

Referenced by PGTYPESinterval_from_asc().

114 {
115  bool datepart = true;
116  bool havefield = false;
117 
118  *dtype = DTK_DELTA;
119  ClearPgTm(tm, fsec);
120 
121  if (strlen(str) < 2 || str[0] != 'P')
122  return DTERR_BAD_FORMAT;
123 
124  str++;
125  while (*str)
126  {
127  char *fieldstart;
128  int val;
129  double fval;
130  char unit;
131  int dterr;
132 
133  if (*str == 'T') /* T indicates the beginning of the time part */
134  {
135  datepart = false;
136  havefield = false;
137  str++;
138  continue;
139  }
140 
141  fieldstart = str;
142  dterr = ParseISO8601Number(str, &str, &val, &fval);
143  if (dterr)
144  return dterr;
145 
146  /*
147  * Note: we could step off the end of the string here. Code below
148  * *must* exit the loop if unit == '\0'.
149  */
150  unit = *str++;
151 
152  if (datepart)
153  {
154  switch (unit) /* before T: Y M W D */
155  {
156  case 'Y':
157  tm->tm_year += val;
158  tm->tm_mon += (fval * 12);
159  break;
160  case 'M':
161  tm->tm_mon += val;
162  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
163  break;
164  case 'W':
165  tm->tm_mday += val * 7;
166  AdjustFractDays(fval, tm, fsec, 7);
167  break;
168  case 'D':
169  tm->tm_mday += val;
170  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
171  break;
172  case 'T': /* ISO 8601 4.4.3.3 Alternative Format / Basic */
173  case '\0':
174  if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
175  {
176  tm->tm_year += val / 10000;
177  tm->tm_mon += (val / 100) % 100;
178  tm->tm_mday += val % 100;
179  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
180  if (unit == '\0')
181  return 0;
182  datepart = false;
183  havefield = false;
184  continue;
185  }
186  /* Else fall through to extended alternative format */
187  /* FALLTHROUGH */
188  case '-': /* ISO 8601 4.4.3.3 Alternative Format,
189  * Extended */
190  if (havefield)
191  return DTERR_BAD_FORMAT;
192 
193  tm->tm_year += val;
194  tm->tm_mon += (fval * 12);
195  if (unit == '\0')
196  return 0;
197  if (unit == 'T')
198  {
199  datepart = false;
200  havefield = false;
201  continue;
202  }
203 
204  dterr = ParseISO8601Number(str, &str, &val, &fval);
205  if (dterr)
206  return dterr;
207  tm->tm_mon += val;
208  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
209  if (*str == '\0')
210  return 0;
211  if (*str == 'T')
212  {
213  datepart = false;
214  havefield = false;
215  continue;
216  }
217  if (*str != '-')
218  return DTERR_BAD_FORMAT;
219  str++;
220 
221  dterr = ParseISO8601Number(str, &str, &val, &fval);
222  if (dterr)
223  return dterr;
224  tm->tm_mday += val;
225  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
226  if (*str == '\0')
227  return 0;
228  if (*str == 'T')
229  {
230  datepart = false;
231  havefield = false;
232  continue;
233  }
234  return DTERR_BAD_FORMAT;
235  default:
236  /* not a valid date unit suffix */
237  return DTERR_BAD_FORMAT;
238  }
239  }
240  else
241  {
242  switch (unit) /* after T: H M S */
243  {
244  case 'H':
245  tm->tm_hour += val;
246  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
247  break;
248  case 'M':
249  tm->tm_min += val;
250  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
251  break;
252  case 'S':
253  tm->tm_sec += val;
254  AdjustFractSeconds(fval, tm, fsec, 1);
255  break;
256  case '\0': /* ISO 8601 4.4.3.3 Alternative Format */
257  if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
258  {
259  tm->tm_hour += val / 10000;
260  tm->tm_min += (val / 100) % 100;
261  tm->tm_sec += val % 100;
262  AdjustFractSeconds(fval, tm, fsec, 1);
263  return 0;
264  }
265  /* Else fall through to extended alternative format */
266  /* FALLTHROUGH */
267  case ':': /* ISO 8601 4.4.3.3 Alternative Format,
268  * Extended */
269  if (havefield)
270  return DTERR_BAD_FORMAT;
271 
272  tm->tm_hour += val;
273  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
274  if (unit == '\0')
275  return 0;
276 
277  dterr = ParseISO8601Number(str, &str, &val, &fval);
278  if (dterr)
279  return dterr;
280  tm->tm_min += val;
281  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
282  if (*str == '\0')
283  return 0;
284  if (*str != ':')
285  return DTERR_BAD_FORMAT;
286  str++;
287 
288  dterr = ParseISO8601Number(str, &str, &val, &fval);
289  if (dterr)
290  return dterr;
291  tm->tm_sec += val;
292  AdjustFractSeconds(fval, tm, fsec, 1);
293  if (*str == '\0')
294  return 0;
295  return DTERR_BAD_FORMAT;
296 
297  default:
298  /* not a valid time unit suffix */
299  return DTERR_BAD_FORMAT;
300  }
301  }
302 
303  havefield = true;
304  }
305 
306  return 0;
307 }
static void AdjustFractDays(double frac, struct tm *tm, fsec_t *fsec, int scale)
Definition: interval.c:41
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define DTK_DELTA
Definition: datetime.h:162
int tm_hour
Definition: pgtime.h:29
static int ISO8601IntegerWidth(const char *fieldstart)
Definition: interval.c:81
static struct pg_tm tm
Definition: localtime.c:106
static void ClearPgTm(struct tm *tm, fsec_t *fsec)
Definition: interval.c:94
#define SECS_PER_DAY
Definition: timestamp.h:86
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:88
#define SECS_PER_HOUR
Definition: timestamp.h:87
#define DAYS_PER_MONTH
Definition: timestamp.h:77
static void AdjustFractSeconds(double frac, struct tm *tm, fsec_t *fsec, int scale)
Definition: interval.c:23
int tm_year
Definition: pgtime.h:32
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
long val
Definition: informix.c:689
static int ParseISO8601Number(const char *str, char **endptr, int *ipart, double *fpart)
Definition: interval.c:56

◆ EncodeInterval()

void EncodeInterval ( struct tm tm,
fsec_t  fsec,
int  style,
char *  str 
)

Definition at line 763 of file interval.c.

References AddISO8601IntPart(), AddPostgresIntPart(), AddVerboseIntPart(), AppendSeconds(), INTSTYLE_ISO_8601, INTSTYLE_POSTGRES, INTSTYLE_POSTGRES_VERBOSE, INTSTYLE_SQL_STANDARD, MAX_INTERVAL_PRECISION, and generate_unaccent_rules::str.

Referenced by PGTYPESinterval_to_asc().

764 {
765  char *cp = str;
766  int year = tm->tm_year;
767  int mon = tm->tm_mon;
768  int mday = tm->tm_mday;
769  int hour = tm->tm_hour;
770  int min = tm->tm_min;
771  int sec = tm->tm_sec;
772  bool is_before = false;
773  bool is_zero = true;
774 
775  /*
776  * The sign of year and month are guaranteed to match, since they are
777  * stored internally as "month". But we'll need to check for is_before and
778  * is_zero when determining the signs of day and hour/minute/seconds
779  * fields.
780  */
781  switch (style)
782  {
783  /* SQL Standard interval format */
785  {
786  bool has_negative = year < 0 || mon < 0 ||
787  mday < 0 || hour < 0 ||
788  min < 0 || sec < 0 || fsec < 0;
789  bool has_positive = year > 0 || mon > 0 ||
790  mday > 0 || hour > 0 ||
791  min > 0 || sec > 0 || fsec > 0;
792  bool has_year_month = year != 0 || mon != 0;
793  bool has_day_time = mday != 0 || hour != 0 ||
794  min != 0 || sec != 0 || fsec != 0;
795  bool has_day = mday != 0;
796  bool sql_standard_value = !(has_negative && has_positive) &&
797  !(has_year_month && has_day_time);
798 
799  /*
800  * SQL Standard wants only 1 "<sign>" preceding the whole
801  * interval ... but can't do that if mixed signs.
802  */
803  if (has_negative && sql_standard_value)
804  {
805  *cp++ = '-';
806  year = -year;
807  mon = -mon;
808  mday = -mday;
809  hour = -hour;
810  min = -min;
811  sec = -sec;
812  fsec = -fsec;
813  }
814 
815  if (!has_negative && !has_positive)
816  {
817  sprintf(cp, "0");
818  }
819  else if (!sql_standard_value)
820  {
821  /*
822  * For non sql-standard interval values, force outputting
823  * the signs to avoid ambiguities with intervals with
824  * mixed sign components.
825  */
826  char year_sign = (year < 0 || mon < 0) ? '-' : '+';
827  char day_sign = (mday < 0) ? '-' : '+';
828  char sec_sign = (hour < 0 || min < 0 ||
829  sec < 0 || fsec < 0) ? '-' : '+';
830 
831  sprintf(cp, "%c%d-%d %c%d %c%d:%02d:",
832  year_sign, abs(year), abs(mon),
833  day_sign, abs(mday),
834  sec_sign, abs(hour), abs(min));
835  cp += strlen(cp);
836  AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
837  }
838  else if (has_year_month)
839  {
840  sprintf(cp, "%d-%d", year, mon);
841  }
842  else if (has_day)
843  {
844  sprintf(cp, "%d %d:%02d:", mday, hour, min);
845  cp += strlen(cp);
846  AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
847  }
848  else
849  {
850  sprintf(cp, "%d:%02d:", hour, min);
851  cp += strlen(cp);
852  AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
853  }
854  }
855  break;
856 
857  /* ISO 8601 "time-intervals by duration only" */
858  case INTSTYLE_ISO_8601:
859  /* special-case zero to avoid printing nothing */
860  if (year == 0 && mon == 0 && mday == 0 &&
861  hour == 0 && min == 0 && sec == 0 && fsec == 0)
862  {
863  sprintf(cp, "PT0S");
864  break;
865  }
866  *cp++ = 'P';
867  cp = AddISO8601IntPart(cp, year, 'Y');
868  cp = AddISO8601IntPart(cp, mon, 'M');
869  cp = AddISO8601IntPart(cp, mday, 'D');
870  if (hour != 0 || min != 0 || sec != 0 || fsec != 0)
871  *cp++ = 'T';
872  cp = AddISO8601IntPart(cp, hour, 'H');
873  cp = AddISO8601IntPart(cp, min, 'M');
874  if (sec != 0 || fsec != 0)
875  {
876  if (sec < 0 || fsec < 0)
877  *cp++ = '-';
878  AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
879  cp += strlen(cp);
880  *cp++ = 'S';
881  *cp = '\0';
882  }
883  break;
884 
885  /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
886  case INTSTYLE_POSTGRES:
887  cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before);
888  cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before);
889  cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before);
890  if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0)
891  {
892  bool minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
893 
894  sprintf(cp, "%s%s%02d:%02d:",
895  is_zero ? "" : " ",
896  (minus ? "-" : (is_before ? "+" : "")),
897  abs(hour), abs(min));
898  cp += strlen(cp);
899  AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
900  }
901  break;
902 
903  /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
905  default:
906  strcpy(cp, "@");
907  cp++;
908  cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
909  cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
910  cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
911  cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
912  cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
913  if (sec != 0 || fsec != 0)
914  {
915  *cp++ = ' ';
916  if (sec < 0 || (sec == 0 && fsec < 0))
917  {
918  if (is_zero)
919  is_before = true;
920  else if (!is_before)
921  *cp++ = '-';
922  }
923  else if (is_before)
924  *cp++ = '-';
925  AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
926  cp += strlen(cp);
927  sprintf(cp, " sec%s",
928  (abs(sec) != 1 || fsec != 0) ? "s" : "");
929  is_zero = false;
930  }
931  /* identically zero? then put in a unitless zero... */
932  if (is_zero)
933  strcat(cp, " 0");
934  if (is_before)
935  strcat(cp, " ago");
936  break;
937  }
938 }
#define INTSTYLE_POSTGRES_VERBOSE
Definition: miscadmin.h:233
static void AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: interval.c:737
int tm_hour
Definition: pgtime.h:29
static struct pg_tm tm
Definition: localtime.c:106
#define MAX_INTERVAL_PRECISION
Definition: timestamp.h:54
static char * AddISO8601IntPart(char *cp, int value, char units)
Definition: interval.c:727
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define INTSTYLE_ISO_8601
Definition: miscadmin.h:235
static char * AddPostgresIntPart(char *cp, int value, const char *units, bool *is_zero, bool *is_before)
Definition: interval.c:704
#define INTSTYLE_SQL_STANDARD
Definition: miscadmin.h:234
int tm_year
Definition: pgtime.h:32
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28
static char * AddVerboseIntPart(char *cp, int value, const char *units, bool *is_zero, bool *is_before)
Definition: interval.c:684
#define INTSTYLE_POSTGRES
Definition: miscadmin.h:232

◆ interval2tm()

static int interval2tm ( interval  span,
struct tm tm,
fsec_t fsec 
)
static

Definition at line 945 of file interval.c.

References interval::month, MONTHS_PER_YEAR, interval::time, USECS_PER_DAY, USECS_PER_HOUR, USECS_PER_MINUTE, and USECS_PER_SEC.

Referenced by PGTYPESinterval_to_asc().

946 {
947  int64 time;
948 
949  if (span.month != 0)
950  {
951  tm->tm_year = span.month / MONTHS_PER_YEAR;
952  tm->tm_mon = span.month % MONTHS_PER_YEAR;
953 
954  }
955  else
956  {
957  tm->tm_year = 0;
958  tm->tm_mon = 0;
959  }
960 
961  time = span.time;
962 
963  tm->tm_mday = time / USECS_PER_DAY;
964  time -= tm->tm_mday * USECS_PER_DAY;
965  tm->tm_hour = time / USECS_PER_HOUR;
966  time -= tm->tm_hour * USECS_PER_HOUR;
967  tm->tm_min = time / USECS_PER_MINUTE;
968  time -= tm->tm_min * USECS_PER_MINUTE;
969  tm->tm_sec = time / USECS_PER_SEC;
970  *fsec = time - (tm->tm_sec * USECS_PER_SEC);
971 
972  return 0;
973 } /* interval2tm() */
#define USECS_PER_SEC
Definition: timestamp.h:94
int tm_hour
Definition: pgtime.h:29
#define USECS_PER_MINUTE
Definition: timestamp.h:93
static struct pg_tm tm
Definition: localtime.c:106
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define USECS_PER_HOUR
Definition: timestamp.h:92
#define USECS_PER_DAY
Definition: timestamp.h:91
int tm_year
Definition: pgtime.h:32
int tm_sec
Definition: pgtime.h:27
int tm_min
Definition: pgtime.h:28

◆ ISO8601IntegerWidth()

static int ISO8601IntegerWidth ( const char *  fieldstart)
static

Definition at line 81 of file interval.c.

Referenced by DecodeISO8601Interval().

82 {
83  /* We might have had a leading '-' */
84  if (*fieldstart == '-')
85  fieldstart++;
86  return strspn(fieldstart, "0123456789");
87 }

◆ ParseISO8601Number()

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

Definition at line 56 of file interval.c.

References DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, and val.

Referenced by DecodeISO8601Interval().

57 {
58  double val;
59 
60  if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
61  return DTERR_BAD_FORMAT;
62  errno = 0;
63  val = strtod(str, endptr);
64  /* did we not see anything that looks like a double? */
65  if (*endptr == str || errno != 0)
66  return DTERR_BAD_FORMAT;
67  /* watch out for overflow */
68  if (val < INT_MIN || val > INT_MAX)
69  return DTERR_FIELD_OVERFLOW;
70  /* be very sure we truncate towards zero (cf dtrunc()) */
71  if (val >= 0)
72  *ipart = (int) floor(val);
73  else
74  *ipart = (int) -floor(-val);
75  *fpart = val - *ipart;
76  return 0;
77 }
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
long val
Definition: informix.c:689

◆ PGTYPESinterval_copy()

int PGTYPESinterval_copy ( interval intvlsrc,
interval intvldest 
)

Definition at line 1086 of file interval.c.

References interval::month, and interval::time.

Referenced by ecpg_get_data(), and main().

1087 {
1088  intvldest->time = intvlsrc->time;
1089  intvldest->month = intvlsrc->month;
1090 
1091  return 0;
1092 }

◆ PGTYPESinterval_free()

void PGTYPESinterval_free ( interval intvl)

Definition at line 1001 of file interval.c.

References free.

Referenced by main().

1002 {
1003  free(intvl);
1004 }
#define free(a)
Definition: header.h:65

◆ PGTYPESinterval_from_asc()

interval* PGTYPESinterval_from_asc ( char *  str,
char **  endptr 
)

Definition at line 1007 of file interval.c.

References DecodeInterval(), DecodeISO8601Interval(), DTK_DELTA, free, MAXDATEFIELDS, MAXDATELEN, ParseDateTime(), pgtypes_alloc(), PGTYPES_INTVL_BAD_INTERVAL, tm, tm2interval(), and pg_tm::tm_year.

Referenced by ecpg_get_data(), and main().

1008 {
1009  interval *result = NULL;
1010  fsec_t fsec;
1011  struct tm tt,
1012  *tm = &tt;
1013  int dtype;
1014  int nf;
1015  char *field[MAXDATEFIELDS];
1016  int ftype[MAXDATEFIELDS];
1017  char lowstr[MAXDATELEN + MAXDATEFIELDS];
1018  char *realptr;
1019  char **ptr = (endptr != NULL) ? endptr : &realptr;
1020 
1021  tm->tm_year = 0;
1022  tm->tm_mon = 0;
1023  tm->tm_mday = 0;
1024  tm->tm_hour = 0;
1025  tm->tm_min = 0;
1026  tm->tm_sec = 0;
1027  fsec = 0;
1028 
1029  if (strlen(str) > MAXDATELEN)
1030  {
1032  return NULL;
1033  }
1034 
1035  if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
1036  (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0 &&
1037  DecodeISO8601Interval(str, &dtype, tm, &fsec) != 0))
1038  {
1040  return NULL;
1041  }
1042 
1043  result = (interval *) pgtypes_alloc(sizeof(interval));
1044  if (!result)
1045  return NULL;
1046 
1047  if (dtype != DTK_DELTA)
1048  {
1050  free(result);
1051  return NULL;
1052  }
1053 
1054  if (tm2interval(tm, fsec, result) != 0)
1055  {
1057  free(result);
1058  return NULL;
1059  }
1060 
1061  errno = 0;
1062  return result;
1063 }
#define MAXDATELEN
Definition: datetime.h:203
int DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm *tm, fsec_t *fsec)
Definition: interval.c:326
static int DecodeISO8601Interval(char *str, int *dtype, struct tm *tm, fsec_t *fsec)
Definition: interval.c:112
static int tm2interval(struct tm *tm, fsec_t fsec, interval *span)
Definition: interval.c:976
#define DTK_DELTA
Definition: datetime.h:162
static struct pg_tm tm
Definition: localtime.c:106
char * pgtypes_alloc(long size)
Definition: common.c:10
int32 fsec_t
Definition: timestamp.h:41
#define free(a)
Definition: header.h:65
#define MAXDATEFIELDS
Definition: datetime.h:205
#define PGTYPES_INTVL_BAD_INTERVAL
Definition: pgtypes_error.h:18
int tm_year
Definition: pgtime.h:32
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:546

◆ PGTYPESinterval_new()

interval* PGTYPESinterval_new ( void  )

Definition at line 991 of file interval.c.

References pgtypes_alloc().

Referenced by main().

992 {
993  interval *result;
994 
995  result = (interval *) pgtypes_alloc(sizeof(interval));
996  /* result can be NULL if we run out of memory */
997  return result;
998 }
char * pgtypes_alloc(long size)
Definition: common.c:10

◆ PGTYPESinterval_to_asc()

char* PGTYPESinterval_to_asc ( interval span)

Definition at line 1066 of file interval.c.

References buf, EncodeInterval(), interval2tm(), IntervalStyle, INTSTYLE_POSTGRES_VERBOSE, MAXDATELEN, PGTYPES_INTVL_BAD_INTERVAL, pgtypes_strdup(), and tm.

Referenced by ecpg_store_input(), intoasc(), and main().

1067 {
1068  struct tm tt,
1069  *tm = &tt;
1070  fsec_t fsec;
1071  char buf[MAXDATELEN + 1];
1073 
1074  if (interval2tm(*span, tm, &fsec) != 0)
1075  {
1077  return NULL;
1078  }
1079 
1080  EncodeInterval(tm, fsec, IntervalStyle, buf);
1081 
1082  return pgtypes_strdup(buf);
1083 }
#define MAXDATELEN
Definition: datetime.h:203
#define INTSTYLE_POSTGRES_VERBOSE
Definition: miscadmin.h:233
int IntervalStyle
Definition: globals.c:116
void EncodeInterval(struct tm *tm, fsec_t fsec, int style, char *str)
Definition: interval.c:763
static struct pg_tm tm
Definition: localtime.c:106
char * pgtypes_strdup(const char *str)
Definition: common.c:20
static char * buf
Definition: pg_test_fsync.c:67
int32 fsec_t
Definition: timestamp.h:41
static int interval2tm(interval span, struct tm *tm, fsec_t *fsec)
Definition: interval.c:945
#define PGTYPES_INTVL_BAD_INTERVAL
Definition: pgtypes_error.h:18

◆ tm2interval()

static int tm2interval ( struct tm tm,
fsec_t  fsec,
interval span 
)
static

Definition at line 976 of file interval.c.

References interval::month, MONTHS_PER_YEAR, interval::time, and USECS_PER_SEC.

Referenced by PGTYPESinterval_from_asc().

977 {
978  if ((double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon > INT_MAX ||
979  (double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon < INT_MIN)
980  return -1;
981  span->month = tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
982  span->time = (((((((tm->tm_mday * INT64CONST(24)) +
983  tm->tm_hour) * INT64CONST(60)) +
984  tm->tm_min) * INT64CONST(60)) +
985  tm->tm_sec) * USECS_PER_SEC) + fsec;
986 
987  return 0;
988 } /* tm2interval() */
#define USECS_PER_SEC
Definition: timestamp.h:94
int tm_hour
Definition: pgtime.h:29
static struct pg_tm tm
Definition: localtime.c:106
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
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