PostgreSQL Source Code  git master
timestamp.c
Go to the documentation of this file.
1 /*
2  * src/interfaces/ecpg/pgtypeslib/timestamp.c
3  */
4 #include "postgres_fe.h"
5 
6 #include <time.h>
7 #include <limits.h>
8 #include <math.h>
9 
10 #ifdef __FAST_MATH__
11 #error -ffast-math is known to break this code
12 #endif
13 
14 #include "common/int.h"
15 #include "dt.h"
16 #include "pgtypes_date.h"
17 #include "pgtypes_timestamp.h"
18 #include "pgtypeslib_extern.h"
19 
20 static int64
21 time2t(const int hour, const int min, const int sec, const fsec_t fsec)
22 {
23  return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
24 } /* time2t() */
25 
26 static timestamp
27 dt2local(timestamp dt, int tz)
28 {
29  dt -= (tz * USECS_PER_SEC);
30  return dt;
31 } /* dt2local() */
32 
33 /* tm2timestamp()
34  * Convert a tm structure to a timestamp data type.
35  * Note that year is _not_ 1900-based, but is an explicit full value.
36  * Also, month is one-based, _not_ zero-based.
37  *
38  * Returns -1 on failure (overflow).
39  */
40 int
41 tm2timestamp(struct tm *tm, fsec_t fsec, int *tzp, timestamp * result)
42 {
43  int dDate;
44  int64 time;
45 
46  /* Prevent overflow in Julian-day routines */
48  return -1;
49 
50  dDate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
51  time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
52  if (unlikely(pg_mul_s64_overflow(dDate, USECS_PER_DAY, result) ||
53  pg_add_s64_overflow(*result, time, result)))
54  return -1;
55  if (tzp != NULL)
56  *result = dt2local(*result, -(*tzp));
57 
58  /* final range check catches just-out-of-range timestamps */
59  if (!IS_VALID_TIMESTAMP(*result))
60  return -1;
61 
62  return 0;
63 } /* tm2timestamp() */
64 
65 static timestamp
67 {
68  int64 noresult = 0;
69  timestamp dt;
70  struct tm tt,
71  *tm = &tt;
72 
73  if (GetEpochTime(tm) < 0)
74  return noresult;
75 
76  tm2timestamp(tm, 0, NULL, &dt);
77  return dt;
78 } /* SetEpochTimestamp() */
79 
80 /* timestamp2tm()
81  * Convert timestamp data type to POSIX time structure.
82  * Note that year is _not_ 1900-based, but is an explicit full value.
83  * Also, month is one-based, _not_ zero-based.
84  * Returns:
85  * 0 on success
86  * -1 on out of range
87  *
88  * For dates within the system-supported time_t range, convert to the
89  * local time zone. If out of this range, leave as GMT. - tgl 97/05/27
90  */
91 static int
92 timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, const char **tzn)
93 {
94  int64 dDate,
95  date0;
96  int64 time;
97 #if defined(HAVE_STRUCT_TM_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
98  time_t utime;
99  struct tm *tx;
100 #endif
101 
102  date0 = date2j(2000, 1, 1);
103 
104  time = dt;
105  TMODULO(time, dDate, USECS_PER_DAY);
106 
107  if (time < INT64CONST(0))
108  {
109  time += USECS_PER_DAY;
110  dDate -= 1;
111  }
112 
113  /* add offset to go from J2000 back to standard Julian date */
114  dDate += date0;
115 
116  /* Julian day routine does not work for negative Julian days */
117  if (dDate < 0 || dDate > (timestamp) INT_MAX)
118  return -1;
119 
120  j2date((int) dDate, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
121  dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
122 
123  if (tzp != NULL)
124  {
125  /*
126  * Does this fall within the capabilities of the localtime()
127  * interface? Then use this to rotate to the local time zone.
128  */
130  {
131 #if defined(HAVE_STRUCT_TM_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
132  struct tm tmbuf;
133 
134  utime = dt / USECS_PER_SEC +
135  ((date0 - date2j(1970, 1, 1)) * INT64CONST(86400));
136 
137  tx = localtime_r(&utime, &tmbuf);
138  tm->tm_year = tx->tm_year + 1900;
139  tm->tm_mon = tx->tm_mon + 1;
140  tm->tm_mday = tx->tm_mday;
141  tm->tm_hour = tx->tm_hour;
142  tm->tm_min = tx->tm_min;
143  tm->tm_isdst = tx->tm_isdst;
144 
145 #if defined(HAVE_STRUCT_TM_TM_ZONE)
146  tm->tm_gmtoff = tx->tm_gmtoff;
147  tm->tm_zone = tx->tm_zone;
148 
149  *tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
150  if (tzn != NULL)
151  *tzn = tm->tm_zone;
152 #elif defined(HAVE_INT_TIMEZONE)
154  if (tzn != NULL)
155  *tzn = TZNAME_GLOBAL[(tm->tm_isdst > 0)];
156 #endif
157 #else /* not (HAVE_STRUCT_TM_TM_ZONE ||
158  * HAVE_INT_TIMEZONE) */
159  *tzp = 0;
160  /* Mark this as *no* time zone available */
161  tm->tm_isdst = -1;
162  if (tzn != NULL)
163  *tzn = NULL;
164 #endif
165  }
166  else
167  {
168  *tzp = 0;
169  /* Mark this as *no* time zone available */
170  tm->tm_isdst = -1;
171  if (tzn != NULL)
172  *tzn = NULL;
173  }
174  }
175  else
176  {
177  tm->tm_isdst = -1;
178  if (tzn != NULL)
179  *tzn = NULL;
180  }
181 
182  tm->tm_yday = dDate - date2j(tm->tm_year, 1, 1) + 1;
183 
184  return 0;
185 } /* timestamp2tm() */
186 
187 /* EncodeSpecialTimestamp()
188  * * Convert reserved timestamp data type to string.
189  * */
190 static void
192 {
193  if (TIMESTAMP_IS_NOBEGIN(dt))
194  strcpy(str, EARLY);
195  else if (TIMESTAMP_IS_NOEND(dt))
196  strcpy(str, LATE);
197  else
198  abort(); /* shouldn't happen */
199 }
200 
201 timestamp
202 PGTYPEStimestamp_from_asc(char *str, char **endptr)
203 {
204  timestamp result;
205  int64 noresult = 0;
206  fsec_t fsec;
207  struct tm tt,
208  *tm = &tt;
209  int dtype;
210  int nf;
211  char *field[MAXDATEFIELDS];
212  int ftype[MAXDATEFIELDS];
213  char lowstr[MAXDATELEN + MAXDATEFIELDS];
214  char *realptr;
215  char **ptr = (endptr != NULL) ? endptr : &realptr;
216 
217  if (strlen(str) > MAXDATELEN)
218  {
219  errno = PGTYPES_TS_BAD_TIMESTAMP;
220  return noresult;
221  }
222 
223  if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
224  DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, 0) != 0)
225  {
226  errno = PGTYPES_TS_BAD_TIMESTAMP;
227  return noresult;
228  }
229 
230  switch (dtype)
231  {
232  case DTK_DATE:
233  if (tm2timestamp(tm, fsec, NULL, &result) != 0)
234  {
235  errno = PGTYPES_TS_BAD_TIMESTAMP;
236  return noresult;
237  }
238  break;
239 
240  case DTK_EPOCH:
241  result = SetEpochTimestamp();
242  break;
243 
244  case DTK_LATE:
245  TIMESTAMP_NOEND(result);
246  break;
247 
248  case DTK_EARLY:
249  TIMESTAMP_NOBEGIN(result);
250  break;
251 
252  default:
253  errno = PGTYPES_TS_BAD_TIMESTAMP;
254  return noresult;
255  }
256 
257  /* AdjustTimestampForTypmod(&result, typmod); */
258 
259  /*
260  * Since it's difficult to test for noresult, make sure errno is 0 if no
261  * error occurred.
262  */
263  errno = 0;
264  return result;
265 }
266 
267 char *
269 {
270  struct tm tt,
271  *tm = &tt;
272  char buf[MAXDATELEN + 1];
273  fsec_t fsec;
274  int DateStyle = 1; /* this defaults to USE_ISO_DATES, shall we
275  * make it an option? */
276 
277  if (TIMESTAMP_NOT_FINITE(tstamp))
278  EncodeSpecialTimestamp(tstamp, buf);
279  else if (timestamp2tm(tstamp, NULL, tm, &fsec, NULL) == 0)
280  EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf, 0);
281  else
282  {
283  errno = PGTYPES_TS_BAD_TIMESTAMP;
284  return NULL;
285  }
286  return pgtypes_strdup(buf);
287 }
288 
289 void
291 {
292  struct tm tm;
293 
295  if (errno == 0)
296  tm2timestamp(&tm, 0, NULL, ts);
297 }
298 
299 static int
300 dttofmtasc_replace(timestamp * ts, date dDate, int dow, struct tm *tm,
301  char *output, int *pstr_len, const char *fmtstr)
302 {
303  union un_fmt_comb replace_val;
304  int replace_type;
305  int i;
306  const char *p = fmtstr;
307  char *q = output;
308 
309  while (*p)
310  {
311  if (*p == '%')
312  {
313  p++;
314  /* fix compiler warning */
315  replace_type = PGTYPES_TYPE_NOTHING;
316  switch (*p)
317  {
318  /* the abbreviated name of the day in the week */
319  /* XXX should be locale aware */
320  case 'a':
321  replace_val.str_val = pgtypes_date_weekdays_short[dow];
322  replace_type = PGTYPES_TYPE_STRING_CONSTANT;
323  break;
324  /* the full name of the day in the week */
325  /* XXX should be locale aware */
326  case 'A':
327  replace_val.str_val = days[dow];
328  replace_type = PGTYPES_TYPE_STRING_CONSTANT;
329  break;
330  /* the abbreviated name of the month */
331  /* XXX should be locale aware */
332  case 'b':
333  case 'h':
334  replace_val.str_val = months[tm->tm_mon - 1];
335  replace_type = PGTYPES_TYPE_STRING_CONSTANT;
336  break;
337  /* the full name of the month */
338  /* XXX should be locale aware */
339  case 'B':
340  replace_val.str_val = pgtypes_date_months[tm->tm_mon - 1];
341  replace_type = PGTYPES_TYPE_STRING_CONSTANT;
342  break;
343 
344  /*
345  * The preferred date and time representation for the
346  * current locale.
347  */
348  case 'c':
349  /* XXX */
350  break;
351  /* the century number with leading zeroes */
352  case 'C':
353  replace_val.uint_val = tm->tm_year / 100;
354  replace_type = PGTYPES_TYPE_UINT_2_LZ;
355  break;
356  /* day with leading zeroes (01 - 31) */
357  case 'd':
358  replace_val.uint_val = tm->tm_mday;
359  replace_type = PGTYPES_TYPE_UINT_2_LZ;
360  break;
361  /* the date in the format mm/dd/yy */
362  case 'D':
363 
364  /*
365  * ts, dDate, dow, tm is information about the timestamp
366  *
367  * q is the start of the current output buffer
368  *
369  * pstr_len is a pointer to the remaining size of output,
370  * i.e. the size of q
371  */
372  i = dttofmtasc_replace(ts, dDate, dow, tm,
373  q, pstr_len,
374  "%m/%d/%y");
375  if (i)
376  return i;
377  break;
378  /* day with leading spaces (01 - 31) */
379  case 'e':
380  replace_val.uint_val = tm->tm_mday;
381  replace_type = PGTYPES_TYPE_UINT_2_LS;
382  break;
383 
384  /*
385  * alternative format modifier
386  */
387  case 'E':
388  {
389  char tmp[4] = "%Ex";
390 
391  p++;
392  if (*p == '\0')
393  return -1;
394  tmp[2] = *p;
395 
396  /*
397  * strftime's month is 0 based, ours is 1 based
398  */
399  tm->tm_mon -= 1;
400  i = strftime(q, *pstr_len, tmp, tm);
401  if (i == 0)
402  return -1;
403  while (*q)
404  {
405  q++;
406  (*pstr_len)--;
407  }
408  tm->tm_mon += 1;
409  replace_type = PGTYPES_TYPE_NOTHING;
410  break;
411  }
412 
413  /*
414  * The ISO 8601 year with century as a decimal number. The
415  * 4-digit year corresponding to the ISO week number.
416  */
417  case 'G':
418  {
419  /* Keep compiler quiet - Don't use a literal format */
420  const char *fmt = "%G";
421 
422  tm->tm_mon -= 1;
423  i = strftime(q, *pstr_len, fmt, tm);
424  if (i == 0)
425  return -1;
426  while (*q)
427  {
428  q++;
429  (*pstr_len)--;
430  }
431  tm->tm_mon += 1;
432  replace_type = PGTYPES_TYPE_NOTHING;
433  }
434  break;
435 
436  /*
437  * Like %G, but without century, i.e., with a 2-digit year
438  * (00-99).
439  */
440  case 'g':
441  {
442  const char *fmt = "%g"; /* Keep compiler quiet about
443  * 2-digit year */
444 
445  tm->tm_mon -= 1;
446  i = strftime(q, *pstr_len, fmt, tm);
447  if (i == 0)
448  return -1;
449  while (*q)
450  {
451  q++;
452  (*pstr_len)--;
453  }
454  tm->tm_mon += 1;
455  replace_type = PGTYPES_TYPE_NOTHING;
456  }
457  break;
458  /* hour (24 hour clock) with leading zeroes */
459  case 'H':
460  replace_val.uint_val = tm->tm_hour;
461  replace_type = PGTYPES_TYPE_UINT_2_LZ;
462  break;
463  /* hour (12 hour clock) with leading zeroes */
464  case 'I':
465  replace_val.uint_val = tm->tm_hour % 12;
466  replace_type = PGTYPES_TYPE_UINT_2_LZ;
467  break;
468 
469  /*
470  * The day of the year as a decimal number with leading
471  * zeroes. It ranges from 001 to 366.
472  */
473  case 'j':
474  replace_val.uint_val = tm->tm_yday;
475  replace_type = PGTYPES_TYPE_UINT_3_LZ;
476  break;
477 
478  /*
479  * The hour (24 hour clock). Leading zeroes will be turned
480  * into spaces.
481  */
482  case 'k':
483  replace_val.uint_val = tm->tm_hour;
484  replace_type = PGTYPES_TYPE_UINT_2_LS;
485  break;
486 
487  /*
488  * The hour (12 hour clock). Leading zeroes will be turned
489  * into spaces.
490  */
491  case 'l':
492  replace_val.uint_val = tm->tm_hour % 12;
493  replace_type = PGTYPES_TYPE_UINT_2_LS;
494  break;
495  /* The month as a decimal number with a leading zero */
496  case 'm':
497  replace_val.uint_val = tm->tm_mon;
498  replace_type = PGTYPES_TYPE_UINT_2_LZ;
499  break;
500  /* The minute as a decimal number with a leading zero */
501  case 'M':
502  replace_val.uint_val = tm->tm_min;
503  replace_type = PGTYPES_TYPE_UINT_2_LZ;
504  break;
505  /* A newline character */
506  case 'n':
507  replace_val.char_val = '\n';
508  replace_type = PGTYPES_TYPE_CHAR;
509  break;
510  /* the AM/PM specifier (uppercase) */
511  /* XXX should be locale aware */
512  case 'p':
513  if (tm->tm_hour < 12)
514  replace_val.str_val = "AM";
515  else
516  replace_val.str_val = "PM";
517  replace_type = PGTYPES_TYPE_STRING_CONSTANT;
518  break;
519  /* the AM/PM specifier (lowercase) */
520  /* XXX should be locale aware */
521  case 'P':
522  if (tm->tm_hour < 12)
523  replace_val.str_val = "am";
524  else
525  replace_val.str_val = "pm";
526  replace_type = PGTYPES_TYPE_STRING_CONSTANT;
527  break;
528  /* the time in the format %I:%M:%S %p */
529  /* XXX should be locale aware */
530  case 'r':
531  i = dttofmtasc_replace(ts, dDate, dow, tm,
532  q, pstr_len,
533  "%I:%M:%S %p");
534  if (i)
535  return i;
536  break;
537  /* The time in 24 hour notation (%H:%M) */
538  case 'R':
539  i = dttofmtasc_replace(ts, dDate, dow, tm,
540  q, pstr_len,
541  "%H:%M");
542  if (i)
543  return i;
544  break;
545  /* The number of seconds since the Epoch (1970-01-01) */
546  case 's':
547  replace_val.int64_val = (*ts - SetEpochTimestamp()) / 1000000.0;
548  replace_type = PGTYPES_TYPE_INT64;
549  break;
550  /* seconds as a decimal number with leading zeroes */
551  case 'S':
552  replace_val.uint_val = tm->tm_sec;
553  replace_type = PGTYPES_TYPE_UINT_2_LZ;
554  break;
555  /* A tabulator */
556  case 't':
557  replace_val.char_val = '\t';
558  replace_type = PGTYPES_TYPE_CHAR;
559  break;
560  /* The time in 24 hour notation (%H:%M:%S) */
561  case 'T':
562  i = dttofmtasc_replace(ts, dDate, dow, tm,
563  q, pstr_len,
564  "%H:%M:%S");
565  if (i)
566  return i;
567  break;
568 
569  /*
570  * The day of the week as a decimal, Monday = 1, Sunday =
571  * 7
572  */
573  case 'u':
574  replace_val.uint_val = dow;
575  if (replace_val.uint_val == 0)
576  replace_val.uint_val = 7;
577  replace_type = PGTYPES_TYPE_UINT;
578  break;
579  /* The week number of the year as a decimal number */
580  case 'U':
581  tm->tm_mon -= 1;
582  i = strftime(q, *pstr_len, "%U", tm);
583  if (i == 0)
584  return -1;
585  while (*q)
586  {
587  q++;
588  (*pstr_len)--;
589  }
590  tm->tm_mon += 1;
591  replace_type = PGTYPES_TYPE_NOTHING;
592  break;
593 
594  /*
595  * The ISO 8601:1988 week number of the current year as a
596  * decimal number.
597  */
598  case 'V':
599  {
600  /* Keep compiler quiet - Don't use a literal format */
601  const char *fmt = "%V";
602 
603  i = strftime(q, *pstr_len, fmt, tm);
604  if (i == 0)
605  return -1;
606  while (*q)
607  {
608  q++;
609  (*pstr_len)--;
610  }
611  replace_type = PGTYPES_TYPE_NOTHING;
612  }
613  break;
614 
615  /*
616  * The day of the week as a decimal, Sunday being 0 and
617  * Monday 1.
618  */
619  case 'w':
620  replace_val.uint_val = dow;
621  replace_type = PGTYPES_TYPE_UINT;
622  break;
623  /* The week number of the year (another definition) */
624  case 'W':
625  tm->tm_mon -= 1;
626  i = strftime(q, *pstr_len, "%U", tm);
627  if (i == 0)
628  return -1;
629  while (*q)
630  {
631  q++;
632  (*pstr_len)--;
633  }
634  tm->tm_mon += 1;
635  replace_type = PGTYPES_TYPE_NOTHING;
636  break;
637 
638  /*
639  * The preferred date representation for the current
640  * locale without the time.
641  */
642  case 'x':
643  {
644  const char *fmt = "%x"; /* Keep compiler quiet about
645  * 2-digit year */
646 
647  tm->tm_mon -= 1;
648  i = strftime(q, *pstr_len, fmt, tm);
649  if (i == 0)
650  return -1;
651  while (*q)
652  {
653  q++;
654  (*pstr_len)--;
655  }
656  tm->tm_mon += 1;
657  replace_type = PGTYPES_TYPE_NOTHING;
658  }
659  break;
660 
661  /*
662  * The preferred time representation for the current
663  * locale without the date.
664  */
665  case 'X':
666  tm->tm_mon -= 1;
667  i = strftime(q, *pstr_len, "%X", tm);
668  if (i == 0)
669  return -1;
670  while (*q)
671  {
672  q++;
673  (*pstr_len)--;
674  }
675  tm->tm_mon += 1;
676  replace_type = PGTYPES_TYPE_NOTHING;
677  break;
678  /* The year without the century (2 digits, leading zeroes) */
679  case 'y':
680  replace_val.uint_val = tm->tm_year % 100;
681  replace_type = PGTYPES_TYPE_UINT_2_LZ;
682  break;
683  /* The year with the century (4 digits) */
684  case 'Y':
685  replace_val.uint_val = tm->tm_year;
686  replace_type = PGTYPES_TYPE_UINT;
687  break;
688  /* The time zone offset from GMT */
689  case 'z':
690  tm->tm_mon -= 1;
691  i = strftime(q, *pstr_len, "%z", tm);
692  if (i == 0)
693  return -1;
694  while (*q)
695  {
696  q++;
697  (*pstr_len)--;
698  }
699  tm->tm_mon += 1;
700  replace_type = PGTYPES_TYPE_NOTHING;
701  break;
702  /* The name or abbreviation of the time zone */
703  case 'Z':
704  tm->tm_mon -= 1;
705  i = strftime(q, *pstr_len, "%Z", tm);
706  if (i == 0)
707  return -1;
708  while (*q)
709  {
710  q++;
711  (*pstr_len)--;
712  }
713  tm->tm_mon += 1;
714  replace_type = PGTYPES_TYPE_NOTHING;
715  break;
716  /* A % sign */
717  case '%':
718  replace_val.char_val = '%';
719  replace_type = PGTYPES_TYPE_CHAR;
720  break;
721  case '\0':
722  /* fmtstr: foo%' - The string ends with a % sign */
723 
724  /*
725  * this is not compliant to the specification
726  */
727  return -1;
728  default:
729 
730  /*
731  * if we don't know the pattern, we just copy it
732  */
733  if (*pstr_len > 1)
734  {
735  *q = '%';
736  q++;
737  (*pstr_len)--;
738  if (*pstr_len > 1)
739  {
740  *q = *p;
741  q++;
742  (*pstr_len)--;
743  }
744  else
745  {
746  *q = '\0';
747  return -1;
748  }
749  *q = '\0';
750  }
751  else
752  return -1;
753  break;
754  }
755  i = pgtypes_fmt_replace(replace_val, replace_type, &q, pstr_len);
756  if (i)
757  return i;
758  }
759  else
760  {
761  if (*pstr_len > 1)
762  {
763  *q = *p;
764  (*pstr_len)--;
765  q++;
766  *q = '\0';
767  }
768  else
769  return -1;
770  }
771  p++;
772  }
773  return 0;
774 }
775 
776 
777 int
778 PGTYPEStimestamp_fmt_asc(timestamp * ts, char *output, int str_len, const char *fmtstr)
779 {
780  struct tm tm;
781  fsec_t fsec;
782  date dDate;
783  int dow;
784 
785  dDate = PGTYPESdate_from_timestamp(*ts);
786  dow = PGTYPESdate_dayofweek(dDate);
787  timestamp2tm(*ts, NULL, &tm, &fsec, NULL);
788 
789  return dttofmtasc_replace(ts, dDate, dow, &tm, output, &str_len, fmtstr);
790 }
791 
792 int
794 {
795  if (TIMESTAMP_NOT_FINITE(*ts1) || TIMESTAMP_NOT_FINITE(*ts2))
797  else
798  iv->time = (*ts1 - *ts2);
799 
800  iv->month = 0;
801 
802  return 0;
803 }
804 
805 int
806 PGTYPEStimestamp_defmt_asc(const char *str, const char *fmt, timestamp * d)
807 {
808  int year,
809  month,
810  day;
811  int hour,
812  minute,
813  second;
814  int tz;
815 
816  int i;
817  char *mstr;
818  char *mfmt;
819 
820  if (!fmt)
821  fmt = "%Y-%m-%d %H:%M:%S";
822  if (!fmt[0])
823  return 1;
824 
825  mstr = pgtypes_strdup(str);
826  mfmt = pgtypes_strdup(fmt);
827 
828  /*
829  * initialize with impossible values so that we can see if the fields
830  * where specified at all
831  */
832  /* XXX ambiguity with 1 BC for year? */
833  year = -1;
834  month = -1;
835  day = -1;
836  hour = 0;
837  minute = -1;
838  second = -1;
839  tz = 0;
840 
841  i = PGTYPEStimestamp_defmt_scan(&mstr, mfmt, d, &year, &month, &day, &hour, &minute, &second, &tz);
842  free(mstr);
843  free(mfmt);
844  return i;
845 }
846 
847 /*
848 * add an interval to a time stamp
849 *
850 * *tout = tin + span
851 *
852 * returns 0 if successful
853 * returns -1 if it fails
854 *
855 */
856 
857 int
859 {
860  if (TIMESTAMP_NOT_FINITE(*tin))
861  *tout = *tin;
862  else
863  {
864  if (span->month != 0)
865  {
866  struct tm tt,
867  *tm = &tt;
868  fsec_t fsec;
869 
870  if (timestamp2tm(*tin, NULL, tm, &fsec, NULL) != 0)
871  return -1;
872  tm->tm_mon += span->month;
873  if (tm->tm_mon > MONTHS_PER_YEAR)
874  {
875  tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
876  tm->tm_mon = (tm->tm_mon - 1) % MONTHS_PER_YEAR + 1;
877  }
878  else if (tm->tm_mon < 1)
879  {
880  tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
882  }
883 
884 
885  /* adjust for end of month boundary problems... */
886  if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
887  tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
888 
889 
890  if (tm2timestamp(tm, fsec, NULL, tin) != 0)
891  return -1;
892  }
893 
894  *tin += span->time;
895  *tout = *tin;
896  }
897 
898  return 0;
899 }
900 
901 
902 /*
903 * subtract an interval from a time stamp
904 *
905 * *tout = tin - span
906 *
907 * returns 0 if successful
908 * returns -1 if it fails
909 *
910 */
911 
912 int
914 {
915  interval tspan;
916 
917  tspan.month = -span->month;
918  tspan.time = -span->time;
919 
920  return PGTYPEStimestamp_add_interval(tin, &tspan, tout);
921 }
const int day_tab[2][13]
Definition: datetime.c:75
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:754
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:311
void GetCurrentDateTime(struct pg_tm *tm)
Definition: datetime.c:366
void EncodeDateTime(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
Definition: datetime.c:4342
const char *const months[]
Definition: datetime.c:81
int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp, DateTimeErrorExtra *extra)
Definition: datetime.c:978
int date2j(int year, int month, int day)
Definition: datetime.c:286
const char *const days[]
Definition: datetime.c:84
void dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
Definition: timestamp.c:1864
void GetEpochTime(struct pg_tm *tm)
Definition: timestamp.c:2149
Timestamp SetEpochTimestamp(void)
Definition: timestamp.c:2171
int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
Definition: timestamp.c:1987
void EncodeSpecialTimestamp(Timestamp dt, char *str)
Definition: timestamp.c:1586
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1891
#define unlikely(x)
Definition: c.h:314
#define SECS_PER_HOUR
Definition: timestamp.h:127
int32 fsec_t
Definition: timestamp.h:41
#define TIMESTAMP_NOBEGIN(j)
Definition: timestamp.h:159
#define MONTHS_PER_YEAR
Definition: timestamp.h:108
#define MINS_PER_HOUR
Definition: timestamp.h:129
#define IS_VALID_JULIAN(y, m, d)
Definition: timestamp.h:227
#define IS_VALID_TIMESTAMP(t)
Definition: timestamp.h:267
#define SECS_PER_MINUTE
Definition: timestamp.h:128
#define USECS_PER_DAY
Definition: timestamp.h:131
#define USECS_PER_SEC
Definition: timestamp.h:134
#define TIMESTAMP_IS_NOEND(j)
Definition: timestamp.h:167
#define TIMESTAMP_IS_NOBEGIN(j)
Definition: timestamp.h:162
#define TIMESTAMP_NOT_FINITE(j)
Definition: timestamp.h:169
#define TIMESTAMP_NOEND(j)
Definition: timestamp.h:164
int PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp *d, int *year, int *month, int *day, int *hour, int *minute, int *second, int *tz)
Definition: dt_common.c:2521
#define IS_VALID_UTIME(y, m, d)
Definition: dt.h:298
char * pgtypes_date_months[]
Definition: dt_common.c:499
char * pgtypes_date_weekdays_short[]
Definition: dt_common.c:497
int DateStyle
Definition: globals.c:124
const char * str
#define free(a)
Definition: header.h:65
#define MAXDATEFIELDS
Definition: datetime.h:202
#define DTK_EPOCH
Definition: datetime.h:152
#define TMODULO(t, q, u)
Definition: datetime.h:248
#define DTK_LATE
Definition: datetime.h:151
#define DTK_DATE
Definition: datetime.h:144
#define DTK_EARLY
Definition: datetime.h:150
#define MAXDATELEN
Definition: datetime.h:200
#define isleap(y)
Definition: datetime.h:271
#define EARLY
Definition: datetime.h:39
#define LATE
Definition: datetime.h:40
FILE * output
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:261
static bool pg_add_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:203
char * pgtypes_strdup(const char *str)
Definition: common.c:20
int pgtypes_fmt_replace(union un_fmt_comb replace_val, int replace_type, char **output, int *pstr_len)
Definition: common.c:30
int PGTYPEStimestamp_sub_interval(timestamp *tin, interval *span, timestamp *tout)
Definition: timestamp.c:913
timestamp PGTYPEStimestamp_from_asc(char *str, char **endptr)
Definition: timestamp.c:202
static timestamp dt2local(timestamp dt, int tz)
Definition: timestamp.c:27
int PGTYPEStimestamp_sub(timestamp *ts1, timestamp *ts2, interval *iv)
Definition: timestamp.c:793
static int64 time2t(const int hour, const int min, const int sec, const fsec_t fsec)
Definition: timestamp.c:21
int PGTYPEStimestamp_add_interval(timestamp *tin, interval *span, timestamp *tout)
Definition: timestamp.c:858
void PGTYPEStimestamp_current(timestamp *ts)
Definition: timestamp.c:290
char * PGTYPEStimestamp_to_asc(timestamp tstamp)
Definition: timestamp.c:268
int PGTYPEStimestamp_fmt_asc(timestamp *ts, char *output, int str_len, const char *fmtstr)
Definition: timestamp.c:778
int PGTYPEStimestamp_defmt_asc(const char *str, const char *fmt, timestamp *d)
Definition: timestamp.c:806
static int dttofmtasc_replace(timestamp *ts, date dDate, int dow, struct tm *tm, char *output, int *pstr_len, const char *fmtstr)
Definition: timestamp.c:300
int i
Definition: isn.c:73
static void const char * fmt
static struct pg_tm tm
Definition: localtime.c:104
static char * buf
Definition: pg_test_fsync.c:73
date PGTYPESdate_from_timestamp(timestamp dt)
Definition: datetime.c:31
int PGTYPESdate_dayofweek(date dDate)
Definition: datetime.c:138
long date
Definition: pgtypes_date.h:9
#define PGTYPES_TS_BAD_TIMESTAMP
Definition: pgtypes_error.h:15
#define PGTYPES_TS_ERR_EINFTIME
Definition: pgtypes_error.h:16
int64 timestamp
#define PGTYPES_TYPE_STRING_CONSTANT
#define PGTYPES_TYPE_NOTHING
#define PGTYPES_TYPE_UINT
#define PGTYPES_TYPE_CHAR
#define PGTYPES_TYPE_UINT_2_LS
#define PGTYPES_TYPE_UINT_2_LZ
#define PGTYPES_TYPE_INT64
#define PGTYPES_TYPE_UINT_3_LZ
#define TIMEZONE_GLOBAL
Definition: port.h:268
#define TZNAME_GLOBAL
Definition: port.h:269
static void fmtstr(const char *value, int leftjust, int minlen, int maxwidth, int pointflag, PrintfTarget *target)
Definition: snprintf.c:967
int tm_hour
Definition: pgtime.h:38
int tm_mday
Definition: pgtime.h:39
int tm_mon
Definition: pgtime.h:40
int tm_min
Definition: pgtime.h:37
const char * tm_zone
Definition: pgtime.h:46
int tm_yday
Definition: pgtime.h:43
int tm_sec
Definition: pgtime.h:36
int tm_isdst
Definition: pgtime.h:44
long int tm_gmtoff
Definition: pgtime.h:45
int tm_year
Definition: pgtime.h:41
unsigned int uint_val