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