PostgreSQL Source Code  git master
interval.c File Reference
#include "postgres_fe.h"
#include <time.h>
#include <math.h>
#include <limits.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 int strtoint (const char *nptr, char **endptr, int base)
 
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 737 of file interval.c.

Referenced by EncodeInterval().

738 {
739  if (value == 0)
740  return cp;
741  sprintf(cp, "%d%c", value, units);
742  return cp + strlen(cp);
743 }
static struct @121 value

◆ AddPostgresIntPart()

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

Definition at line 714 of file interval.c.

Referenced by EncodeInterval().

716 {
717  if (value == 0)
718  return cp;
719  sprintf(cp, "%s%s%d %s%s",
720  (!*is_zero) ? " " : "",
721  (*is_before && value > 0) ? "+" : "",
722  value,
723  units,
724  (value != 1) ? "s" : "");
725 
726  /*
727  * Each nonzero field sets is_before for (only) the next one. This is a
728  * tad bizarre but it's how it worked before...
729  */
730  *is_before = (value < 0);
731  *is_zero = false;
732  return cp + strlen(cp);
733 }
static struct @121 value

◆ AddVerboseIntPart()

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

Definition at line 694 of file interval.c.

References value.

Referenced by EncodeInterval().

696 {
697  if (value == 0)
698  return cp;
699  /* first nonzero value sets is_before */
700  if (*is_zero)
701  {
702  *is_before = (value < 0);
703  value = abs(value);
704  }
705  else if (*is_before)
706  value = -value;
707  sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
708  *is_zero = false;
709  return cp + strlen(cp);
710 }
static struct @121 value

◆ AdjustFractDays()

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

Definition at line 53 of file interval.c.

References AdjustFractSeconds(), scale, and SECS_PER_DAY.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

54 {
55  int extra_days;
56 
57  if (frac == 0)
58  return;
59  frac *= scale;
60  extra_days = (int) frac;
61  tm->tm_mday += extra_days;
62  frac -= extra_days;
63  AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
64 }
int scale
Definition: pgbench.c:108
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:35

◆ AdjustFractSeconds()

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

Definition at line 35 of file interval.c.

References rint(), and scale.

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

36 {
37  int sec;
38 
39  if (frac == 0)
40  return;
41  frac *= scale;
42  sec = (int) frac;
43  tm->tm_sec += sec;
44  frac -= sec;
45  *fsec += rint(frac * 1000000);
46 }
int scale
Definition: pgbench.c:108
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 747 of file interval.c.

References Abs, and TrimTrailingZeros().

Referenced by EncodeInterval().

748 {
749  if (fsec == 0)
750  {
751  if (fillzeros)
752  sprintf(cp, "%02d", abs(sec));
753  else
754  sprintf(cp, "%d", abs(sec));
755  }
756  else
757  {
758  if (fillzeros)
759  sprintf(cp, "%02d.%0*d", abs(sec), precision, (int) Abs(fsec));
760  else
761  sprintf(cp, "%d.%0*d", abs(sec), precision, (int) Abs(fsec));
762  TrimTrailingZeros(cp);
763  }
764 }
#define Abs(x)
Definition: c.h:808
void TrimTrailingZeros(char *)
Definition: dt_common.c:728

◆ ClearPgTm()

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

Definition at line 106 of file interval.c.

Referenced by DecodeInterval(), and DecodeISO8601Interval().

107 {
108  tm->tm_year = 0;
109  tm->tm_mon = 0;
110  tm->tm_mday = 0;
111  tm->tm_hour = 0;
112  tm->tm_min = 0;
113  tm->tm_sec = 0;
114  *fsec = 0;
115 }
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 336 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().

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

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

◆ EncodeInterval()

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

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

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

◆ interval2tm()

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

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

956 {
957  int64 time;
958 
959  if (span.month != 0)
960  {
961  tm->tm_year = span.month / MONTHS_PER_YEAR;
962  tm->tm_mon = span.month % MONTHS_PER_YEAR;
963 
964  }
965  else
966  {
967  tm->tm_year = 0;
968  tm->tm_mon = 0;
969  }
970 
971  time = span.time;
972 
973  tm->tm_mday = time / USECS_PER_DAY;
974  time -= tm->tm_mday * USECS_PER_DAY;
975  tm->tm_hour = time / USECS_PER_HOUR;
976  time -= tm->tm_hour * USECS_PER_HOUR;
977  tm->tm_min = time / USECS_PER_MINUTE;
978  time -= tm->tm_min * USECS_PER_MINUTE;
979  tm->tm_sec = time / USECS_PER_SEC;
980  *fsec = time - (tm->tm_sec * USECS_PER_SEC);
981 
982  return 0;
983 } /* 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 93 of file interval.c.

Referenced by DecodeISO8601Interval().

94 {
95  /* We might have had a leading '-' */
96  if (*fieldstart == '-')
97  fieldstart++;
98  return strspn(fieldstart, "0123456789");
99 }

◆ ParseISO8601Number()

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

Definition at line 68 of file interval.c.

References DTERR_BAD_FORMAT, DTERR_FIELD_OVERFLOW, and val.

Referenced by DecodeISO8601Interval().

69 {
70  double val;
71 
72  if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
73  return DTERR_BAD_FORMAT;
74  errno = 0;
75  val = strtod(str, endptr);
76  /* did we not see anything that looks like a double? */
77  if (*endptr == str || errno != 0)
78  return DTERR_BAD_FORMAT;
79  /* watch out for overflow */
80  if (val < INT_MIN || val > INT_MAX)
81  return DTERR_FIELD_OVERFLOW;
82  /* be very sure we truncate towards zero (cf dtrunc()) */
83  if (val >= 0)
84  *ipart = (int) floor(val);
85  else
86  *ipart = (int) -floor(-val);
87  *fpart = val - *ipart;
88  return 0;
89 }
#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 1096 of file interval.c.

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

Referenced by ecpg_get_data(), and main().

1097 {
1098  intvldest->time = intvlsrc->time;
1099  intvldest->month = intvlsrc->month;
1100 
1101  return 0;
1102 }

◆ PGTYPESinterval_free()

void PGTYPESinterval_free ( interval intvl)

Definition at line 1011 of file interval.c.

References free.

Referenced by main().

1012 {
1013  free(intvl);
1014 }
#define free(a)
Definition: header.h:65

◆ PGTYPESinterval_from_asc()

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

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

1018 {
1019  interval *result = NULL;
1020  fsec_t fsec;
1021  struct tm tt,
1022  *tm = &tt;
1023  int dtype;
1024  int nf;
1025  char *field[MAXDATEFIELDS];
1026  int ftype[MAXDATEFIELDS];
1027  char lowstr[MAXDATELEN + MAXDATEFIELDS];
1028  char *realptr;
1029  char **ptr = (endptr != NULL) ? endptr : &realptr;
1030 
1031  tm->tm_year = 0;
1032  tm->tm_mon = 0;
1033  tm->tm_mday = 0;
1034  tm->tm_hour = 0;
1035  tm->tm_min = 0;
1036  tm->tm_sec = 0;
1037  fsec = 0;
1038 
1039  if (strlen(str) > MAXDATELEN)
1040  {
1042  return NULL;
1043  }
1044 
1045  if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
1046  (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0 &&
1047  DecodeISO8601Interval(str, &dtype, tm, &fsec) != 0))
1048  {
1050  return NULL;
1051  }
1052 
1053  result = (interval *) pgtypes_alloc(sizeof(interval));
1054  if (!result)
1055  return NULL;
1056 
1057  if (dtype != DTK_DELTA)
1058  {
1060  free(result);
1061  return NULL;
1062  }
1063 
1064  if (tm2interval(tm, fsec, result) != 0)
1065  {
1067  free(result);
1068  return NULL;
1069  }
1070 
1071  errno = 0;
1072  return result;
1073 }
#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:336
static int DecodeISO8601Interval(char *str, int *dtype, struct tm *tm, fsec_t *fsec)
Definition: interval.c:124
static int tm2interval(struct tm *tm, fsec_t fsec, interval *span)
Definition: interval.c:986
#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:562

◆ PGTYPESinterval_new()

interval* PGTYPESinterval_new ( void  )

Definition at line 1001 of file interval.c.

References pgtypes_alloc().

Referenced by main().

1002 {
1003  interval *result;
1004 
1005  result = (interval *) pgtypes_alloc(sizeof(interval));
1006  /* result can be NULL if we run out of memory */
1007  return result;
1008 }
char * pgtypes_alloc(long size)
Definition: common.c:9

◆ PGTYPESinterval_to_asc()

char* PGTYPESinterval_to_asc ( interval span)

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

1077 {
1078  struct tm tt,
1079  *tm = &tt;
1080  fsec_t fsec;
1081  char buf[MAXDATELEN + 1];
1083 
1084  if (interval2tm(*span, tm, &fsec) != 0)
1085  {
1087  return NULL;
1088  }
1089 
1090  EncodeInterval(tm, fsec, IntervalStyle, buf);
1091 
1092  return pgtypes_strdup(buf);
1093 }
#define MAXDATELEN
Definition: datetime.h:203
#define INTSTYLE_POSTGRES_VERBOSE
Definition: miscadmin.h:232
int IntervalStyle
Definition: globals.c:109
void EncodeInterval(struct tm *tm, fsec_t fsec, int style, char *str)
Definition: interval.c:773
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:955
#define PGTYPES_INTVL_BAD_INTERVAL
Definition: pgtypes_error.h:18

◆ strtoint()

static int strtoint ( const char *  nptr,
char **  endptr,
int  base 
)
static

Definition at line 19 of file interval.c.

References val.

Referenced by DecodeInterval().

20 {
21  long val;
22 
23  val = strtol(nptr, endptr, base);
24 #ifdef HAVE_LONG_INT_64
25  if (val != (long) ((int32) val))
26  errno = ERANGE;
27 #endif
28  return (int) val;
29 }
signed int int32
Definition: c.h:284
long val
Definition: informix.c:689

◆ tm2interval()

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

Definition at line 986 of file interval.c.

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

Referenced by PGTYPESinterval_from_asc().

987 {
988  if ((double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon > INT_MAX ||
989  (double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon < INT_MIN)
990  return -1;
991  span->month = tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
992  span->time = (((((((tm->tm_mday * INT64CONST(24)) +
993  tm->tm_hour) * INT64CONST(60)) +
994  tm->tm_min) * INT64CONST(60)) +
995  tm->tm_sec) * USECS_PER_SEC) + fsec;
996 
997  return 0;
998 } /* 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