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