00001
00002
00003
00004 #include "postgres_fe.h"
00005
00006 #include <time.h>
00007 #include <float.h>
00008 #include <limits.h>
00009 #include <math.h>
00010
00011 #ifdef __FAST_MATH__
00012 #error -ffast-math is known to break this code
00013 #endif
00014
00015 #include "extern.h"
00016 #include "dt.h"
00017 #include "pgtypes_timestamp.h"
00018 #include "pgtypes_date.h"
00019
00020
00021 int PGTYPEStimestamp_defmt_scan(char **, const char *, timestamp *, int *, int *, int *,
00022 int *, int *, int *, int *);
00023
00024 #ifdef HAVE_INT64_TIMESTAMP
00025 static int64
00026 time2t(const int hour, const int min, const int sec, const fsec_t fsec)
00027 {
00028 return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
00029 }
00030 #else
00031 static double
00032 time2t(const int hour, const int min, const int sec, const fsec_t fsec)
00033 {
00034 return (((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec + fsec;
00035 }
00036 #endif
00037
00038 static timestamp
00039 dt2local(timestamp dt, int tz)
00040 {
00041 #ifdef HAVE_INT64_TIMESTAMP
00042 dt -= (tz * USECS_PER_SEC);
00043 #else
00044 dt -= tz;
00045 #endif
00046 return dt;
00047 }
00048
00049
00050
00051
00052
00053
00054
00055
00056 int
00057 tm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, timestamp * result)
00058 {
00059 #ifdef HAVE_INT64_TIMESTAMP
00060 int dDate;
00061 int64 time;
00062 #else
00063 double dDate,
00064 time;
00065 #endif
00066
00067
00068 if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
00069 return -1;
00070
00071 dDate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
00072 time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
00073 #ifdef HAVE_INT64_TIMESTAMP
00074 *result = (dDate * USECS_PER_DAY) + time;
00075
00076 if ((*result - time) / USECS_PER_DAY != dDate)
00077 return -1;
00078
00079
00080 if ((*result < 0 && dDate > 0) ||
00081 (*result > 0 && dDate < -1))
00082 return -1;
00083 #else
00084 *result = dDate * SECS_PER_DAY + time;
00085 #endif
00086 if (tzp != NULL)
00087 *result = dt2local(*result, -(*tzp));
00088
00089 return 0;
00090 }
00091
00092 static timestamp
00093 SetEpochTimestamp(void)
00094 {
00095 #ifdef HAVE_INT64_TIMESTAMP
00096 int64 noresult = 0;
00097 #else
00098 double noresult = 0.0;
00099 #endif
00100 timestamp dt;
00101 struct tm tt,
00102 *tm = &tt;
00103
00104 if (GetEpochTime(tm) < 0)
00105 return noresult;
00106
00107 tm2timestamp(tm, 0, NULL, &dt);
00108 return dt;
00109 }
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 static int
00123 timestamp2tm(timestamp dt, int *tzp, struct tm * tm, fsec_t *fsec, const char **tzn)
00124 {
00125 #ifdef HAVE_INT64_TIMESTAMP
00126 int64 dDate,
00127 date0;
00128 int64 time;
00129 #else
00130 double dDate,
00131 date0;
00132 double time;
00133 #endif
00134 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
00135 time_t utime;
00136 struct tm *tx;
00137 #endif
00138
00139 date0 = date2j(2000, 1, 1);
00140
00141 #ifdef HAVE_INT64_TIMESTAMP
00142 time = dt;
00143 TMODULO(time, dDate, USECS_PER_DAY);
00144
00145 if (time < INT64CONST(0))
00146 {
00147 time += USECS_PER_DAY;
00148 dDate -= 1;
00149 }
00150
00151
00152 dDate += date0;
00153
00154
00155 if (dDate < 0 || dDate > (timestamp) INT_MAX)
00156 return -1;
00157
00158 j2date((int) dDate, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
00159 dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
00160 #else
00161 time = dt;
00162 TMODULO(time, dDate, (double) SECS_PER_DAY);
00163
00164 if (time < 0)
00165 {
00166 time += SECS_PER_DAY;
00167 dDate -= 1;
00168 }
00169
00170
00171 dDate += date0;
00172
00173 recalc_d:
00174
00175 if (dDate < 0 || dDate > (timestamp) INT_MAX)
00176 return -1;
00177
00178 j2date((int) dDate, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
00179 recalc_t:
00180 dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
00181
00182 *fsec = TSROUND(*fsec);
00183
00184 if (*fsec >= 1.0)
00185 {
00186 time = ceil(time);
00187 if (time >= (double) SECS_PER_DAY)
00188 {
00189 time = 0;
00190 dDate += 1;
00191 goto recalc_d;
00192 }
00193 goto recalc_t;
00194 }
00195 #endif
00196
00197 if (tzp != NULL)
00198 {
00199
00200
00201
00202
00203 if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
00204 {
00205 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
00206
00207 #ifdef HAVE_INT64_TIMESTAMP
00208 utime = dt / USECS_PER_SEC +
00209 ((date0 - date2j(1970, 1, 1)) * INT64CONST(86400));
00210 #else
00211 utime = dt + (date0 - date2j(1970, 1, 1)) * SECS_PER_DAY;
00212 #endif
00213
00214 tx = localtime(&utime);
00215 tm->tm_year = tx->tm_year + 1900;
00216 tm->tm_mon = tx->tm_mon + 1;
00217 tm->tm_mday = tx->tm_mday;
00218 tm->tm_hour = tx->tm_hour;
00219 tm->tm_min = tx->tm_min;
00220 tm->tm_isdst = tx->tm_isdst;
00221
00222 #if defined(HAVE_TM_ZONE)
00223 tm->tm_gmtoff = tx->tm_gmtoff;
00224 tm->tm_zone = tx->tm_zone;
00225
00226 *tzp = -tm->tm_gmtoff;
00227 if (tzn != NULL)
00228 *tzn = tm->tm_zone;
00229 #elif defined(HAVE_INT_TIMEZONE)
00230 *tzp = (tm->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL;
00231 if (tzn != NULL)
00232 *tzn = TZNAME_GLOBAL[(tm->tm_isdst > 0)];
00233 #endif
00234 #else
00235 *tzp = 0;
00236
00237 tm->tm_isdst = -1;
00238 if (tzn != NULL)
00239 *tzn = NULL;
00240 #endif
00241 }
00242 else
00243 {
00244 *tzp = 0;
00245
00246 tm->tm_isdst = -1;
00247 if (tzn != NULL)
00248 *tzn = NULL;
00249 }
00250 }
00251 else
00252 {
00253 tm->tm_isdst = -1;
00254 if (tzn != NULL)
00255 *tzn = NULL;
00256 }
00257
00258 return 0;
00259 }
00260
00261
00262
00263
00264 static int
00265 EncodeSpecialTimestamp(timestamp dt, char *str)
00266 {
00267 if (TIMESTAMP_IS_NOBEGIN(dt))
00268 strcpy(str, EARLY);
00269 else if (TIMESTAMP_IS_NOEND(dt))
00270 strcpy(str, LATE);
00271 else
00272 return FALSE;
00273
00274 return TRUE;
00275 }
00276
00277 timestamp
00278 PGTYPEStimestamp_from_asc(char *str, char **endptr)
00279 {
00280 timestamp result;
00281
00282 #ifdef HAVE_INT64_TIMESTAMP
00283 int64 noresult = 0;
00284 #else
00285 double noresult = 0.0;
00286 #endif
00287 fsec_t fsec;
00288 struct tm tt,
00289 *tm = &tt;
00290 int dtype;
00291 int nf;
00292 char *field[MAXDATEFIELDS];
00293 int ftype[MAXDATEFIELDS];
00294 char lowstr[MAXDATELEN + MAXDATEFIELDS];
00295 char *realptr;
00296 char **ptr = (endptr != NULL) ? endptr : &realptr;
00297
00298 if (strlen(str) >= sizeof(lowstr))
00299 {
00300 errno = PGTYPES_TS_BAD_TIMESTAMP;
00301 return (noresult);
00302 }
00303
00304 if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
00305 DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, 0) != 0)
00306 {
00307 errno = PGTYPES_TS_BAD_TIMESTAMP;
00308 return (noresult);
00309 }
00310
00311 switch (dtype)
00312 {
00313 case DTK_DATE:
00314 if (tm2timestamp(tm, fsec, NULL, &result) != 0)
00315 {
00316 errno = PGTYPES_TS_BAD_TIMESTAMP;
00317 return (noresult);
00318 }
00319 break;
00320
00321 case DTK_EPOCH:
00322 result = SetEpochTimestamp();
00323 break;
00324
00325 case DTK_LATE:
00326 TIMESTAMP_NOEND(result);
00327 break;
00328
00329 case DTK_EARLY:
00330 TIMESTAMP_NOBEGIN(result);
00331 break;
00332
00333 case DTK_INVALID:
00334 errno = PGTYPES_TS_BAD_TIMESTAMP;
00335 return (noresult);
00336
00337 default:
00338 errno = PGTYPES_TS_BAD_TIMESTAMP;
00339 return (noresult);
00340 }
00341
00342
00343
00344
00345
00346
00347
00348 errno = 0;
00349 return result;
00350 }
00351
00352 char *
00353 PGTYPEStimestamp_to_asc(timestamp tstamp)
00354 {
00355 struct tm tt,
00356 *tm = &tt;
00357 char buf[MAXDATELEN + 1];
00358 fsec_t fsec;
00359 int DateStyle = 1;
00360
00361
00362 if (TIMESTAMP_NOT_FINITE(tstamp))
00363 EncodeSpecialTimestamp(tstamp, buf);
00364 else if (timestamp2tm(tstamp, NULL, tm, &fsec, NULL) == 0)
00365 EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf, 0);
00366 else
00367 {
00368 errno = PGTYPES_TS_BAD_TIMESTAMP;
00369 return NULL;
00370 }
00371 return pgtypes_strdup(buf);
00372 }
00373
00374 void
00375 PGTYPEStimestamp_current(timestamp * ts)
00376 {
00377 struct tm tm;
00378
00379 GetCurrentDateTime(&tm);
00380 if (errno == 0)
00381 tm2timestamp(&tm, 0, NULL, ts);
00382 return;
00383 }
00384
00385 static int
00386 dttofmtasc_replace(timestamp * ts, date dDate, int dow, struct tm * tm,
00387 char *output, int *pstr_len, const char *fmtstr)
00388 {
00389 union un_fmt_comb replace_val;
00390 int replace_type;
00391 int i;
00392 const char *p = fmtstr;
00393 char *q = output;
00394
00395 while (*p)
00396 {
00397 if (*p == '%')
00398 {
00399 p++;
00400
00401 replace_type = PGTYPES_TYPE_NOTHING;
00402 switch (*p)
00403 {
00404
00405
00406 case 'a':
00407 replace_val.str_val = pgtypes_date_weekdays_short[dow];
00408 replace_type = PGTYPES_TYPE_STRING_CONSTANT;
00409 break;
00410
00411
00412 case 'A':
00413 replace_val.str_val = days[dow];
00414 replace_type = PGTYPES_TYPE_STRING_CONSTANT;
00415 break;
00416
00417
00418 case 'b':
00419 case 'h':
00420 replace_val.str_val = months[tm->tm_mon];
00421 replace_type = PGTYPES_TYPE_STRING_CONSTANT;
00422 break;
00423
00424
00425 case 'B':
00426 replace_val.str_val = pgtypes_date_months[tm->tm_mon];
00427 replace_type = PGTYPES_TYPE_STRING_CONSTANT;
00428 break;
00429
00430
00431
00432
00433
00434 case 'c':
00435
00436 break;
00437
00438 case 'C':
00439 replace_val.uint_val = tm->tm_year / 100;
00440 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00441 break;
00442
00443 case 'd':
00444 replace_val.uint_val = tm->tm_mday;
00445 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00446 break;
00447
00448 case 'D':
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 i = dttofmtasc_replace(ts, dDate, dow, tm,
00459 q, pstr_len,
00460 "%m/%d/%y");
00461 if (i)
00462 return i;
00463 break;
00464
00465 case 'e':
00466 replace_val.uint_val = tm->tm_mday;
00467 replace_type = PGTYPES_TYPE_UINT_2_LS;
00468 break;
00469
00470
00471
00472
00473 case 'E':
00474 {
00475 char tmp[4] = "%Ex";
00476
00477 p++;
00478 if (*p == '\0')
00479 return -1;
00480 tmp[2] = *p;
00481
00482
00483
00484
00485 tm->tm_mon -= 1;
00486 i = strftime(q, *pstr_len, tmp, tm);
00487 if (i == 0)
00488 return -1;
00489 while (*q)
00490 {
00491 q++;
00492 (*pstr_len)--;
00493 }
00494 tm->tm_mon += 1;
00495 replace_type = PGTYPES_TYPE_NOTHING;
00496 break;
00497 }
00498
00499
00500
00501
00502
00503 case 'G':
00504 {
00505
00506 const char *fmt = "%G";
00507
00508 tm->tm_mon -= 1;
00509 i = strftime(q, *pstr_len, fmt, tm);
00510 if (i == 0)
00511 return -1;
00512 while (*q)
00513 {
00514 q++;
00515 (*pstr_len)--;
00516 }
00517 tm->tm_mon += 1;
00518 replace_type = PGTYPES_TYPE_NOTHING;
00519 }
00520 break;
00521
00522
00523
00524
00525
00526 case 'g':
00527 {
00528 const char *fmt = "%g";
00529
00530
00531 tm->tm_mon -= 1;
00532 i = strftime(q, *pstr_len, fmt, tm);
00533 if (i == 0)
00534 return -1;
00535 while (*q)
00536 {
00537 q++;
00538 (*pstr_len)--;
00539 }
00540 tm->tm_mon += 1;
00541 replace_type = PGTYPES_TYPE_NOTHING;
00542 }
00543 break;
00544
00545 case 'H':
00546 replace_val.uint_val = tm->tm_hour;
00547 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00548 break;
00549
00550 case 'I':
00551 replace_val.uint_val = tm->tm_hour % 12;
00552 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00553 break;
00554
00555
00556
00557
00558
00559 case 'j':
00560 replace_val.uint_val = tm->tm_yday;
00561 replace_type = PGTYPES_TYPE_UINT_3_LZ;
00562 break;
00563
00564
00565
00566
00567
00568 case 'k':
00569 replace_val.uint_val = tm->tm_hour;
00570 replace_type = PGTYPES_TYPE_UINT_2_LS;
00571 break;
00572
00573
00574
00575
00576
00577 case 'l':
00578 replace_val.uint_val = tm->tm_hour % 12;
00579 replace_type = PGTYPES_TYPE_UINT_2_LS;
00580 break;
00581
00582 case 'm':
00583 replace_val.uint_val = tm->tm_mon;
00584 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00585 break;
00586
00587 case 'M':
00588 replace_val.uint_val = tm->tm_min;
00589 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00590 break;
00591
00592 case 'n':
00593 replace_val.char_val = '\n';
00594 replace_type = PGTYPES_TYPE_CHAR;
00595 break;
00596
00597
00598 case 'p':
00599 if (tm->tm_hour < 12)
00600 replace_val.str_val = "AM";
00601 else
00602 replace_val.str_val = "PM";
00603 replace_type = PGTYPES_TYPE_STRING_CONSTANT;
00604 break;
00605
00606
00607 case 'P':
00608 if (tm->tm_hour < 12)
00609 replace_val.str_val = "am";
00610 else
00611 replace_val.str_val = "pm";
00612 replace_type = PGTYPES_TYPE_STRING_CONSTANT;
00613 break;
00614
00615
00616 case 'r':
00617 i = dttofmtasc_replace(ts, dDate, dow, tm,
00618 q, pstr_len,
00619 "%I:%M:%S %p");
00620 if (i)
00621 return i;
00622 break;
00623
00624 case 'R':
00625 i = dttofmtasc_replace(ts, dDate, dow, tm,
00626 q, pstr_len,
00627 "%H:%M");
00628 if (i)
00629 return i;
00630 break;
00631
00632 case 's':
00633 #ifdef HAVE_INT64_TIMESTAMP
00634 replace_val.int64_val = (*ts - SetEpochTimestamp()) / 1000000.0;
00635 replace_type = PGTYPES_TYPE_INT64;
00636 #else
00637 replace_val.double_val = *ts - SetEpochTimestamp();
00638 replace_type = PGTYPES_TYPE_DOUBLE_NF;
00639 #endif
00640 break;
00641
00642 case 'S':
00643 replace_val.uint_val = tm->tm_sec;
00644 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00645 break;
00646
00647 case 't':
00648 replace_val.char_val = '\t';
00649 replace_type = PGTYPES_TYPE_CHAR;
00650 break;
00651
00652 case 'T':
00653 i = dttofmtasc_replace(ts, dDate, dow, tm,
00654 q, pstr_len,
00655 "%H:%M:%S");
00656 if (i)
00657 return i;
00658 break;
00659
00660
00661
00662
00663
00664 case 'u':
00665 replace_val.uint_val = dow;
00666 if (replace_val.uint_val == 0)
00667 replace_val.uint_val = 7;
00668 replace_type = PGTYPES_TYPE_UINT;
00669 break;
00670
00671 case 'U':
00672 tm->tm_mon -= 1;
00673 i = strftime(q, *pstr_len, "%U", tm);
00674 if (i == 0)
00675 return -1;
00676 while (*q)
00677 {
00678 q++;
00679 (*pstr_len)--;
00680 }
00681 tm->tm_mon += 1;
00682 replace_type = PGTYPES_TYPE_NOTHING;
00683 break;
00684
00685
00686
00687
00688
00689 case 'V':
00690 {
00691
00692 const char *fmt = "%V";
00693
00694 i = strftime(q, *pstr_len, fmt, tm);
00695 if (i == 0)
00696 return -1;
00697 while (*q)
00698 {
00699 q++;
00700 (*pstr_len)--;
00701 }
00702 replace_type = PGTYPES_TYPE_NOTHING;
00703 }
00704 break;
00705
00706
00707
00708
00709
00710 case 'w':
00711 replace_val.uint_val = dow;
00712 replace_type = PGTYPES_TYPE_UINT;
00713 break;
00714
00715 case 'W':
00716 tm->tm_mon -= 1;
00717 i = strftime(q, *pstr_len, "%U", tm);
00718 if (i == 0)
00719 return -1;
00720 while (*q)
00721 {
00722 q++;
00723 (*pstr_len)--;
00724 }
00725 tm->tm_mon += 1;
00726 replace_type = PGTYPES_TYPE_NOTHING;
00727 break;
00728
00729
00730
00731
00732
00733 case 'x':
00734 {
00735 const char *fmt = "%x";
00736
00737
00738 tm->tm_mon -= 1;
00739 i = strftime(q, *pstr_len, fmt, tm);
00740 if (i == 0)
00741 return -1;
00742 while (*q)
00743 {
00744 q++;
00745 (*pstr_len)--;
00746 }
00747 tm->tm_mon += 1;
00748 replace_type = PGTYPES_TYPE_NOTHING;
00749 }
00750 break;
00751
00752
00753
00754
00755
00756 case 'X':
00757 tm->tm_mon -= 1;
00758 i = strftime(q, *pstr_len, "%X", tm);
00759 if (i == 0)
00760 return -1;
00761 while (*q)
00762 {
00763 q++;
00764 (*pstr_len)--;
00765 }
00766 tm->tm_mon += 1;
00767 replace_type = PGTYPES_TYPE_NOTHING;
00768 break;
00769
00770 case 'y':
00771 replace_val.uint_val = tm->tm_year % 100;
00772 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00773 break;
00774
00775 case 'Y':
00776 replace_val.uint_val = tm->tm_year;
00777 replace_type = PGTYPES_TYPE_UINT;
00778 break;
00779
00780 case 'z':
00781 tm->tm_mon -= 1;
00782 i = strftime(q, *pstr_len, "%z", tm);
00783 if (i == 0)
00784 return -1;
00785 while (*q)
00786 {
00787 q++;
00788 (*pstr_len)--;
00789 }
00790 tm->tm_mon += 1;
00791 replace_type = PGTYPES_TYPE_NOTHING;
00792 break;
00793
00794 case 'Z':
00795 tm->tm_mon -= 1;
00796 i = strftime(q, *pstr_len, "%Z", tm);
00797 if (i == 0)
00798 return -1;
00799 while (*q)
00800 {
00801 q++;
00802 (*pstr_len)--;
00803 }
00804 tm->tm_mon += 1;
00805 replace_type = PGTYPES_TYPE_NOTHING;
00806 break;
00807
00808 case '%':
00809 replace_val.char_val = '%';
00810 replace_type = PGTYPES_TYPE_CHAR;
00811 break;
00812 case '\0':
00813
00814
00815
00816
00817
00818 return -1;
00819 default:
00820
00821
00822
00823
00824 if (*pstr_len > 1)
00825 {
00826 *q = '%';
00827 q++;
00828 (*pstr_len)--;
00829 if (*pstr_len > 1)
00830 {
00831 *q = *p;
00832 q++;
00833 (*pstr_len)--;
00834 }
00835 else
00836 {
00837 *q = '\0';
00838 return -1;
00839 }
00840 *q = '\0';
00841 }
00842 else
00843 return -1;
00844 break;
00845 }
00846 i = pgtypes_fmt_replace(replace_val, replace_type, &q, pstr_len);
00847 if (i)
00848 return i;
00849 }
00850 else
00851 {
00852 if (*pstr_len > 1)
00853 {
00854 *q = *p;
00855 (*pstr_len)--;
00856 q++;
00857 *q = '\0';
00858 }
00859 else
00860 return -1;
00861 }
00862 p++;
00863 }
00864 return 0;
00865 }
00866
00867
00868 int
00869 PGTYPEStimestamp_fmt_asc(timestamp * ts, char *output, int str_len, const char *fmtstr)
00870 {
00871 struct tm tm;
00872 fsec_t fsec;
00873 date dDate;
00874 int dow;
00875
00876 dDate = PGTYPESdate_from_timestamp(*ts);
00877 dow = PGTYPESdate_dayofweek(dDate);
00878 timestamp2tm(*ts, NULL, &tm, &fsec, NULL);
00879
00880 return dttofmtasc_replace(ts, dDate, dow, &tm, output, &str_len, fmtstr);
00881 }
00882
00883 int
00884 PGTYPEStimestamp_sub(timestamp * ts1, timestamp * ts2, interval * iv)
00885 {
00886 if (TIMESTAMP_NOT_FINITE(*ts1) || TIMESTAMP_NOT_FINITE(*ts2))
00887 return PGTYPES_TS_ERR_EINFTIME;
00888 else
00889 iv->time = (*ts1 - *ts2);
00890
00891 iv->month = 0;
00892
00893 return 0;
00894 }
00895
00896 int
00897 PGTYPEStimestamp_defmt_asc(char *str, const char *fmt, timestamp * d)
00898 {
00899 int year,
00900 month,
00901 day;
00902 int hour,
00903 minute,
00904 second;
00905 int tz;
00906
00907 int i;
00908 char *mstr;
00909 char *mfmt;
00910
00911 if (!fmt)
00912 fmt = "%Y-%m-%d %H:%M:%S";
00913 if (!fmt[0])
00914 return 1;
00915
00916 mstr = pgtypes_strdup(str);
00917 mfmt = pgtypes_strdup(fmt);
00918
00919
00920
00921
00922
00923
00924 year = -1;
00925 month = -1;
00926 day = -1;
00927 hour = 0;
00928 minute = -1;
00929 second = -1;
00930 tz = 0;
00931
00932 i = PGTYPEStimestamp_defmt_scan(&mstr, mfmt, d, &year, &month, &day, &hour, &minute, &second, &tz);
00933 free(mstr);
00934 free(mfmt);
00935 return i;
00936 }
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948 int
00949 PGTYPEStimestamp_add_interval(timestamp * tin, interval * span, timestamp * tout)
00950 {
00951
00952
00953 if (TIMESTAMP_NOT_FINITE(*tin))
00954 *tout = *tin;
00955
00956
00957 else
00958 {
00959 if (span->month != 0)
00960 {
00961 struct tm tt,
00962 *tm = &tt;
00963 fsec_t fsec;
00964
00965
00966 if (timestamp2tm(*tin, NULL, tm, &fsec, NULL) != 0)
00967 return -1;
00968 tm->tm_mon += span->month;
00969 if (tm->tm_mon > MONTHS_PER_YEAR)
00970 {
00971 tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
00972 tm->tm_mon = (tm->tm_mon - 1) % MONTHS_PER_YEAR + 1;
00973 }
00974 else if (tm->tm_mon < 1)
00975 {
00976 tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
00977 tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
00978 }
00979
00980
00981
00982 if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
00983 tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
00984
00985
00986 if (tm2timestamp(tm, fsec, NULL, tin) != 0)
00987 return -1;
00988 }
00989
00990
00991 *tin += span->time;
00992 *tout = *tin;
00993 }
00994 return 0;
00995
00996 }
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009 int
01010 PGTYPEStimestamp_sub_interval(timestamp * tin, interval * span, timestamp * tout)
01011 {
01012 interval tspan;
01013
01014 tspan.month = -span->month;
01015 tspan.time = -span->time;
01016
01017
01018 return PGTYPEStimestamp_add_interval(tin, &tspan, tout);
01019 }