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 725 of file interval.c.

Referenced by EncodeInterval().

726 {
727  if (value == 0)
728  return cp;
729  sprintf(cp, "%d%c", value, units);
730  return cp + strlen(cp);
731 }
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 702 of file interval.c.

Referenced by EncodeInterval().

704 {
705  if (value == 0)
706  return cp;
707  sprintf(cp, "%s%s%d %s%s",
708  (!*is_zero) ? " " : "",
709  (*is_before && value > 0) ? "+" : "",
710  value,
711  units,
712  (value != 1) ? "s" : "");
713 
714  /*
715  * Each nonzero field sets is_before for (only) the next one. This is a
716  * tad bizarre but it's how it worked before...
717  */
718  *is_before = (value < 0);
719  *is_zero = false;
720  return cp + strlen(cp);
721 }
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 682 of file interval.c.

References value.

Referenced by EncodeInterval().

684 {
685  if (value == 0)
686  return cp;
687  /* first nonzero value sets is_before */
688  if (*is_zero)
689  {
690  *is_before = (value < 0);
691  value = abs(value);
692  }
693  else if (*is_before)
694  value = -value;
695  sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
696  *is_zero = false;
697  return cp + strlen(cp);
698 }
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:120
static struct pg_tm tm
Definition: localtime.c:107
#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:120
static struct pg_tm tm
Definition: localtime.c:107
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 735 of file interval.c.

References Abs, and TrimTrailingZeros().

Referenced by EncodeInterval().

736 {
737  if (fsec == 0)
738  {
739  if (fillzeros)
740  sprintf(cp, "%02d", abs(sec));
741  else
742  sprintf(cp, "%d", abs(sec));
743  }
744  else
745  {
746  if (fillzeros)
747  sprintf(cp, "%02d.%0*d", abs(sec), precision, (int) Abs(fsec));
748  else
749  sprintf(cp, "%d.%0*d", abs(sec), precision, (int) Abs(fsec));
750  TrimTrailingZeros(cp);
751  }
752 }
#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:107
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 324 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().

326 {
329  bool is_before = false;
330  char *cp;
331  int fmask = 0,
332  tmask,
333  type;
334  int i;
335  int dterr;
336  int val;
337  double fval;
338 
339  *dtype = DTK_DELTA;
340  type = IGNORE_DTF;
341  ClearPgTm(tm, fsec);
342 
343  /* read through list backwards to pick up units before values */
344  for (i = nf - 1; i >= 0; i--)
345  {
346  switch (ftype[i])
347  {
348  case DTK_TIME:
349  dterr = DecodeTime(field[i], /* range, */
350  &tmask, tm, fsec);
351  if (dterr)
352  return dterr;
353  type = DTK_DAY;
354  break;
355 
356  case DTK_TZ:
357 
358  /*
359  * Timezone is a token with a leading sign character and at
360  * least one digit; there could be ':', '.', '-' embedded in
361  * it as well.
362  */
363  Assert(*field[i] == '-' || *field[i] == '+');
364 
365  /*
366  * Try for hh:mm or hh:mm:ss. If not, fall through to
367  * DTK_NUMBER case, which can handle signed float numbers and
368  * signed year-month values.
369  */
370  if (strchr(field[i] + 1, ':') != NULL &&
371  DecodeTime(field[i] + 1, /* INTERVAL_FULL_RANGE, */
372  &tmask, tm, fsec) == 0)
373  {
374  if (*field[i] == '-')
375  {
376  /* flip the sign on all fields */
377  tm->tm_hour = -tm->tm_hour;
378  tm->tm_min = -tm->tm_min;
379  tm->tm_sec = -tm->tm_sec;
380  *fsec = -(*fsec);
381  }
382 
383  /*
384  * Set the next type to be a day, if units are not
385  * specified. This handles the case of '1 +02:03' since we
386  * are reading right to left.
387  */
388  type = DTK_DAY;
389  tmask = DTK_M(TZ);
390  break;
391  }
392  /* FALL THROUGH */
393 
394  case DTK_DATE:
395  case DTK_NUMBER:
396  if (type == IGNORE_DTF)
397  {
398  /* use typmod to decide what rightmost field is */
399  switch (range)
400  {
401  case INTERVAL_MASK(YEAR):
402  type = DTK_YEAR;
403  break;
404  case INTERVAL_MASK(MONTH):
406  type = DTK_MONTH;
407  break;
408  case INTERVAL_MASK(DAY):
409  type = DTK_DAY;
410  break;
411  case INTERVAL_MASK(HOUR):
415  type = DTK_HOUR;
416  break;
417  case INTERVAL_MASK(MINUTE):
419  type = DTK_MINUTE;
420  break;
421  case INTERVAL_MASK(SECOND):
424  type = DTK_SECOND;
425  break;
426  default:
427  type = DTK_SECOND;
428  break;
429  }
430  }
431 
432  errno = 0;
433  val = strtoint(field[i], &cp, 10);
434  if (errno == ERANGE)
435  return DTERR_FIELD_OVERFLOW;
436 
437  if (*cp == '-')
438  {
439  /* SQL "years-months" syntax */
440  int val2;
441 
442  val2 = strtoint(cp + 1, &cp, 10);
443  if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
444  return DTERR_FIELD_OVERFLOW;
445  if (*cp != '\0')
446  return DTERR_BAD_FORMAT;
447  type = DTK_MONTH;
448  if (*field[i] == '-')
449  val2 = -val2;
450  val = val * MONTHS_PER_YEAR + val2;
451  fval = 0;
452  }
453  else if (*cp == '.')
454  {
455  errno = 0;
456  fval = strtod(cp, &cp);
457  if (*cp != '\0' || errno != 0)
458  return DTERR_BAD_FORMAT;
459 
460  if (*field[i] == '-')
461  fval = -fval;
462  }
463  else if (*cp == '\0')
464  fval = 0;
465  else
466  return DTERR_BAD_FORMAT;
467 
468  tmask = 0; /* DTK_M(type); */
469 
470  switch (type)
471  {
472  case DTK_MICROSEC:
473  *fsec += rint(val + fval);
474  tmask = DTK_M(MICROSECOND);
475  break;
476 
477  case DTK_MILLISEC:
478  *fsec += rint((val + fval) * 1000);
479  tmask = DTK_M(MILLISECOND);
480  break;
481 
482  case DTK_SECOND:
483  tm->tm_sec += val;
484  *fsec += rint(fval * 1000000);
485 
486  /*
487  * If any subseconds were specified, consider this
488  * microsecond and millisecond input as well.
489  */
490  if (fval == 0)
491  tmask = DTK_M(SECOND);
492  else
493  tmask = DTK_ALL_SECS_M;
494  break;
495 
496  case DTK_MINUTE:
497  tm->tm_min += val;
498  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
499  tmask = DTK_M(MINUTE);
500  break;
501 
502  case DTK_HOUR:
503  tm->tm_hour += val;
504  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
505  tmask = DTK_M(HOUR);
506  type = DTK_DAY;
507  break;
508 
509  case DTK_DAY:
510  tm->tm_mday += val;
511  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
512  tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
513  break;
514 
515  case DTK_WEEK:
516  tm->tm_mday += val * 7;
517  AdjustFractDays(fval, tm, fsec, 7);
518  tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
519  break;
520 
521  case DTK_MONTH:
522  tm->tm_mon += val;
523  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
524  tmask = DTK_M(MONTH);
525  break;
526 
527  case DTK_YEAR:
528  tm->tm_year += val;
529  if (fval != 0)
530  tm->tm_mon += fval * MONTHS_PER_YEAR;
531  tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
532  break;
533 
534  case DTK_DECADE:
535  tm->tm_year += val * 10;
536  if (fval != 0)
537  tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
538  tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
539  break;
540 
541  case DTK_CENTURY:
542  tm->tm_year += val * 100;
543  if (fval != 0)
544  tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
545  tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
546  break;
547 
548  case DTK_MILLENNIUM:
549  tm->tm_year += val * 1000;
550  if (fval != 0)
551  tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
552  tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
553  break;
554 
555  default:
556  return DTERR_BAD_FORMAT;
557  }
558  break;
559 
560  case DTK_STRING:
561  case DTK_SPECIAL:
562  type = DecodeUnits(i, field[i], &val);
563  if (type == IGNORE_DTF)
564  continue;
565 
566  tmask = 0; /* DTK_M(type); */
567  switch (type)
568  {
569  case UNITS:
570  type = val;
571  break;
572 
573  case AGO:
574  is_before = true;
575  type = val;
576  break;
577 
578  case RESERV:
579  tmask = (DTK_DATE_M | DTK_TIME_M);
580  *dtype = val;
581  break;
582 
583  default:
584  return DTERR_BAD_FORMAT;
585  }
586  break;
587 
588  default:
589  return DTERR_BAD_FORMAT;
590  }
591 
592  if (tmask & fmask)
593  return DTERR_BAD_FORMAT;
594  fmask |= tmask;
595  }
596 
597  /* ensure that at least one time field has been found */
598  if (fmask == 0)
599  return DTERR_BAD_FORMAT;
600 
601  /* ensure fractional seconds are fractional */
602  if (*fsec != 0)
603  {
604  int sec;
605 
606  sec = *fsec / USECS_PER_SEC;
607  *fsec -= sec * USECS_PER_SEC;
608  tm->tm_sec += sec;
609  }
610 
611  /*----------
612  * The SQL standard defines the interval literal
613  * '-1 1:00:00'
614  * to mean "negative 1 days and negative 1 hours", while Postgres
615  * traditionally treats this as meaning "negative 1 days and positive
616  * 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign
617  * to all fields if there are no other explicit signs.
618  *
619  * We leave the signs alone if there are additional explicit signs.
620  * This protects us against misinterpreting postgres-style dump output,
621  * since the postgres-style output code has always put an explicit sign on
622  * all fields following a negative field. But note that SQL-spec output
623  * is ambiguous and can be misinterpreted on load! (So it's best practice
624  * to dump in postgres style, not SQL style.)
625  *----------
626  */
627  if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
628  {
629  /* Check for additional explicit signs */
630  bool more_signs = false;
631 
632  for (i = 1; i < nf; i++)
633  {
634  if (*field[i] == '-' || *field[i] == '+')
635  {
636  more_signs = true;
637  break;
638  }
639  }
640 
641  if (!more_signs)
642  {
643  /*
644  * Rather than re-determining which field was field[0], just force
645  * 'em all negative.
646  */
647  if (*fsec > 0)
648  *fsec = -(*fsec);
649  if (tm->tm_sec > 0)
650  tm->tm_sec = -tm->tm_sec;
651  if (tm->tm_min > 0)
652  tm->tm_min = -tm->tm_min;
653  if (tm->tm_hour > 0)
654  tm->tm_hour = -tm->tm_hour;
655  if (tm->tm_mday > 0)
656  tm->tm_mday = -tm->tm_mday;
657  if (tm->tm_mon > 0)
658  tm->tm_mon = -tm->tm_mon;
659  if (tm->tm_year > 0)
660  tm->tm_year = -tm->tm_year;
661  }
662  }
663 
664  /* finally, AGO negates everything */
665  if (is_before)
666  {
667  *fsec = -(*fsec);
668  tm->tm_sec = -tm->tm_sec;
669  tm->tm_min = -tm->tm_min;
670  tm->tm_hour = -tm->tm_hour;
671  tm->tm_mday = -tm->tm_mday;
672  tm->tm_mon = -tm->tm_mon;
673  tm->tm_year = -tm->tm_year;
674  }
675 
676  return 0;
677 }
#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:118
#define TZ
Definition: datetime.h:96
#define SECOND
Definition: datetime.h:103
int DecodeUnits(int field, char *lowtoken, int *val)
Definition: datetime.c:3712
#define INTERVAL_FULL_RANGE
Definition: timestamp.h:48
#define DTK_DATE_M
Definition: datetime.h:194
static struct pg_tm tm
Definition: localtime.c:107
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:2542
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  case '-': /* ISO 8601 4.4.3.3 Alternative Format,
188  * Extended */
189  if (havefield)
190  return DTERR_BAD_FORMAT;
191 
192  tm->tm_year += val;
193  tm->tm_mon += (fval * 12);
194  if (unit == '\0')
195  return 0;
196  if (unit == 'T')
197  {
198  datepart = false;
199  havefield = false;
200  continue;
201  }
202 
203  dterr = ParseISO8601Number(str, &str, &val, &fval);
204  if (dterr)
205  return dterr;
206  tm->tm_mon += val;
207  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
208  if (*str == '\0')
209  return 0;
210  if (*str == 'T')
211  {
212  datepart = false;
213  havefield = false;
214  continue;
215  }
216  if (*str != '-')
217  return DTERR_BAD_FORMAT;
218  str++;
219 
220  dterr = ParseISO8601Number(str, &str, &val, &fval);
221  if (dterr)
222  return dterr;
223  tm->tm_mday += val;
224  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
225  if (*str == '\0')
226  return 0;
227  if (*str == 'T')
228  {
229  datepart = false;
230  havefield = false;
231  continue;
232  }
233  return DTERR_BAD_FORMAT;
234  default:
235  /* not a valid date unit suffix */
236  return DTERR_BAD_FORMAT;
237  }
238  }
239  else
240  {
241  switch (unit) /* after T: H M S */
242  {
243  case 'H':
244  tm->tm_hour += val;
245  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
246  break;
247  case 'M':
248  tm->tm_min += val;
249  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
250  break;
251  case 'S':
252  tm->tm_sec += val;
253  AdjustFractSeconds(fval, tm, fsec, 1);
254  break;
255  case '\0': /* ISO 8601 4.4.3.3 Alternative Format */
256  if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
257  {
258  tm->tm_hour += val / 10000;
259  tm->tm_min += (val / 100) % 100;
260  tm->tm_sec += val % 100;
261  AdjustFractSeconds(fval, tm, fsec, 1);
262  return 0;
263  }
264  /* Else fall through to extended alternative format */
265  case ':': /* ISO 8601 4.4.3.3 Alternative Format,
266  * Extended */
267  if (havefield)
268  return DTERR_BAD_FORMAT;
269 
270  tm->tm_hour += val;
271  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
272  if (unit == '\0')
273  return 0;
274 
275  dterr = ParseISO8601Number(str, &str, &val, &fval);
276  if (dterr)
277  return dterr;
278  tm->tm_min += val;
279  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
280  if (*str == '\0')
281  return 0;
282  if (*str != ':')
283  return DTERR_BAD_FORMAT;
284  str++;
285 
286  dterr = ParseISO8601Number(str, &str, &val, &fval);
287  if (dterr)
288  return dterr;
289  tm->tm_sec += val;
290  AdjustFractSeconds(fval, tm, fsec, 1);
291  if (*str == '\0')
292  return 0;
293  return DTERR_BAD_FORMAT;
294 
295  default:
296  /* not a valid time unit suffix */
297  return DTERR_BAD_FORMAT;
298  }
299  }
300 
301  havefield = true;
302  }
303 
304  return 0;
305 }
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:107
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 761 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().

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

◆ interval2tm()

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

Definition at line 943 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().

944 {
945  int64 time;
946 
947  if (span.month != 0)
948  {
949  tm->tm_year = span.month / MONTHS_PER_YEAR;
950  tm->tm_mon = span.month % MONTHS_PER_YEAR;
951 
952  }
953  else
954  {
955  tm->tm_year = 0;
956  tm->tm_mon = 0;
957  }
958 
959  time = span.time;
960 
961  tm->tm_mday = time / USECS_PER_DAY;
962  time -= tm->tm_mday * USECS_PER_DAY;
963  tm->tm_hour = time / USECS_PER_HOUR;
964  time -= tm->tm_hour * USECS_PER_HOUR;
965  tm->tm_min = time / USECS_PER_MINUTE;
966  time -= tm->tm_min * USECS_PER_MINUTE;
967  tm->tm_sec = time / USECS_PER_SEC;
968  *fsec = time - (tm->tm_sec * USECS_PER_SEC);
969 
970  return 0;
971 } /* 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:107
#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 1084 of file interval.c.

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

Referenced by ecpg_get_data(), and main().

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

◆ PGTYPESinterval_free()

void PGTYPESinterval_free ( interval intvl)

Definition at line 999 of file interval.c.

References free.

Referenced by main().

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

◆ PGTYPESinterval_from_asc()

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

Definition at line 1005 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().

1006 {
1007  interval *result = NULL;
1008  fsec_t fsec;
1009  struct tm tt,
1010  *tm = &tt;
1011  int dtype;
1012  int nf;
1013  char *field[MAXDATEFIELDS];
1014  int ftype[MAXDATEFIELDS];
1015  char lowstr[MAXDATELEN + MAXDATEFIELDS];
1016  char *realptr;
1017  char **ptr = (endptr != NULL) ? endptr : &realptr;
1018 
1019  tm->tm_year = 0;
1020  tm->tm_mon = 0;
1021  tm->tm_mday = 0;
1022  tm->tm_hour = 0;
1023  tm->tm_min = 0;
1024  tm->tm_sec = 0;
1025  fsec = 0;
1026 
1027  if (strlen(str) > MAXDATELEN)
1028  {
1030  return NULL;
1031  }
1032 
1033  if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
1034  (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0 &&
1035  DecodeISO8601Interval(str, &dtype, tm, &fsec) != 0))
1036  {
1038  return NULL;
1039  }
1040 
1041  result = (interval *) pgtypes_alloc(sizeof(interval));
1042  if (!result)
1043  return NULL;
1044 
1045  if (dtype != DTK_DELTA)
1046  {
1048  free(result);
1049  return NULL;
1050  }
1051 
1052  if (tm2interval(tm, fsec, result) != 0)
1053  {
1055  free(result);
1056  return NULL;
1057  }
1058 
1059  errno = 0;
1060  return result;
1061 }
#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:324
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:974
#define DTK_DELTA
Definition: datetime.h:162
static struct pg_tm tm
Definition: localtime.c:107
char * pgtypes_alloc(long size)
Definition: common.c:9
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 989 of file interval.c.

References pgtypes_alloc().

Referenced by main().

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

◆ PGTYPESinterval_to_asc()

char* PGTYPESinterval_to_asc ( interval span)

Definition at line 1064 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().

1065 {
1066  struct tm tt,
1067  *tm = &tt;
1068  fsec_t fsec;
1069  char buf[MAXDATELEN + 1];
1071 
1072  if (interval2tm(*span, tm, &fsec) != 0)
1073  {
1075  return NULL;
1076  }
1077 
1078  EncodeInterval(tm, fsec, IntervalStyle, buf);
1079 
1080  return pgtypes_strdup(buf);
1081 }
#define MAXDATELEN
Definition: datetime.h:203
#define INTSTYLE_POSTGRES_VERBOSE
Definition: miscadmin.h:233
int IntervalStyle
Definition: globals.c:118
void EncodeInterval(struct tm *tm, fsec_t fsec, int style, char *str)
Definition: interval.c:761
static struct pg_tm tm
Definition: localtime.c:107
char * pgtypes_strdup(const char *str)
Definition: common.c:19
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:943
#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 974 of file interval.c.

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

Referenced by PGTYPESinterval_from_asc().

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