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