00001
00002
00003 #include "postgres_fe.h"
00004
00005 #include <time.h>
00006 #include <ctype.h>
00007 #include <float.h>
00008 #include <limits.h>
00009
00010 #include "extern.h"
00011 #include "dt.h"
00012 #include "pgtypes_error.h"
00013 #include "pgtypes_date.h"
00014
00015 date *
00016 PGTYPESdate_new(void)
00017 {
00018 date *result;
00019
00020 result = (date *) pgtypes_alloc(sizeof(date));
00021
00022 return result;
00023 }
00024
00025 void
00026 PGTYPESdate_free(date * d)
00027 {
00028 free(d);
00029 }
00030
00031 date
00032 PGTYPESdate_from_timestamp(timestamp dt)
00033 {
00034 date dDate;
00035
00036 dDate = 0;
00037
00038 if (!TIMESTAMP_NOT_FINITE(dt))
00039 {
00040 #ifdef HAVE_INT64_TIMESTAMP
00041
00042 dDate = (dt / USECS_PER_DAY);
00043 #else
00044
00045 dDate = (dt / (double) SECS_PER_DAY);
00046 #endif
00047 }
00048
00049 return dDate;
00050 }
00051
00052 date
00053 PGTYPESdate_from_asc(char *str, char **endptr)
00054 {
00055
00056 date dDate;
00057 fsec_t fsec;
00058 struct tm tt,
00059 *tm = &tt;
00060 int dtype;
00061 int nf;
00062 char *field[MAXDATEFIELDS];
00063 int ftype[MAXDATEFIELDS];
00064 char lowstr[MAXDATELEN + 1];
00065 char *realptr;
00066 char **ptr = (endptr != NULL) ? endptr : &realptr;
00067
00068 bool EuroDates = FALSE;
00069
00070 errno = 0;
00071 if (strlen(str) >= sizeof(lowstr))
00072 {
00073 errno = PGTYPES_DATE_BAD_DATE;
00074 return INT_MIN;
00075 }
00076
00077 if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
00078 DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, EuroDates) != 0)
00079 {
00080 errno = PGTYPES_DATE_BAD_DATE;
00081 return INT_MIN;
00082 }
00083
00084 switch (dtype)
00085 {
00086 case DTK_DATE:
00087 break;
00088
00089 case DTK_EPOCH:
00090 if (GetEpochTime(tm) < 0)
00091 {
00092 errno = PGTYPES_DATE_BAD_DATE;
00093 return INT_MIN;
00094 }
00095 break;
00096
00097 default:
00098 errno = PGTYPES_DATE_BAD_DATE;
00099 return INT_MIN;
00100 }
00101
00102 dDate = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1));
00103
00104 return dDate;
00105 }
00106
00107 char *
00108 PGTYPESdate_to_asc(date dDate)
00109 {
00110 struct tm tt,
00111 *tm = &tt;
00112 char buf[MAXDATELEN + 1];
00113 int DateStyle = 1;
00114 bool EuroDates = FALSE;
00115
00116 j2date(dDate + date2j(2000, 1, 1), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
00117 EncodeDateOnly(tm, DateStyle, buf, EuroDates);
00118 return pgtypes_strdup(buf);
00119 }
00120
00121 void
00122 PGTYPESdate_julmdy(date jd, int *mdy)
00123 {
00124 int y,
00125 m,
00126 d;
00127
00128 j2date((int) (jd + date2j(2000, 1, 1)), &y, &m, &d);
00129 mdy[0] = m;
00130 mdy[1] = d;
00131 mdy[2] = y;
00132 }
00133
00134 void
00135 PGTYPESdate_mdyjul(int *mdy, date * jdate)
00136 {
00137
00138
00139
00140
00141 *jdate = (date) (date2j(mdy[2], mdy[0], mdy[1]) - date2j(2000, 1, 1));
00142 }
00143
00144 int
00145 PGTYPESdate_dayofweek(date dDate)
00146 {
00147
00148
00149
00150
00151 return (int) (dDate + date2j(2000, 1, 1) + 1) % 7;
00152 }
00153
00154 void
00155 PGTYPESdate_today(date * d)
00156 {
00157 struct tm ts;
00158
00159 GetCurrentDateTime(&ts);
00160 if (errno == 0)
00161 *d = date2j(ts.tm_year, ts.tm_mon, ts.tm_mday) - date2j(2000, 1, 1);
00162 return;
00163 }
00164
00165 #define PGTYPES_DATE_NUM_MAX_DIGITS 20
00166
00167
00168 #define PGTYPES_FMTDATE_DAY_DIGITS_LZ 1
00169 #define PGTYPES_FMTDATE_DOW_LITERAL_SHORT 2
00170 #define PGTYPES_FMTDATE_MONTH_DIGITS_LZ 3
00171 #define PGTYPES_FMTDATE_MONTH_LITERAL_SHORT 4
00172 #define PGTYPES_FMTDATE_YEAR_DIGITS_SHORT 5
00173 #define PGTYPES_FMTDATE_YEAR_DIGITS_LONG 6
00174
00175 int
00176 PGTYPESdate_fmt_asc(date dDate, const char *fmtstring, char *outbuf)
00177 {
00178 static struct
00179 {
00180 char *format;
00181 int component;
00182 } mapping[] =
00183 {
00184
00185
00186
00187
00188 {
00189 "ddd", PGTYPES_FMTDATE_DOW_LITERAL_SHORT
00190 },
00191 {
00192 "dd", PGTYPES_FMTDATE_DAY_DIGITS_LZ
00193 },
00194 {
00195 "mmm", PGTYPES_FMTDATE_MONTH_LITERAL_SHORT
00196 },
00197 {
00198 "mm", PGTYPES_FMTDATE_MONTH_DIGITS_LZ
00199 },
00200 {
00201 "yyyy", PGTYPES_FMTDATE_YEAR_DIGITS_LONG
00202 },
00203 {
00204 "yy", PGTYPES_FMTDATE_YEAR_DIGITS_SHORT
00205 },
00206 {
00207 NULL, 0
00208 }
00209 };
00210
00211 union un_fmt_comb replace_val;
00212 int replace_type;
00213
00214 int i;
00215 int dow;
00216 char *start_pattern;
00217 struct tm tm;
00218
00219
00220 strcpy(outbuf, fmtstring);
00221
00222
00223 j2date(dDate + date2j(2000, 1, 1), &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
00224 dow = PGTYPESdate_dayofweek(dDate);
00225
00226 for (i = 0; mapping[i].format != NULL; i++)
00227 {
00228 while ((start_pattern = strstr(outbuf, mapping[i].format)) != NULL)
00229 {
00230 switch (mapping[i].component)
00231 {
00232 case PGTYPES_FMTDATE_DOW_LITERAL_SHORT:
00233 replace_val.str_val = pgtypes_date_weekdays_short[dow];
00234 replace_type = PGTYPES_TYPE_STRING_CONSTANT;
00235 break;
00236 case PGTYPES_FMTDATE_DAY_DIGITS_LZ:
00237 replace_val.uint_val = tm.tm_mday;
00238 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00239 break;
00240 case PGTYPES_FMTDATE_MONTH_LITERAL_SHORT:
00241 replace_val.str_val = months[tm.tm_mon - 1];
00242 replace_type = PGTYPES_TYPE_STRING_CONSTANT;
00243 break;
00244 case PGTYPES_FMTDATE_MONTH_DIGITS_LZ:
00245 replace_val.uint_val = tm.tm_mon;
00246 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00247 break;
00248 case PGTYPES_FMTDATE_YEAR_DIGITS_LONG:
00249 replace_val.uint_val = tm.tm_year;
00250 replace_type = PGTYPES_TYPE_UINT_4_LZ;
00251 break;
00252 case PGTYPES_FMTDATE_YEAR_DIGITS_SHORT:
00253 replace_val.uint_val = tm.tm_year % 100;
00254 replace_type = PGTYPES_TYPE_UINT_2_LZ;
00255 break;
00256 default:
00257
00258
00259
00260
00261 replace_val.str_val = " ";
00262 replace_type = PGTYPES_TYPE_STRING_CONSTANT;
00263 }
00264 switch (replace_type)
00265 {
00266 case PGTYPES_TYPE_STRING_MALLOCED:
00267 case PGTYPES_TYPE_STRING_CONSTANT:
00268 strncpy(start_pattern, replace_val.str_val,
00269 strlen(replace_val.str_val));
00270 if (replace_type == PGTYPES_TYPE_STRING_MALLOCED)
00271 free(replace_val.str_val);
00272 break;
00273 case PGTYPES_TYPE_UINT:
00274 {
00275 char *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
00276
00277 if (!t)
00278 return -1;
00279 snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
00280 "%u", replace_val.uint_val);
00281 strncpy(start_pattern, t, strlen(t));
00282 free(t);
00283 }
00284 break;
00285 case PGTYPES_TYPE_UINT_2_LZ:
00286 {
00287 char *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
00288
00289 if (!t)
00290 return -1;
00291 snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
00292 "%02u", replace_val.uint_val);
00293 strncpy(start_pattern, t, strlen(t));
00294 free(t);
00295 }
00296 break;
00297 case PGTYPES_TYPE_UINT_4_LZ:
00298 {
00299 char *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
00300
00301 if (!t)
00302 return -1;
00303 snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
00304 "%04u", replace_val.uint_val);
00305 strncpy(start_pattern, t, strlen(t));
00306 free(t);
00307 }
00308 break;
00309 default:
00310
00311
00312
00313
00314
00315 break;
00316 }
00317 }
00318 }
00319 return 0;
00320 }
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 #define PGTYPES_DATE_MONTH_MAXLENGTH 20
00337 int
00338 PGTYPESdate_defmt_asc(date * d, const char *fmt, char *str)
00339 {
00340
00341
00342
00343
00344 int token[3][2];
00345 int token_values[3] = {-1, -1, -1};
00346 char *fmt_token_order;
00347 char *fmt_ystart,
00348 *fmt_mstart,
00349 *fmt_dstart;
00350 unsigned int i;
00351 int reading_digit;
00352 int token_count;
00353 char *str_copy;
00354 struct tm tm;
00355
00356 tm.tm_year = tm.tm_mon = tm.tm_mday = 0;
00357
00358 if (!d || !str || !fmt)
00359 {
00360 errno = PGTYPES_DATE_ERR_EARGS;
00361 return -1;
00362 }
00363
00364
00365 fmt_ystart = strstr(fmt, "yy");
00366 fmt_mstart = strstr(fmt, "mm");
00367 fmt_dstart = strstr(fmt, "dd");
00368
00369 if (!fmt_ystart || !fmt_mstart || !fmt_dstart)
00370 {
00371 errno = PGTYPES_DATE_ERR_EARGS;
00372 return -1;
00373 }
00374
00375 if (fmt_ystart < fmt_mstart)
00376 {
00377
00378 if (fmt_dstart < fmt_ystart)
00379 {
00380
00381 fmt_token_order = "dym";
00382 }
00383 else if (fmt_dstart > fmt_mstart)
00384 {
00385
00386 fmt_token_order = "ymd";
00387 }
00388 else
00389 {
00390
00391 fmt_token_order = "ydm";
00392 }
00393 }
00394 else
00395 {
00396
00397
00398 if (fmt_dstart < fmt_mstart)
00399 {
00400
00401 fmt_token_order = "dmy";
00402 }
00403 else if (fmt_dstart > fmt_ystart)
00404 {
00405
00406 fmt_token_order = "myd";
00407 }
00408 else
00409 {
00410
00411 fmt_token_order = "mdy";
00412 }
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 reading_digit = 1;
00427 for (i = 0; str[i]; i++)
00428 {
00429 if (!isdigit((unsigned char) str[i]))
00430 {
00431 reading_digit = 0;
00432 break;
00433 }
00434 }
00435 if (reading_digit)
00436 {
00437 int frag_length[3];
00438 int target_pos;
00439
00440 i = strlen(str);
00441 if (i != 8 && i != 6)
00442 {
00443 errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
00444 return -1;
00445 }
00446
00447
00448
00449
00450
00451
00452 str_copy = pgtypes_alloc(strlen(str) + 1 + 2);
00453 if (!str_copy)
00454 return -1;
00455
00456
00457 if (i == 6)
00458 {
00459 frag_length[0] = 2;
00460 frag_length[1] = 2;
00461 frag_length[2] = 2;
00462 }
00463 else
00464 {
00465 if (fmt_token_order[0] == 'y')
00466 {
00467 frag_length[0] = 4;
00468 frag_length[1] = 2;
00469 frag_length[2] = 2;
00470 }
00471 else if (fmt_token_order[1] == 'y')
00472 {
00473 frag_length[0] = 2;
00474 frag_length[1] = 4;
00475 frag_length[2] = 2;
00476 }
00477 else
00478 {
00479 frag_length[0] = 2;
00480 frag_length[1] = 2;
00481 frag_length[2] = 4;
00482 }
00483 }
00484 target_pos = 0;
00485
00486
00487
00488
00489
00490
00491 for (i = 0; i < 3; i++)
00492 {
00493 int start_pos = 0;
00494
00495 if (i >= 1)
00496 start_pos += frag_length[0];
00497 if (i == 2)
00498 start_pos += frag_length[1];
00499
00500 strncpy(str_copy + target_pos, str + start_pos,
00501 frag_length[i]);
00502 target_pos += frag_length[i];
00503 if (i != 2)
00504 {
00505 str_copy[target_pos] = ' ';
00506 target_pos++;
00507 }
00508 }
00509 str_copy[target_pos] = '\0';
00510 }
00511 else
00512 {
00513 str_copy = pgtypes_strdup(str);
00514 if (!str_copy)
00515 return -1;
00516
00517
00518 for (i = 0; str_copy[i]; i++)
00519 str_copy[i] = (char) pg_tolower((unsigned char) str_copy[i]);
00520 }
00521
00522
00523 reading_digit = 0;
00524 token_count = 0;
00525 for (i = 0; i < strlen(str_copy); i++)
00526 {
00527 if (!isdigit((unsigned char) str_copy[i]) && reading_digit)
00528 {
00529
00530 token[token_count][1] = i - 1;
00531 reading_digit = 0;
00532 token_count++;
00533 }
00534 else if (isdigit((unsigned char) str_copy[i]) && !reading_digit)
00535 {
00536
00537 token[token_count][0] = i;
00538 reading_digit = 1;
00539 }
00540 }
00541
00542
00543
00544
00545
00546 if (reading_digit)
00547 {
00548 token[token_count][1] = i - 1;
00549 token_count++;
00550 }
00551
00552
00553 if (token_count < 2)
00554 {
00555
00556
00557
00558
00559 free(str_copy);
00560 errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
00561 return -1;
00562 }
00563
00564 if (token_count != 3)
00565 {
00566
00567
00568
00569
00570 char *month_lower_tmp = pgtypes_alloc(PGTYPES_DATE_MONTH_MAXLENGTH);
00571 char *start_pos;
00572 int j;
00573 int offset;
00574 int found = 0;
00575 char **list;
00576
00577 if (!month_lower_tmp)
00578 {
00579
00580 free(str_copy);
00581 return -1;
00582 }
00583 list = pgtypes_date_months;
00584 for (i = 0; list[i]; i++)
00585 {
00586 for (j = 0; j < PGTYPES_DATE_MONTH_MAXLENGTH; j++)
00587 {
00588 month_lower_tmp[j] = (char) pg_tolower((unsigned char) list[i][j]);
00589 if (!month_lower_tmp[j])
00590 {
00591
00592 break;
00593 }
00594 }
00595 if ((start_pos = strstr(str_copy, month_lower_tmp)))
00596 {
00597 offset = start_pos - str_copy;
00598
00599
00600
00601
00602
00603 if (offset < token[0][0])
00604 {
00605 token[2][0] = token[1][0];
00606 token[2][1] = token[1][1];
00607 token[1][0] = token[0][0];
00608 token[1][1] = token[0][1];
00609 token_count = 0;
00610 }
00611 else if (offset < token[1][0])
00612 {
00613 token[2][0] = token[1][0];
00614 token[2][1] = token[1][1];
00615 token_count = 1;
00616 }
00617 else
00618 token_count = 2;
00619 token[token_count][0] = offset;
00620 token[token_count][1] = offset + strlen(month_lower_tmp) - 1;
00621
00622
00623
00624
00625
00626 token_values[token_count] = i + 1;
00627 found = 1;
00628 break;
00629 }
00630
00631
00632
00633
00634
00635
00636 if (list == pgtypes_date_months)
00637 {
00638 if (list[i + 1] == NULL)
00639 {
00640 list = months;
00641 i = -1;
00642 }
00643 }
00644 }
00645 if (!found)
00646 {
00647 free(month_lower_tmp);
00648 free(str_copy);
00649 errno = PGTYPES_DATE_ERR_ENOTDMY;
00650 return -1;
00651 }
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664 if (fmt_token_order[token_count] != 'm')
00665 {
00666
00667 token_values[token_count] = -1;
00668 }
00669 free(month_lower_tmp);
00670 }
00671
00672
00673 for (i = 0; i < 3; i++)
00674 {
00675 *(str_copy + token[i][1] + 1) = '\0';
00676
00677 if (token_values[i] == -1)
00678 {
00679 errno = 0;
00680 token_values[i] = strtol(str_copy + token[i][0], (char **) NULL, 10);
00681
00682 if (errno)
00683 token_values[i] = -1;
00684 }
00685 if (fmt_token_order[i] == 'd')
00686 tm.tm_mday = token_values[i];
00687 else if (fmt_token_order[i] == 'm')
00688 tm.tm_mon = token_values[i];
00689 else if (fmt_token_order[i] == 'y')
00690 tm.tm_year = token_values[i];
00691 }
00692 free(str_copy);
00693
00694 if (tm.tm_mday < 1 || tm.tm_mday > 31)
00695 {
00696 errno = PGTYPES_DATE_BAD_DAY;
00697 return -1;
00698 }
00699
00700 if (tm.tm_mon < 1 || tm.tm_mon > MONTHS_PER_YEAR)
00701 {
00702 errno = PGTYPES_DATE_BAD_MONTH;
00703 return -1;
00704 }
00705
00706 if (tm.tm_mday == 31 && (tm.tm_mon == 4 || tm.tm_mon == 6 || tm.tm_mon == 9 || tm.tm_mon == 11))
00707 {
00708 errno = PGTYPES_DATE_BAD_DAY;
00709 return -1;
00710 }
00711
00712 if (tm.tm_mon == 2 && tm.tm_mday > 29)
00713 {
00714 errno = PGTYPES_DATE_BAD_DAY;
00715 return -1;
00716 }
00717
00718 *d = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - date2j(2000, 1, 1);
00719
00720 return 0;
00721 }