dt.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:99k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * dt.c
  4.  *   Functions for the built-in type "dt".
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/dt.c,v 1.72.2.1 1999/08/02 05:24:51 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <ctype.h>
  15. #include <math.h>
  16. #include <sys/types.h>
  17. #include <errno.h>
  18. #include "postgres.h"
  19. #ifdef HAVE_FLOAT_H
  20. #include <float.h>
  21. #endif
  22. #ifdef HAVE_LIMITS_H
  23. #include <limits.h>
  24. #endif
  25. #ifndef USE_POSIX_TIME
  26. #include <sys/timeb.h>
  27. #endif
  28. #include "miscadmin.h"
  29. #include "utils/builtins.h"
  30. static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
  31. static int DecodeNumber(int flen, char *field,
  32. int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits);
  33. static int DecodeNumberField(int len, char *str,
  34. int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits);
  35. static int DecodeSpecial(int field, char *lowtoken, int *val);
  36. static int DecodeTime(char *str, int fmask, int *tmask,
  37.    struct tm * tm, double *fsec);
  38. static int DecodeTimezone(char *str, int *tzp);
  39. static int DecodeUnits(int field, char *lowtoken, int *val);
  40. static int EncodeSpecialDateTime(DateTime dt, char *str);
  41. static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
  42. static DateTime dt2local(DateTime dt, int timezone);
  43. static void dt2time(DateTime dt, int *hour, int *min, double *sec);
  44. static int j2day(int jd);
  45. static double time2t(const int hour, const int min, const double sec);
  46. static int timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec);
  47. static int tm2timespan(struct tm * tm, double fsec, TimeSpan *span);
  48. #define USE_DATE_CACHE 1
  49. #define ROUND_ALL 0
  50. int day_tab[2][13] = {
  51. {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0},
  52. {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}};
  53. char    *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  54. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
  55. char    *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
  56. "Thursday", "Friday", "Saturday", NULL};
  57. /* TMODULO()
  58.  * Macro to replace modf(), which is broken on some platforms.
  59.  */
  60. #define TMODULO(t,q,u) 
  61. do { 
  62. q = ((t < 0)? ceil(t / u): floor(t / u)); 
  63. if (q != 0) 
  64. t -= rint(q * u); 
  65. } while(0)
  66. static void GetEpochTime(struct tm * tm);
  67. #define UTIME_MINYEAR (1901)
  68. #define UTIME_MINMONTH (12)
  69. #define UTIME_MINDAY (14)
  70. #define UTIME_MAXYEAR (2038)
  71. #define UTIME_MAXMONTH (01)
  72. #define UTIME_MAXDAY (18)
  73. #define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) 
  74.  || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) 
  75.   || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) 
  76.  && ((y < UTIME_MAXYEAR) 
  77.  || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) 
  78.   || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY))))))
  79. /*****************************************************************************
  80.  *  USER I/O ROUTINES  *
  81.  *****************************************************************************/
  82. /* datetime_in()
  83.  * Convert a string to internal form.
  84.  */
  85. DateTime   *
  86. datetime_in(char *str)
  87. {
  88. DateTime   *result;
  89. double fsec;
  90. struct tm tt,
  91.    *tm = &tt;
  92. int tz;
  93. int dtype;
  94. int nf;
  95. char    *field[MAXDATEFIELDS];
  96. int ftype[MAXDATEFIELDS];
  97. char lowstr[MAXDATELEN + 1];
  98. if (!PointerIsValid(str))
  99. elog(ERROR, "Bad (null) datetime external representation", NULL);
  100. if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
  101.   || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
  102. elog(ERROR, "Bad datetime external representation '%s'", str);
  103. result = palloc(sizeof(DateTime));
  104. switch (dtype)
  105. {
  106. case DTK_DATE:
  107. if (tm2datetime(tm, fsec, &tz, result) != 0)
  108. elog(ERROR, "Datetime out of range '%s'", str);
  109. #ifdef DATEDEBUG
  110. printf("datetime_in- date is %fn", *result);
  111. #endif
  112. break;
  113. case DTK_EPOCH:
  114. DATETIME_EPOCH(*result);
  115. break;
  116. case DTK_CURRENT:
  117. DATETIME_CURRENT(*result);
  118. break;
  119. case DTK_LATE:
  120. DATETIME_NOEND(*result);
  121. break;
  122. case DTK_EARLY:
  123. DATETIME_NOBEGIN(*result);
  124. break;
  125. case DTK_INVALID:
  126. DATETIME_INVALID(*result);
  127. break;
  128. default:
  129. elog(ERROR, "Internal coding error, can't input datetime '%s'", str);
  130. }
  131. return result;
  132. } /* datetime_in() */
  133. /* datetime_out()
  134.  * Convert a datetime to external form.
  135.  */
  136. char *
  137. datetime_out(DateTime *dt)
  138. {
  139. char    *result;
  140. int tz;
  141. struct tm tt,
  142.    *tm = &tt;
  143. double fsec;
  144. char    *tzn;
  145. char buf[MAXDATELEN + 1];
  146. if (!PointerIsValid(dt))
  147. return NULL;
  148. if (DATETIME_IS_RESERVED(*dt))
  149. {
  150. EncodeSpecialDateTime(*dt, buf);
  151. }
  152. else if (datetime2tm(*dt, &tz, tm, &fsec, &tzn) == 0)
  153. {
  154. EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
  155. }
  156. else
  157. EncodeSpecialDateTime(DT_INVALID, buf);
  158. result = palloc(strlen(buf) + 1);
  159. strcpy(result, buf);
  160. return result;
  161. } /* datetime_out() */
  162. /* timespan_in()
  163.  * Convert a string to internal form.
  164.  *
  165.  * External format(s):
  166.  * Uses the generic date/time parsing and decoding routines.
  167.  */
  168. TimeSpan   *
  169. timespan_in(char *str)
  170. {
  171. TimeSpan   *span;
  172. double fsec;
  173. struct tm tt,
  174.    *tm = &tt;
  175. int dtype;
  176. int nf;
  177. char    *field[MAXDATEFIELDS];
  178. int ftype[MAXDATEFIELDS];
  179. char lowstr[MAXDATELEN + 1];
  180. tm->tm_year = 0;
  181. tm->tm_mon = 0;
  182. tm->tm_mday = 0;
  183. tm->tm_hour = 0;
  184. tm->tm_min = 0;
  185. tm->tm_sec = 0;
  186. fsec = 0;
  187. if (!PointerIsValid(str))
  188. elog(ERROR, "Bad (null) timespan external representation", NULL);
  189. if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
  190. || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
  191. elog(ERROR, "Bad timespan external representation '%s'", str);
  192. span = palloc(sizeof(TimeSpan));
  193. switch (dtype)
  194. {
  195. case DTK_DELTA:
  196. if (tm2timespan(tm, fsec, span) != 0)
  197. {
  198. #if NOT_USED
  199. TIMESPAN_INVALID(span);
  200. #endif
  201. elog(ERROR, "Bad timespan external representation '%s'", str);
  202. }
  203. break;
  204. default:
  205. elog(ERROR, "Internal coding error, can't input timespan '%s'", str);
  206. }
  207. return span;
  208. } /* timespan_in() */
  209. /* timespan_out()
  210.  * Convert a time span to external form.
  211.  */
  212. char *
  213. timespan_out(TimeSpan *span)
  214. {
  215. char    *result;
  216. struct tm tt,
  217.    *tm = &tt;
  218. double fsec;
  219. char buf[MAXDATELEN + 1];
  220. if (!PointerIsValid(span))
  221. return NULL;
  222. if (timespan2tm(*span, tm, &fsec) != 0)
  223. return NULL;
  224. if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0)
  225. elog(ERROR, "Unable to format timespan", NULL);
  226. result = palloc(strlen(buf) + 1);
  227. strcpy(result, buf);
  228. return result;
  229. } /* timespan_out() */
  230. /*****************************************************************************
  231.  *  PUBLIC ROUTINES  *
  232.  *****************************************************************************/
  233. bool
  234. datetime_finite(DateTime *datetime)
  235. {
  236. if (!PointerIsValid(datetime))
  237. return FALSE;
  238. return !DATETIME_NOT_FINITE(*datetime);
  239. } /* datetime_finite() */
  240. bool
  241. timespan_finite(TimeSpan *timespan)
  242. {
  243. if (!PointerIsValid(timespan))
  244. return FALSE;
  245. return !TIMESPAN_NOT_FINITE(*timespan);
  246. } /* timespan_finite() */
  247. /*----------------------------------------------------------
  248.  * Relational operators for datetime.
  249.  *---------------------------------------------------------*/
  250. static void
  251. GetEpochTime(struct tm * tm)
  252. {
  253. struct tm  *t0;
  254. time_t epoch = 0;
  255. t0 = gmtime(&epoch);
  256. tm->tm_year = t0->tm_year;
  257. tm->tm_mon = t0->tm_mon;
  258. tm->tm_mday = t0->tm_mday;
  259. tm->tm_hour = t0->tm_hour;
  260. tm->tm_min = t0->tm_min;
  261. tm->tm_sec = t0->tm_sec;
  262. if (tm->tm_year < 1900)
  263. tm->tm_year += 1900;
  264. tm->tm_mon++;
  265. #ifdef DATEDEBUG
  266. printf("GetEpochTime- %04d-%02d-%02d %02d:%02d:%02dn",
  267.    tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
  268. #endif
  269. return;
  270. } /* GetEpochTime() */
  271. DateTime
  272. SetDateTime(DateTime dt)
  273. {
  274. struct tm tt;
  275. if (DATETIME_IS_CURRENT(dt))
  276. {
  277. GetCurrentTime(&tt);
  278. tm2datetime(&tt, 0, NULL, &dt);
  279. dt = dt2local(dt, -CTimeZone);
  280. #ifdef DATEDEBUG
  281. printf("SetDateTime- current time is %fn", dt);
  282. #endif
  283. }
  284. else
  285. { /* if (DATETIME_IS_EPOCH(dt1)) */
  286. GetEpochTime(&tt);
  287. tm2datetime(&tt, 0, NULL, &dt);
  288. #ifdef DATEDEBUG
  289. printf("SetDateTime- epoch time is %fn", dt);
  290. #endif
  291. }
  292. return dt;
  293. } /* SetDateTime() */
  294. /* datetime_relop - is datetime1 relop datetime2
  295.  */
  296. bool
  297. datetime_eq(DateTime *datetime1, DateTime *datetime2)
  298. {
  299. DateTime dt1,
  300. dt2;
  301. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  302. return FALSE;
  303. dt1 = *datetime1;
  304. dt2 = *datetime2;
  305. if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
  306. return FALSE;
  307. if (DATETIME_IS_RELATIVE(dt1))
  308. dt1 = SetDateTime(dt1);
  309. if (DATETIME_IS_RELATIVE(dt2))
  310. dt2 = SetDateTime(dt2);
  311. return dt1 == dt2;
  312. } /* datetime_eq() */
  313. bool
  314. datetime_ne(DateTime *datetime1, DateTime *datetime2)
  315. {
  316. DateTime dt1,
  317. dt2;
  318. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  319. return FALSE;
  320. dt1 = *datetime1;
  321. dt2 = *datetime2;
  322. if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
  323. return FALSE;
  324. if (DATETIME_IS_RELATIVE(dt1))
  325. dt1 = SetDateTime(dt1);
  326. if (DATETIME_IS_RELATIVE(dt2))
  327. dt2 = SetDateTime(dt2);
  328. return dt1 != dt2;
  329. } /* datetime_ne() */
  330. bool
  331. datetime_lt(DateTime *datetime1, DateTime *datetime2)
  332. {
  333. DateTime dt1,
  334. dt2;
  335. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  336. return FALSE;
  337. dt1 = *datetime1;
  338. dt2 = *datetime2;
  339. if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
  340. return FALSE;
  341. if (DATETIME_IS_RELATIVE(dt1))
  342. dt1 = SetDateTime(dt1);
  343. if (DATETIME_IS_RELATIVE(dt2))
  344. dt2 = SetDateTime(dt2);
  345. return dt1 < dt2;
  346. } /* datetime_lt() */
  347. bool
  348. datetime_gt(DateTime *datetime1, DateTime *datetime2)
  349. {
  350. DateTime dt1,
  351. dt2;
  352. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  353. return FALSE;
  354. dt1 = *datetime1;
  355. dt2 = *datetime2;
  356. if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
  357. return FALSE;
  358. if (DATETIME_IS_RELATIVE(dt1))
  359. dt1 = SetDateTime(dt1);
  360. if (DATETIME_IS_RELATIVE(dt2))
  361. dt2 = SetDateTime(dt2);
  362. #ifdef DATEDEBUG
  363. printf("datetime_gt- %f %s greater than %fn", dt1, ((dt1 > dt2) ? "is" : "is not"), dt2);
  364. #endif
  365. return dt1 > dt2;
  366. } /* datetime_gt() */
  367. bool
  368. datetime_le(DateTime *datetime1, DateTime *datetime2)
  369. {
  370. DateTime dt1,
  371. dt2;
  372. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  373. return FALSE;
  374. dt1 = *datetime1;
  375. dt2 = *datetime2;
  376. if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
  377. return FALSE;
  378. if (DATETIME_IS_RELATIVE(dt1))
  379. dt1 = SetDateTime(dt1);
  380. if (DATETIME_IS_RELATIVE(dt2))
  381. dt2 = SetDateTime(dt2);
  382. return dt1 <= dt2;
  383. } /* datetime_le() */
  384. bool
  385. datetime_ge(DateTime *datetime1, DateTime *datetime2)
  386. {
  387. DateTime dt1,
  388. dt2;
  389. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  390. return FALSE;
  391. dt1 = *datetime1;
  392. dt2 = *datetime2;
  393. if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
  394. return FALSE;
  395. if (DATETIME_IS_RELATIVE(dt1))
  396. dt1 = SetDateTime(dt1);
  397. if (DATETIME_IS_RELATIVE(dt2))
  398. dt2 = SetDateTime(dt2);
  399. return dt1 >= dt2;
  400. } /* datetime_ge() */
  401. /* datetime_cmp - 3-state comparison for datetime
  402.  * collate invalid datetime at the end
  403.  */
  404. int
  405. datetime_cmp(DateTime *datetime1, DateTime *datetime2)
  406. {
  407. DateTime dt1,
  408. dt2;
  409. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  410. return 0;
  411. dt1 = *datetime1;
  412. dt2 = *datetime2;
  413. if (DATETIME_IS_INVALID(dt1))
  414. {
  415. return (DATETIME_IS_INVALID(dt2) ? 0 : 1);
  416. }
  417. else if (DATETIME_IS_INVALID(dt2))
  418. {
  419. return -1;
  420. }
  421. else
  422. {
  423. if (DATETIME_IS_RELATIVE(dt1))
  424. dt1 = SetDateTime(dt1);
  425. if (DATETIME_IS_RELATIVE(dt2))
  426. dt2 = SetDateTime(dt2);
  427. }
  428. return ((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0));
  429. } /* datetime_cmp() */
  430. /* timespan_relop - is timespan1 relop timespan2
  431.  */
  432. bool
  433. timespan_eq(TimeSpan *timespan1, TimeSpan *timespan2)
  434. {
  435. if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
  436. return FALSE;
  437. if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
  438. return FALSE;
  439. return ((timespan1->time == timespan2->time)
  440. && (timespan1->month == timespan2->month));
  441. } /* timespan_eq() */
  442. bool
  443. timespan_ne(TimeSpan *timespan1, TimeSpan *timespan2)
  444. {
  445. if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
  446. return FALSE;
  447. if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
  448. return FALSE;
  449. return ((timespan1->time != timespan2->time)
  450. || (timespan1->month != timespan2->month));
  451. } /* timespan_ne() */
  452. bool
  453. timespan_lt(TimeSpan *timespan1, TimeSpan *timespan2)
  454. {
  455. double span1,
  456. span2;
  457. if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
  458. return FALSE;
  459. if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
  460. return FALSE;
  461. span1 = timespan1->time;
  462. if (timespan1->month != 0)
  463. span1 += (timespan1->month * (30.0 * 86400));
  464. span2 = timespan2->time;
  465. if (timespan2->month != 0)
  466. span2 += (timespan2->month * (30.0 * 86400));
  467. return span1 < span2;
  468. } /* timespan_lt() */
  469. bool
  470. timespan_gt(TimeSpan *timespan1, TimeSpan *timespan2)
  471. {
  472. double span1,
  473. span2;
  474. if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
  475. return FALSE;
  476. if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
  477. return FALSE;
  478. span1 = timespan1->time;
  479. if (timespan1->month != 0)
  480. span1 += (timespan1->month * (30.0 * 86400));
  481. span2 = timespan2->time;
  482. if (timespan2->month != 0)
  483. span2 += (timespan2->month * (30.0 * 86400));
  484. return span1 > span2;
  485. } /* timespan_gt() */
  486. bool
  487. timespan_le(TimeSpan *timespan1, TimeSpan *timespan2)
  488. {
  489. double span1,
  490. span2;
  491. if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
  492. return FALSE;
  493. if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
  494. return FALSE;
  495. span1 = timespan1->time;
  496. if (timespan1->month != 0)
  497. span1 += (timespan1->month * (30.0 * 86400));
  498. span2 = timespan2->time;
  499. if (timespan2->month != 0)
  500. span2 += (timespan2->month * (30.0 * 86400));
  501. return span1 <= span2;
  502. } /* timespan_le() */
  503. bool
  504. timespan_ge(TimeSpan *timespan1, TimeSpan *timespan2)
  505. {
  506. double span1,
  507. span2;
  508. if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
  509. return FALSE;
  510. if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
  511. return FALSE;
  512. span1 = timespan1->time;
  513. if (timespan1->month != 0)
  514. span1 += (timespan1->month * (30.0 * 86400));
  515. span2 = timespan2->time;
  516. if (timespan2->month != 0)
  517. span2 += (timespan2->month * (30.0 * 86400));
  518. return span1 >= span2;
  519. } /* timespan_ge() */
  520. /* timespan_cmp - 3-state comparison for timespan
  521.  */
  522. int
  523. timespan_cmp(TimeSpan *timespan1, TimeSpan *timespan2)
  524. {
  525. double span1,
  526. span2;
  527. if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
  528. return 0;
  529. if (TIMESPAN_IS_INVALID(*timespan1))
  530. {
  531. return TIMESPAN_IS_INVALID(*timespan2) ? 0 : 1;
  532. }
  533. else if (TIMESPAN_IS_INVALID(*timespan2))
  534. return -1;
  535. span1 = timespan1->time;
  536. if (timespan1->month != 0)
  537. span1 += (timespan1->month * (30.0 * 86400));
  538. span2 = timespan2->time;
  539. if (timespan2->month != 0)
  540. span2 += (timespan2->month * (30.0 * 86400));
  541. return (span1 < span2) ? -1 : (span1 > span2) ? 1 : 0;
  542. } /* timespan_cmp() */
  543. /*----------------------------------------------------------
  544.  * "Arithmetic" operators on date/times.
  545.  * datetime_foo returns foo as an object (pointer) that
  546.  * can be passed between languages.
  547.  * datetime_xx is an internal routine which returns the
  548.  * actual value.
  549.  *---------------------------------------------------------*/
  550. DateTime   *
  551. datetime_smaller(DateTime *datetime1, DateTime *datetime2)
  552. {
  553. DateTime   *result;
  554. DateTime dt1,
  555. dt2;
  556. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  557. return NULL;
  558. dt1 = *datetime1;
  559. dt2 = *datetime2;
  560. result = palloc(sizeof(DateTime));
  561. if (DATETIME_IS_RELATIVE(dt1))
  562. dt1 = SetDateTime(dt1);
  563. if (DATETIME_IS_RELATIVE(dt2))
  564. dt2 = SetDateTime(dt2);
  565. if (DATETIME_IS_INVALID(dt1))
  566. *result = dt2;
  567. else if (DATETIME_IS_INVALID(dt2))
  568. *result = dt1;
  569. else
  570. *result = ((dt2 < dt1) ? dt2 : dt1);
  571. return result;
  572. } /* datetime_smaller() */
  573. DateTime   *
  574. datetime_larger(DateTime *datetime1, DateTime *datetime2)
  575. {
  576. DateTime   *result;
  577. DateTime dt1,
  578. dt2;
  579. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  580. return NULL;
  581. dt1 = *datetime1;
  582. dt2 = *datetime2;
  583. result = palloc(sizeof(DateTime));
  584. if (DATETIME_IS_RELATIVE(dt1))
  585. dt1 = SetDateTime(dt1);
  586. if (DATETIME_IS_RELATIVE(dt2))
  587. dt2 = SetDateTime(dt2);
  588. if (DATETIME_IS_INVALID(dt1))
  589. *result = dt2;
  590. else if (DATETIME_IS_INVALID(dt2))
  591. *result = dt1;
  592. else
  593. *result = ((dt2 > dt1) ? dt2 : dt1);
  594. return result;
  595. } /* datetime_larger() */
  596. TimeSpan   *
  597. datetime_mi(DateTime *datetime1, DateTime *datetime2)
  598. {
  599. TimeSpan   *result;
  600. DateTime dt1,
  601. dt2;
  602. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  603. return NULL;
  604. dt1 = *datetime1;
  605. dt2 = *datetime2;
  606. result = palloc(sizeof(TimeSpan));
  607. if (DATETIME_IS_RELATIVE(dt1))
  608. dt1 = SetDateTime(dt1);
  609. if (DATETIME_IS_RELATIVE(dt2))
  610. dt2 = SetDateTime(dt2);
  611. #ifdef DATEDEBUG
  612. printf("datetime_mi- evaluate %f - %fn", dt1, dt2);
  613. #endif
  614. if (DATETIME_IS_INVALID(dt1)
  615. || DATETIME_IS_INVALID(dt2))
  616. {
  617. DATETIME_INVALID(result->time);
  618. }
  619. else
  620. result->time = JROUND(dt1 - dt2);
  621. result->month = 0;
  622. return result;
  623. } /* datetime_mi() */
  624. /* datetime_pl_span()
  625.  * Add a timespan to a datetime data type.
  626.  * Note that timespan has provisions for qualitative year/month
  627.  * units, so try to do the right thing with them.
  628.  * To add a month, increment the month, and use the same day of month.
  629.  * Then, if the next month has fewer days, set the day of month
  630.  * to the last day of month.
  631.  */
  632. DateTime   *
  633. datetime_pl_span(DateTime *datetime, TimeSpan *span)
  634. {
  635. DateTime   *result;
  636. DateTime dt;
  637. int tz;
  638. char    *tzn;
  639. if ((!PointerIsValid(datetime)) || (!PointerIsValid(span)))
  640. return NULL;
  641. result = palloc(sizeof(DateTime));
  642. #ifdef DATEDEBUG
  643. printf("datetime_pl_span- add %f to %d %fn", *datetime, span->month, span->time);
  644. #endif
  645. if (DATETIME_NOT_FINITE(*datetime))
  646. {
  647. *result = *datetime;
  648. }
  649. else if (TIMESPAN_IS_INVALID(*span))
  650. {
  651. DATETIME_INVALID(*result);
  652. }
  653. else
  654. {
  655. dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
  656. #ifdef ROUND_ALL
  657. dt = JROUND(dt + span->time);
  658. #else
  659. dt += span->time;
  660. #endif
  661. if (span->month != 0)
  662. {
  663. struct tm tt,
  664.    *tm = &tt;
  665. double fsec;
  666. if (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0)
  667. {
  668. #ifdef DATEDEBUG
  669. printf("datetime_pl_span- date was %04d-%02d-%02d %02d:%02d:%02dn",
  670.    tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
  671. #endif
  672. tm->tm_mon += span->month;
  673. if (tm->tm_mon > 12)
  674. {
  675. tm->tm_year += ((tm->tm_mon - 1) / 12);
  676. tm->tm_mon = (((tm->tm_mon - 1) % 12) + 1);
  677. }
  678. else if (tm->tm_mon < 1)
  679. {
  680. tm->tm_year += ((tm->tm_mon / 12) - 1);
  681. tm->tm_mon = ((tm->tm_mon % 12) + 12);
  682. }
  683. /* adjust for end of month boundary problems... */
  684. if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
  685. tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
  686. #ifdef DATEDEBUG
  687. printf("datetime_pl_span- date becomes %04d-%02d-%02d %02d:%02d:%02dn",
  688.    tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
  689. #endif
  690. if (tm2datetime(tm, fsec, &tz, &dt) != 0)
  691. elog(ERROR, "Unable to add datetime and timespan", NULL);
  692. }
  693. else
  694. DATETIME_INVALID(dt);
  695. }
  696. *result = dt;
  697. }
  698. return result;
  699. } /* datetime_pl_span() */
  700. DateTime   *
  701. datetime_mi_span(DateTime *datetime, TimeSpan *span)
  702. {
  703. DateTime   *result;
  704. TimeSpan tspan;
  705. if (!PointerIsValid(datetime) || !PointerIsValid(span))
  706. return NULL;
  707. tspan.month = -span->month;
  708. tspan.time = -span->time;
  709. result = datetime_pl_span(datetime, &tspan);
  710. return result;
  711. } /* datetime_mi_span() */
  712. TimeSpan   *
  713. timespan_um(TimeSpan *timespan)
  714. {
  715. TimeSpan   *result;
  716. if (!PointerIsValid(timespan))
  717. return NULL;
  718. result = palloc(sizeof(TimeSpan));
  719. result->time = -(timespan->time);
  720. result->month = -(timespan->month);
  721. return result;
  722. } /* timespan_um() */
  723. TimeSpan   *
  724. timespan_smaller(TimeSpan *timespan1, TimeSpan *timespan2)
  725. {
  726. TimeSpan   *result;
  727. double span1,
  728. span2;
  729. if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
  730. return NULL;
  731. result = palloc(sizeof(TimeSpan));
  732. if (TIMESPAN_IS_INVALID(*timespan1))
  733. {
  734. result->time = timespan2->time;
  735. result->month = timespan2->month;
  736. }
  737. else if (TIMESPAN_IS_INVALID(*timespan2))
  738. {
  739. result->time = timespan1->time;
  740. result->month = timespan1->month;
  741. }
  742. else
  743. {
  744. span1 = timespan1->time;
  745. if (timespan1->month != 0)
  746. span1 += (timespan1->month * (30.0 * 86400));
  747. span2 = timespan2->time;
  748. if (timespan2->month != 0)
  749. span2 += (timespan2->month * (30.0 * 86400));
  750. #ifdef DATEDEBUG
  751. printf("timespan_smaller- months %d %d times %f %f spans %f %fn",
  752.    timespan1->month, timespan2->month, timespan1->time, timespan2->time, span1, span2);
  753. #endif
  754. if (span2 < span1)
  755. {
  756. result->time = timespan2->time;
  757. result->month = timespan2->month;
  758. }
  759. else
  760. {
  761. result->time = timespan1->time;
  762. result->month = timespan1->month;
  763. }
  764. }
  765. return result;
  766. } /* timespan_smaller() */
  767. TimeSpan   *
  768. timespan_larger(TimeSpan *timespan1, TimeSpan *timespan2)
  769. {
  770. TimeSpan   *result;
  771. double span1,
  772. span2;
  773. if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
  774. return NULL;
  775. result = palloc(sizeof(TimeSpan));
  776. if (TIMESPAN_IS_INVALID(*timespan1))
  777. {
  778. result->time = timespan2->time;
  779. result->month = timespan2->month;
  780. }
  781. else if (TIMESPAN_IS_INVALID(*timespan2))
  782. {
  783. result->time = timespan1->time;
  784. result->month = timespan1->month;
  785. }
  786. else
  787. {
  788. span1 = timespan1->time;
  789. if (timespan1->month != 0)
  790. span1 += (timespan1->month * (30.0 * 86400));
  791. span2 = timespan2->time;
  792. if (timespan2->month != 0)
  793. span2 += (timespan2->month * (30.0 * 86400));
  794. #ifdef DATEDEBUG
  795. printf("timespan_larger- months %d %d times %f %f spans %f %fn",
  796.    timespan1->month, timespan2->month, timespan1->time, timespan2->time, span1, span2);
  797. #endif
  798. if (span2 > span1)
  799. {
  800. result->time = timespan2->time;
  801. result->month = timespan2->month;
  802. }
  803. else
  804. {
  805. result->time = timespan1->time;
  806. result->month = timespan1->month;
  807. }
  808. }
  809. return result;
  810. } /* timespan_larger() */
  811. TimeSpan   *
  812. timespan_pl(TimeSpan *span1, TimeSpan *span2)
  813. {
  814. TimeSpan   *result;
  815. if ((!PointerIsValid(span1)) || (!PointerIsValid(span2)))
  816. return NULL;
  817. result = palloc(sizeof(TimeSpan));
  818. result->month = (span1->month + span2->month);
  819. result->time = JROUND(span1->time + span2->time);
  820. return result;
  821. } /* timespan_pl() */
  822. TimeSpan   *
  823. timespan_mi(TimeSpan *span1, TimeSpan *span2)
  824. {
  825. TimeSpan   *result;
  826. if ((!PointerIsValid(span1)) || (!PointerIsValid(span2)))
  827. return NULL;
  828. result = palloc(sizeof(TimeSpan));
  829. result->month = (span1->month - span2->month);
  830. result->time = JROUND(span1->time - span2->time);
  831. return result;
  832. } /* timespan_mi() */
  833. TimeSpan   *
  834. timespan_div(TimeSpan *span1, float8 *arg2)
  835. {
  836. TimeSpan   *result;
  837. if ((!PointerIsValid(span1)) || (!PointerIsValid(arg2)))
  838. return NULL;
  839. if (!PointerIsValid(result = palloc(sizeof(TimeSpan))))
  840. elog(ERROR, "Memory allocation failed, can't divide timespans", NULL);
  841. if (*arg2 == 0.0)
  842. elog(ERROR, "timespan_div:  divide by 0.0 error");
  843. result->month = rint(span1->month / *arg2);
  844. result->time = JROUND(span1->time / *arg2);
  845. return result;
  846. } /* timespan_div() */
  847. /* datetime_age()
  848.  * Calculate time difference while retaining year/month fields.
  849.  * Note that this does not result in an accurate absolute time span
  850.  * since year and month are out of context once the arithmetic
  851.  * is done.
  852.  */
  853. TimeSpan   *
  854. datetime_age(DateTime *datetime1, DateTime *datetime2)
  855. {
  856. TimeSpan   *result;
  857. DateTime dt1,
  858. dt2;
  859. double fsec,
  860. fsec1,
  861. fsec2;
  862. struct tm tt,
  863.    *tm = &tt;
  864. struct tm tt1,
  865.    *tm1 = &tt1;
  866. struct tm tt2,
  867.    *tm2 = &tt2;
  868. if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
  869. return NULL;
  870. result = palloc(sizeof(TimeSpan));
  871. dt1 = *datetime1;
  872. dt2 = *datetime2;
  873. if (DATETIME_IS_RELATIVE(dt1))
  874. dt1 = SetDateTime(dt1);
  875. if (DATETIME_IS_RELATIVE(dt2))
  876. dt2 = SetDateTime(dt2);
  877. if (DATETIME_IS_INVALID(dt1)
  878. || DATETIME_IS_INVALID(dt2))
  879. {
  880. DATETIME_INVALID(result->time);
  881. }
  882. else if ((datetime2tm(dt1, NULL, tm1, &fsec1, NULL) == 0)
  883.  && (datetime2tm(dt2, NULL, tm2, &fsec2, NULL) == 0))
  884. {
  885. fsec = (fsec1 - fsec2);
  886. tm->tm_sec = (tm1->tm_sec - tm2->tm_sec);
  887. tm->tm_min = (tm1->tm_min - tm2->tm_min);
  888. tm->tm_hour = (tm1->tm_hour - tm2->tm_hour);
  889. tm->tm_mday = (tm1->tm_mday - tm2->tm_mday);
  890. tm->tm_mon = (tm1->tm_mon - tm2->tm_mon);
  891. tm->tm_year = (tm1->tm_year - tm2->tm_year);
  892. /* flip sign if necessary... */
  893. if (dt1 < dt2)
  894. {
  895. fsec = -fsec;
  896. tm->tm_sec = -tm->tm_sec;
  897. tm->tm_min = -tm->tm_min;
  898. tm->tm_hour = -tm->tm_hour;
  899. tm->tm_mday = -tm->tm_mday;
  900. tm->tm_mon = -tm->tm_mon;
  901. tm->tm_year = -tm->tm_year;
  902. }
  903. if (tm->tm_sec < 0)
  904. {
  905. tm->tm_sec += 60;
  906. tm->tm_min--;
  907. }
  908. if (tm->tm_min < 0)
  909. {
  910. tm->tm_min += 60;
  911. tm->tm_hour--;
  912. }
  913. if (tm->tm_hour < 0)
  914. {
  915. tm->tm_hour += 24;
  916. tm->tm_mday--;
  917. }
  918. if (tm->tm_mday < 0)
  919. {
  920. if (dt1 < dt2)
  921. {
  922. tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
  923. tm->tm_mon--;
  924. }
  925. else
  926. {
  927. tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
  928. tm->tm_mon--;
  929. }
  930. }
  931. if (tm->tm_mon < 0)
  932. {
  933. tm->tm_mon += 12;
  934. tm->tm_year--;
  935. }
  936. /* recover sign if necessary... */
  937. if (dt1 < dt2)
  938. {
  939. fsec = -fsec;
  940. tm->tm_sec = -tm->tm_sec;
  941. tm->tm_min = -tm->tm_min;
  942. tm->tm_hour = -tm->tm_hour;
  943. tm->tm_mday = -tm->tm_mday;
  944. tm->tm_mon = -tm->tm_mon;
  945. tm->tm_year = -tm->tm_year;
  946. }
  947. if (tm2timespan(tm, fsec, result) != 0)
  948. elog(ERROR, "Unable to decode datetime", NULL);
  949. }
  950. else
  951. elog(ERROR, "Unable to decode datetime", NULL);
  952. return result;
  953. } /* datetime_age() */
  954. /*----------------------------------------------------------
  955.  * Conversion operators.
  956.  *---------------------------------------------------------*/
  957. /* datetime_text()
  958.  * Convert datetime to text data type.
  959.  */
  960. text *
  961. datetime_text(DateTime *datetime)
  962. {
  963. text    *result;
  964. char    *str;
  965. int len;
  966. if (!PointerIsValid(datetime))
  967. return NULL;
  968. str = datetime_out(datetime);
  969. if (!PointerIsValid(str))
  970. return NULL;
  971. len = (strlen(str) + VARHDRSZ);
  972. result = palloc(len);
  973. VARSIZE(result) = len;
  974. memmove(VARDATA(result), str, (len - VARHDRSZ));
  975. pfree(str);
  976. return result;
  977. } /* datetime_text() */
  978. /* text_datetime()
  979.  * Convert text string to datetime.
  980.  * Text type is not null terminated, so use temporary string
  981.  * then call the standard input routine.
  982.  */
  983. DateTime   *
  984. text_datetime(text *str)
  985. {
  986. DateTime   *result;
  987. int i;
  988. char    *sp,
  989.    *dp,
  990. dstr[MAXDATELEN + 1];
  991. if (!PointerIsValid(str))
  992. return NULL;
  993. sp = VARDATA(str);
  994. dp = dstr;
  995. for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
  996. *dp++ = *sp++;
  997. *dp = '';
  998. result = datetime_in(dstr);
  999. return result;
  1000. } /* text_datetime() */
  1001. /* timespan_text()
  1002.  * Convert timespan to text data type.
  1003.  */
  1004. text *
  1005. timespan_text(TimeSpan *timespan)
  1006. {
  1007. text    *result;
  1008. char    *str;
  1009. int len;
  1010. if (!PointerIsValid(timespan))
  1011. return NULL;
  1012. str = timespan_out(timespan);
  1013. if (!PointerIsValid(str))
  1014. return NULL;
  1015. len = (strlen(str) + VARHDRSZ);
  1016. result = palloc(len);
  1017. VARSIZE(result) = len;
  1018. memmove(VARDATA(result), str, (len - VARHDRSZ));
  1019. pfree(str);
  1020. return result;
  1021. } /* timespan_text() */
  1022. /* text_timespan()
  1023.  * Convert text string to timespan.
  1024.  * Text type may not be null terminated, so copy to temporary string
  1025.  * then call the standard input routine.
  1026.  */
  1027. TimeSpan   *
  1028. text_timespan(text *str)
  1029. {
  1030. TimeSpan   *result;
  1031. int i;
  1032. char    *sp,
  1033.    *dp,
  1034. dstr[MAXDATELEN + 1];
  1035. if (!PointerIsValid(str))
  1036. return NULL;
  1037. sp = VARDATA(str);
  1038. dp = dstr;
  1039. for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
  1040. *dp++ = *sp++;
  1041. *dp = '';
  1042. result = timespan_in(dstr);
  1043. return result;
  1044. } /* text_timespan() */
  1045. /* datetime_trunc()
  1046.  * Extract specified field from datetime.
  1047.  */
  1048. DateTime   *
  1049. datetime_trunc(text *units, DateTime *datetime)
  1050. {
  1051. DateTime   *result;
  1052. DateTime dt;
  1053. int tz;
  1054. int type,
  1055. val;
  1056. int i;
  1057. char    *up,
  1058.    *lp,
  1059. lowunits[MAXDATELEN + 1];
  1060. double fsec;
  1061. char    *tzn;
  1062. struct tm tt,
  1063.    *tm = &tt;
  1064. if ((!PointerIsValid(units)) || (!PointerIsValid(datetime)))
  1065. return NULL;
  1066. result = palloc(sizeof(DateTime));
  1067. up = VARDATA(units);
  1068. lp = lowunits;
  1069. for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
  1070. *lp++ = tolower(*up++);
  1071. *lp = '';
  1072. type = DecodeUnits(0, lowunits, &val);
  1073. #ifdef DATEDEBUG
  1074. if (type == IGNORE)
  1075. strcpy(lowunits, "(unknown)");
  1076. printf("datetime_trunc- units %s type=%d value=%dn", lowunits, type, val);
  1077. #endif
  1078. if (DATETIME_NOT_FINITE(*datetime))
  1079. {
  1080. #if NOT_USED
  1081. /* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */
  1082. elog(ERROR, "Datetime is not finite", NULL);
  1083. #endif
  1084. *result = 0;
  1085. }
  1086. else
  1087. {
  1088. dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
  1089. if ((type == UNITS) && (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0))
  1090. {
  1091. switch (val)
  1092. {
  1093. case DTK_MILLENIUM:
  1094. tm->tm_year = (tm->tm_year / 1000) * 1000;
  1095. case DTK_CENTURY:
  1096. tm->tm_year = (tm->tm_year / 100) * 100;
  1097. case DTK_DECADE:
  1098. tm->tm_year = (tm->tm_year / 10) * 10;
  1099. case DTK_YEAR:
  1100. tm->tm_mon = 1;
  1101. case DTK_QUARTER:
  1102. tm->tm_mon = (3 * (tm->tm_mon / 4)) + 1;
  1103. case DTK_MONTH:
  1104. tm->tm_mday = 1;
  1105. case DTK_DAY:
  1106. tm->tm_hour = 0;
  1107. case DTK_HOUR:
  1108. tm->tm_min = 0;
  1109. case DTK_MINUTE:
  1110. tm->tm_sec = 0;
  1111. case DTK_SECOND:
  1112. fsec = 0;
  1113. break;
  1114. case DTK_MILLISEC:
  1115. fsec = rint(fsec * 1000) / 1000;
  1116. break;
  1117. case DTK_MICROSEC:
  1118. fsec = rint(fsec * 1000000) / 1000000;
  1119. break;
  1120. default:
  1121. elog(ERROR, "Datetime units '%s' not supported", lowunits);
  1122. result = NULL;
  1123. }
  1124. if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
  1125. {
  1126. #ifdef USE_POSIX_TIME
  1127. tm->tm_isdst = -1;
  1128. tm->tm_year -= 1900;
  1129. tm->tm_mon -= 1;
  1130. tm->tm_isdst = -1;
  1131. mktime(tm);
  1132. tm->tm_year += 1900;
  1133. tm->tm_mon += 1;
  1134. #if defined(HAVE_TM_ZONE)
  1135. tz = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
  1136. #elif defined(HAVE_INT_TIMEZONE)
  1137. #ifdef __CYGWIN__
  1138. tz = (tm->tm_isdst ? (_timezone - 3600) : _timezone);
  1139. #else
  1140. tz = (tm->tm_isdst ? (timezone - 3600) : timezone);
  1141. #endif
  1142. #else
  1143. #error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined
  1144. #endif
  1145. #else /* !USE_POSIX_TIME */
  1146. tz = CTimeZone;
  1147. #endif
  1148. }
  1149. else
  1150. {
  1151. tm->tm_isdst = 0;
  1152. tz = 0;
  1153. }
  1154. if (tm2datetime(tm, fsec, &tz, result) != 0)
  1155. elog(ERROR, "Unable to truncate datetime to '%s'", lowunits);
  1156. #if NOT_USED
  1157. }
  1158. else if ((type == RESERV) && (val == DTK_EPOCH))
  1159. {
  1160. DATETIME_EPOCH(*result);
  1161. *result = dt - SetDateTime(*result);
  1162. #endif
  1163. }
  1164. else
  1165. {
  1166. elog(ERROR, "Datetime units '%s' not recognized", lowunits);
  1167. result = NULL;
  1168. }
  1169. }
  1170. return result;
  1171. } /* datetime_trunc() */
  1172. /* timespan_trunc()
  1173.  * Extract specified field from timespan.
  1174.  */
  1175. TimeSpan   *
  1176. timespan_trunc(text *units, TimeSpan *timespan)
  1177. {
  1178. TimeSpan   *result;
  1179. int type,
  1180. val;
  1181. int i;
  1182. char    *up,
  1183.    *lp,
  1184. lowunits[MAXDATELEN + 1];
  1185. double fsec;
  1186. struct tm tt,
  1187.    *tm = &tt;
  1188. if ((!PointerIsValid(units)) || (!PointerIsValid(timespan)))
  1189. return NULL;
  1190. result = palloc(sizeof(TimeSpan));
  1191. up = VARDATA(units);
  1192. lp = lowunits;
  1193. for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
  1194. *lp++ = tolower(*up++);
  1195. *lp = '';
  1196. type = DecodeUnits(0, lowunits, &val);
  1197. #ifdef DATEDEBUG
  1198. if (type == IGNORE)
  1199. strcpy(lowunits, "(unknown)");
  1200. printf("timespan_trunc- units %s type=%d value=%dn", lowunits, type, val);
  1201. #endif
  1202. if (TIMESPAN_IS_INVALID(*timespan))
  1203. {
  1204. #if NOT_USED
  1205. elog(ERROR, "Timespan is not finite", NULL);
  1206. #endif
  1207. result = NULL;
  1208. }
  1209. else if (type == UNITS)
  1210. {
  1211. if (timespan2tm(*timespan, tm, &fsec) == 0)
  1212. {
  1213. switch (val)
  1214. {
  1215. case DTK_MILLENIUM:
  1216. tm->tm_year = (tm->tm_year / 1000) * 1000;
  1217. case DTK_CENTURY:
  1218. tm->tm_year = (tm->tm_year / 100) * 100;
  1219. case DTK_DECADE:
  1220. tm->tm_year = (tm->tm_year / 10) * 10;
  1221. case DTK_YEAR:
  1222. tm->tm_mon = 0;
  1223. case DTK_QUARTER:
  1224. tm->tm_mon = (3 * (tm->tm_mon / 4));
  1225. case DTK_MONTH:
  1226. tm->tm_mday = 0;
  1227. case DTK_DAY:
  1228. tm->tm_hour = 0;
  1229. case DTK_HOUR:
  1230. tm->tm_min = 0;
  1231. case DTK_MINUTE:
  1232. tm->tm_sec = 0;
  1233. case DTK_SECOND:
  1234. fsec = 0;
  1235. break;
  1236. case DTK_MILLISEC:
  1237. fsec = rint(fsec * 1000) / 1000;
  1238. break;
  1239. case DTK_MICROSEC:
  1240. fsec = rint(fsec * 1000000) / 1000000;
  1241. break;
  1242. default:
  1243. elog(ERROR, "Timespan units '%s' not supported", lowunits);
  1244. result = NULL;
  1245. }
  1246. if (tm2timespan(tm, fsec, result) != 0)
  1247. elog(ERROR, "Unable to truncate timespan to '%s'", lowunits);
  1248. }
  1249. else
  1250. {
  1251. elog(NOTICE, "Timespan out of range", NULL);
  1252. result = NULL;
  1253. }
  1254. #if NOT_USED
  1255. }
  1256. else if ((type == RESERV) && (val == DTK_EPOCH))
  1257. {
  1258. *result = timespan->time;
  1259. if (timespan->month != 0)
  1260. {
  1261. *result += ((365.25 * 86400) * (timespan->month / 12));
  1262. *result += ((30 * 86400) * (timespan->month % 12));
  1263. }
  1264. #endif
  1265. }
  1266. else
  1267. {
  1268. elog(ERROR, "Timespan units '%s' not recognized", units);
  1269. result = NULL;
  1270. }
  1271. return result;
  1272. } /* timespan_trunc() */
  1273. /* datetime_part()
  1274.  * Extract specified field from datetime.
  1275.  */
  1276. float64
  1277. datetime_part(text *units, DateTime *datetime)
  1278. {
  1279. float64 result;
  1280. DateTime dt;
  1281. int tz;
  1282. int type,
  1283. val;
  1284. int i;
  1285. char    *up,
  1286.    *lp,
  1287. lowunits[MAXDATELEN + 1];
  1288. double dummy;
  1289. double fsec;
  1290. char    *tzn;
  1291. struct tm tt,
  1292.    *tm = &tt;
  1293. if ((!PointerIsValid(units)) || (!PointerIsValid(datetime)))
  1294. return NULL;
  1295. result = palloc(sizeof(float64data));
  1296. up = VARDATA(units);
  1297. lp = lowunits;
  1298. for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
  1299. *lp++ = tolower(*up++);
  1300. *lp = '';
  1301. type = DecodeUnits(0, lowunits, &val);
  1302. if (type == IGNORE)
  1303. type = DecodeSpecial(0, lowunits, &val);
  1304. #ifdef DATEDEBUG
  1305. if (type == IGNORE)
  1306. strcpy(lowunits, "(unknown)");
  1307. printf("datetime_part- units %s type=%d value=%dn", lowunits, type, val);
  1308. #endif
  1309. if (DATETIME_NOT_FINITE(*datetime))
  1310. {
  1311. #if NOT_USED
  1312. /* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */
  1313. elog(ERROR, "Datetime is not finite", NULL);
  1314. #endif
  1315. *result = 0;
  1316. }
  1317. else
  1318. {
  1319. dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
  1320. if ((type == UNITS) && (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0))
  1321. {
  1322. switch (val)
  1323. {
  1324. case DTK_TZ:
  1325. *result = tz;
  1326. break;
  1327. case DTK_TZ_MINUTE:
  1328. *result = tz / 60;
  1329. TMODULO(*result, dummy, 60e0);
  1330. break;
  1331. case DTK_TZ_HOUR:
  1332. dummy = tz;
  1333. TMODULO(dummy, *result, 3600e0);
  1334. break;
  1335. case DTK_MICROSEC:
  1336. *result = (fsec * 1000000);
  1337. break;
  1338. case DTK_MILLISEC:
  1339. *result = (fsec * 1000);
  1340. break;
  1341. case DTK_SECOND:
  1342. *result = (tm->tm_sec + fsec);
  1343. break;
  1344. case DTK_MINUTE:
  1345. *result = tm->tm_min;
  1346. break;
  1347. case DTK_HOUR:
  1348. *result = tm->tm_hour;
  1349. break;
  1350. case DTK_DAY:
  1351. *result = tm->tm_mday;
  1352. break;
  1353. case DTK_MONTH:
  1354. *result = tm->tm_mon;
  1355. break;
  1356. case DTK_QUARTER:
  1357. *result = (tm->tm_mon / 4) + 1;
  1358. break;
  1359. case DTK_YEAR:
  1360. *result = tm->tm_year;
  1361. break;
  1362. case DTK_DECADE:
  1363. *result = (tm->tm_year / 10);
  1364. break;
  1365. case DTK_CENTURY:
  1366. *result = (tm->tm_year / 100);
  1367. break;
  1368. case DTK_MILLENIUM:
  1369. *result = (tm->tm_year / 1000);
  1370. break;
  1371. default:
  1372. elog(ERROR, "Datetime units '%s' not supported", lowunits);
  1373. *result = 0;
  1374. }
  1375. }
  1376. else if (type == RESERV)
  1377. {
  1378. switch (val)
  1379. {
  1380. case DTK_EPOCH:
  1381. DATETIME_EPOCH(*result);
  1382. *result = dt - SetDateTime(*result);
  1383. break;
  1384. case DTK_DOW:
  1385. if (datetime2tm(dt, &tz, tm, &fsec, &tzn) != 0)
  1386. elog(ERROR, "Unable to encode datetime", NULL);
  1387. *result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
  1388. break;
  1389. case DTK_DOY:
  1390. if (datetime2tm(dt, &tz, tm, &fsec, &tzn) != 0)
  1391. elog(ERROR, "Unable to encode datetime", NULL);
  1392. *result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
  1393.    - date2j(tm->tm_year, 1, 1) + 1);
  1394. break;
  1395. default:
  1396. elog(ERROR, "Datetime units '%s' not supported", lowunits);
  1397. *result = 0;
  1398. }
  1399. }
  1400. else
  1401. {
  1402. elog(ERROR, "Datetime units '%s' not recognized", lowunits);
  1403. *result = 0;
  1404. }
  1405. }
  1406. return result;
  1407. } /* datetime_part() */
  1408. /* timespan_part()
  1409.  * Extract specified field from timespan.
  1410.  */
  1411. float64
  1412. timespan_part(text *units, TimeSpan *timespan)
  1413. {
  1414. float64 result;
  1415. int type,
  1416. val;
  1417. int i;
  1418. char    *up,
  1419.    *lp,
  1420. lowunits[MAXDATELEN + 1];
  1421. double fsec;
  1422. struct tm tt,
  1423.    *tm = &tt;
  1424. if ((!PointerIsValid(units)) || (!PointerIsValid(timespan)))
  1425. return NULL;
  1426. result = palloc(sizeof(float64data));
  1427. up = VARDATA(units);
  1428. lp = lowunits;
  1429. for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
  1430. *lp++ = tolower(*up++);
  1431. *lp = '';
  1432. type = DecodeUnits(0, lowunits, &val);
  1433. if (type == IGNORE)
  1434. type = DecodeSpecial(0, lowunits, &val);
  1435. #ifdef DATEDEBUG
  1436. if (type == IGNORE)
  1437. strcpy(lowunits, "(unknown)");
  1438. printf("timespan_part- units %s type=%d value=%dn", lowunits, type, val);
  1439. #endif
  1440. if (TIMESPAN_IS_INVALID(*timespan))
  1441. {
  1442. #if NOT_USED
  1443. elog(ERROR, "Timespan is not finite", NULL);
  1444. #endif
  1445. *result = 0;
  1446. }
  1447. else if (type == UNITS)
  1448. {
  1449. if (timespan2tm(*timespan, tm, &fsec) == 0)
  1450. {
  1451. switch (val)
  1452. {
  1453. case DTK_MICROSEC:
  1454. *result = (fsec * 1000000);
  1455. break;
  1456. case DTK_MILLISEC:
  1457. *result = (fsec * 1000);
  1458. break;
  1459. case DTK_SECOND:
  1460. *result = (tm->tm_sec + fsec);
  1461. break;
  1462. case DTK_MINUTE:
  1463. *result = tm->tm_min;
  1464. break;
  1465. case DTK_HOUR:
  1466. *result = tm->tm_hour;
  1467. break;
  1468. case DTK_DAY:
  1469. *result = tm->tm_mday;
  1470. break;
  1471. case DTK_MONTH:
  1472. *result = tm->tm_mon;
  1473. break;
  1474. case DTK_QUARTER:
  1475. *result = (tm->tm_mon / 4) + 1;
  1476. break;
  1477. case DTK_YEAR:
  1478. *result = tm->tm_year;
  1479. break;
  1480. case DTK_DECADE:
  1481. *result = (tm->tm_year / 10);
  1482. break;
  1483. case DTK_CENTURY:
  1484. *result = (tm->tm_year / 100);
  1485. break;
  1486. case DTK_MILLENIUM:
  1487. *result = (tm->tm_year / 1000);
  1488. break;
  1489. default:
  1490. elog(ERROR, "Timespan units '%s' not yet supported", units);
  1491. result = NULL;
  1492. }
  1493. }
  1494. else
  1495. {
  1496. elog(NOTICE, "Timespan out of range", NULL);
  1497. *result = 0;
  1498. }
  1499. }
  1500. else if ((type == RESERV) && (val == DTK_EPOCH))
  1501. {
  1502. *result = timespan->time;
  1503. if (timespan->month != 0)
  1504. {
  1505. *result += ((365.25 * 86400) * (timespan->month / 12));
  1506. *result += ((30 * 86400) * (timespan->month % 12));
  1507. }
  1508. }
  1509. else
  1510. {
  1511. elog(ERROR, "Timespan units '%s' not recognized", units);
  1512. *result = 0;
  1513. }
  1514. return result;
  1515. } /* timespan_part() */
  1516. /* datetime_zone()
  1517.  * Encode datetime type with specified time zone.
  1518.  */
  1519. text *
  1520. datetime_zone(text *zone, DateTime *datetime)
  1521. {
  1522. text    *result;
  1523. DateTime dt;
  1524. int tz;
  1525. int type,
  1526. val;
  1527. int i;
  1528. char    *up,
  1529.    *lp,
  1530. lowzone[MAXDATELEN + 1];
  1531. char    *tzn,
  1532. upzone[MAXDATELEN + 1];
  1533. double fsec;
  1534. struct tm tt,
  1535.    *tm = &tt;
  1536. char buf[MAXDATELEN + 1];
  1537. int len;
  1538. if ((!PointerIsValid(zone)) || (!PointerIsValid(datetime)))
  1539. return NULL;
  1540. up = VARDATA(zone);
  1541. lp = lowzone;
  1542. for (i = 0; i < (VARSIZE(zone) - VARHDRSZ); i++)
  1543. *lp++ = tolower(*up++);
  1544. *lp = '';
  1545. type = DecodeSpecial(0, lowzone, &val);
  1546. #ifdef DATEDEBUG
  1547. if (type == IGNORE)
  1548. strcpy(lowzone, "(unknown)");
  1549. printf("datetime_zone- zone %s type=%d value=%dn", lowzone, type, val);
  1550. #endif
  1551. if (DATETIME_NOT_FINITE(*datetime))
  1552. {
  1553. /*
  1554.  * could return null but Postgres doesn't like that currently. -
  1555.  * tgl 97/06/12
  1556.  */
  1557. elog(ERROR, "Datetime is not finite", NULL);
  1558. result = NULL;
  1559. }
  1560. else if ((type == TZ) || (type == DTZ))
  1561. {
  1562. tm->tm_isdst = ((type == DTZ) ? 1 : 0);
  1563. tz = val * 60;
  1564. dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
  1565. dt = dt2local(dt, tz);
  1566. if (datetime2tm(dt, NULL, tm, &fsec, NULL) != 0)
  1567. elog(ERROR, "Datetime not legal", NULL);
  1568. up = upzone;
  1569. lp = lowzone;
  1570. for (i = 0; *lp != ''; i++)
  1571. *up++ = toupper(*lp++);
  1572. *up = '';
  1573. tzn = upzone;
  1574. EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
  1575. len = (strlen(buf) + VARHDRSZ);
  1576. result = palloc(len);
  1577. VARSIZE(result) = len;
  1578. memmove(VARDATA(result), buf, (len - VARHDRSZ));
  1579. }
  1580. else
  1581. {
  1582. elog(ERROR, "Time zone '%s' not recognized", lowzone);
  1583. result = NULL;
  1584. }
  1585. return result;
  1586. } /* datetime_zone() */
  1587. /*****************************************************************************
  1588.  *  PRIVATE ROUTINES  *
  1589.  *****************************************************************************/
  1590. /* definitions for squeezing values into "value" */
  1591. #define ABS_SIGNBIT (char) 0200
  1592. #define VALMASK (char) 0177
  1593. #define NEG(n) ((n)|ABS_SIGNBIT)
  1594. #define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
  1595. #define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */
  1596. #define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10))
  1597. /*
  1598.  * to keep this table reasonably small, we divide the lexval for TZ and DTZ
  1599.  * entries by 10 and truncate the text field at MAXTOKLEN characters.
  1600.  * the text field is not guaranteed to be NULL-terminated.
  1601.  */
  1602. static datetkn datetktbl[] = {
  1603. /* text token lexval */
  1604. {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
  1605. {"acsst", DTZ, 63}, /* Cent. Australia */
  1606. {"acst", TZ, 57}, /* Cent. Australia */
  1607. {DA_D, ADBC, AD}, /* "ad" for years >= 0 */
  1608. {"abstime", IGNORE, 0}, /* "abstime" for pre-v6.1 "Invalid
  1609.  * Abstime" */
  1610. {"adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */
  1611. {"aesst", DTZ, 66}, /* E. Australia */
  1612. {"aest", TZ, 60}, /* Australia Eastern Std Time */
  1613. {"ahst", TZ, NEG(60)}, /* Alaska-Hawaii Std Time */
  1614. {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
  1615. {"am", AMPM, AM},
  1616. {"apr", MONTH, 4},
  1617. {"april", MONTH, 4},
  1618. {"ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */
  1619. {"at", IGNORE, 0}, /* "at" (throwaway) */
  1620. {"aug", MONTH, 8},
  1621. {"august", MONTH, 8},
  1622. {"awsst", DTZ, 54}, /* W. Australia */
  1623. {"awst", TZ, 48}, /* W. Australia */
  1624. {DB_C, ADBC, BC}, /* "bc" for years < 0 */
  1625. {"bst", TZ, 6}, /* British Summer Time */
  1626. {"bt", TZ, 18}, /* Baghdad Time */
  1627. {"cadt", DTZ, 63}, /* Central Australian DST */
  1628. {"cast", TZ, 57}, /* Central Australian ST */
  1629. {"cat", TZ, NEG(60)}, /* Central Alaska Time */
  1630. {"cct", TZ, 48}, /* China Coast */
  1631. {"cdt", DTZ, NEG(30)}, /* Central Daylight Time */
  1632. {"cet", TZ, 6}, /* Central European Time */
  1633. {"cetdst", DTZ, 12}, /* Central European Dayl.Time */
  1634. {"cst", TZ, NEG(36)}, /* Central Standard Time */
  1635. {DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
  1636. {"dec", MONTH, 12},
  1637. {"december", MONTH, 12},
  1638. {"dnt", TZ, 6}, /* Dansk Normal Tid */
  1639. {"dow", RESERV, DTK_DOW}, /* day of week */
  1640. {"doy", RESERV, DTK_DOY}, /* day of year */
  1641. {"dst", DTZMOD, 6},
  1642. {"east", TZ, NEG(60)}, /* East Australian Std Time */
  1643. {"edt", DTZ, NEG(24)}, /* Eastern Daylight Time */
  1644. {"eet", TZ, 12}, /* East. Europe, USSR Zone 1 */
  1645. {"eetdst", DTZ, 18}, /* Eastern Europe */
  1646. {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
  1647. #if USE_AUSTRALIAN_RULES
  1648. {"est", TZ, 60}, /* Australia Eastern Std Time */
  1649. #else
  1650. {"est", TZ, NEG(30)}, /* Eastern Standard Time */
  1651. #endif
  1652. {"feb", MONTH, 2},
  1653. {"february", MONTH, 2},
  1654. {"fri", DOW, 5},
  1655. {"friday", DOW, 5},
  1656. {"fst", TZ, 6}, /* French Summer Time */
  1657. {"fwt", DTZ, 12}, /* French Winter Time  */
  1658. {"gmt", TZ, 0}, /* Greenwish Mean Time */
  1659. {"gst", TZ, 60}, /* Guam Std Time, USSR Zone 9 */
  1660. {"hdt", DTZ, NEG(54)}, /* Hawaii/Alaska */
  1661. {"hmt", DTZ, 18}, /* Hellas ? ? */
  1662. {"hst", TZ, NEG(60)}, /* Hawaii Std Time */
  1663. {"idle", TZ, 72}, /* Intl. Date Line, East */
  1664. {"idlw", TZ, NEG(72)}, /* Intl. Date Line, West */
  1665. {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */
  1666. {INVALID, RESERV, DTK_INVALID},
  1667. /* "invalid" reserved for invalid time */
  1668. {"ist", TZ, 12}, /* Israel */
  1669. {"it", TZ, 21}, /* Iran Time */
  1670. {"jan", MONTH, 1},
  1671. {"january", MONTH, 1},
  1672. {"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */
  1673. {"jt", TZ, 45}, /* Java Time */
  1674. {"jul", MONTH, 7},
  1675. {"july", MONTH, 7},
  1676. {"jun", MONTH, 6},
  1677. {"june", MONTH, 6},
  1678. {"kst", TZ, 54}, /* Korea Standard Time */
  1679. {"ligt", TZ, 60}, /* From Melbourne, Australia */
  1680. {"mar", MONTH, 3},
  1681. {"march", MONTH, 3},
  1682. {"may", MONTH, 5},
  1683. {"mdt", DTZ, NEG(36)}, /* Mountain Daylight Time */
  1684. {"mest", DTZ, 12}, /* Middle Europe Summer Time */
  1685. {"met", TZ, 6}, /* Middle Europe Time */
  1686. {"metdst", DTZ, 12}, /* Middle Europe Daylight Time */
  1687. {"mewt", TZ, 6}, /* Middle Europe Winter Time */
  1688. {"mez", TZ, 6}, /* Middle Europe Zone */
  1689. {"mon", DOW, 1},
  1690. {"monday", DOW, 1},
  1691. {"mst", TZ, NEG(42)}, /* Mountain Standard Time */
  1692. {"mt", TZ, 51}, /* Moluccas Time */
  1693. {"ndt", DTZ, NEG(15)}, /* Nfld. Daylight Time */
  1694. {"nft", TZ, NEG(21)}, /* Newfoundland Standard Time */
  1695. {"nor", TZ, 6}, /* Norway Standard Time */
  1696. {"nov", MONTH, 11},
  1697. {"november", MONTH, 11},
  1698. {NOW, RESERV, DTK_NOW}, /* current transaction time */
  1699. {"nst", TZ, NEG(21)}, /* Nfld. Standard Time */
  1700. {"nt", TZ, NEG(66)}, /* Nome Time */
  1701. {"nzdt", DTZ, 78}, /* New Zealand Daylight Time */
  1702. {"nzst", TZ, 72}, /* New Zealand Standard Time */
  1703. {"nzt", TZ, 72}, /* New Zealand Time */
  1704. {"oct", MONTH, 10},
  1705. {"october", MONTH, 10},
  1706. {"on", IGNORE, 0}, /* "on" (throwaway) */
  1707. {"pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */
  1708. {"pm", AMPM, PM},
  1709. {"pst", TZ, NEG(48)}, /* Pacific Standard Time */
  1710. {"sadt", DTZ, 63}, /* S. Australian Dayl. Time */
  1711. {"sast", TZ, 57}, /* South Australian Std Time */
  1712. {"sat", DOW, 6},
  1713. {"saturday", DOW, 6},
  1714. {"sep", MONTH, 9},
  1715. {"sept", MONTH, 9},
  1716. {"september", MONTH, 9},
  1717. {"set", TZ, NEG(6)}, /* Seychelles Time ?? */
  1718. {"sst", DTZ, 12}, /* Swedish Summer Time */
  1719. {"sun", DOW, 0},
  1720. {"sunday", DOW, 0},
  1721. {"swt", TZ, 6}, /* Swedish Winter Time */
  1722. {"thu", DOW, 4},
  1723. {"thur", DOW, 4},
  1724. {"thurs", DOW, 4},
  1725. {"thursday", DOW, 4},
  1726. {TODAY, RESERV, DTK_TODAY}, /* midnight */
  1727. {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */
  1728. {"tue", DOW, 2},
  1729. {"tues", DOW, 2},
  1730. {"tuesday", DOW, 2},
  1731. {"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid
  1732.  * time */
  1733. {"ut", TZ, 0},
  1734. {"utc", TZ, 0},
  1735. {"wadt", DTZ, 48}, /* West Australian DST */
  1736. {"wast", TZ, 42}, /* West Australian Std Time */
  1737. {"wat", TZ, NEG(6)}, /* West Africa Time */
  1738. {"wdt", DTZ, 54}, /* West Australian DST */
  1739. {"wed", DOW, 3},
  1740. {"wednesday", DOW, 3},
  1741. {"weds", DOW, 3},
  1742. {"wet", TZ, 0}, /* Western Europe */
  1743. {"wetdst", DTZ, 6}, /* Western Europe */
  1744. {"wst", TZ, 48}, /* West Australian Std Time */
  1745. {"ydt", DTZ, NEG(48)}, /* Yukon Daylight Time */
  1746. {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
  1747. {"yst", TZ, NEG(54)}, /* Yukon Standard Time */
  1748. {"zp4", TZ, NEG(24)}, /* GMT +4  hours. */
  1749. {"zp5", TZ, NEG(30)}, /* GMT +5  hours. */
  1750. {"zp6", TZ, NEG(36)}, /* GMT +6  hours. */
  1751. {"z", RESERV, DTK_ZULU}, /* 00:00:00 */
  1752. {ZULU, RESERV, DTK_ZULU}, /* 00:00:00 */
  1753. };
  1754. static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
  1755. static datetkn deltatktbl[] = {
  1756. /* text token lexval */
  1757. {"@", IGNORE, 0}, /* postgres relative time prefix */
  1758. {DAGO, AGO, 0}, /* "ago" indicates negative time offset */
  1759. {"c", UNITS, DTK_CENTURY}, /* "century" relative time units */
  1760. {"cent", UNITS, DTK_CENTURY}, /* "century" relative time units */
  1761. {"centuries", UNITS, DTK_CENTURY}, /* "centuries" relative time units */
  1762. {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative time units */
  1763. {"d", UNITS, DTK_DAY}, /* "day" relative time units */
  1764. {DDAY, UNITS, DTK_DAY}, /* "day" relative time units */
  1765. {"days", UNITS, DTK_DAY}, /* "days" relative time units */
  1766. {"dec", UNITS, DTK_DECADE}, /* "decade" relative time units */
  1767. {"decs", UNITS, DTK_DECADE},/* "decades" relative time units */
  1768. {DDECADE, UNITS, DTK_DECADE}, /* "decade" relative time units */
  1769. {"decades", UNITS, DTK_DECADE}, /* "decades" relative time units */
  1770. {"h", UNITS, DTK_HOUR}, /* "hour" relative time units */
  1771. {DHOUR, UNITS, DTK_HOUR}, /* "hour" relative time units */
  1772. {"hours", UNITS, DTK_HOUR}, /* "hours" relative time units */
  1773. {"hr", UNITS, DTK_HOUR}, /* "hour" relative time units */
  1774. {"hrs", UNITS, DTK_HOUR}, /* "hours" relative time units */
  1775. {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid
  1776.  * time */
  1777. {"m", UNITS, DTK_MINUTE}, /* "minute" relative time units */
  1778. {"microsecon", UNITS, DTK_MICROSEC}, /* "microsecond" relative
  1779.  * time units */
  1780. {"mil", UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */
  1781. {"mils", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */
  1782. {"millenia", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */
  1783. {DMILLENIUM, UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */
  1784. {"millisecon", UNITS, DTK_MILLISEC}, /* relative time units */
  1785. {"min", UNITS, DTK_MINUTE}, /* "minute" relative time units */
  1786. {"mins", UNITS, DTK_MINUTE},/* "minutes" relative time units */
  1787. {"mins", UNITS, DTK_MINUTE},/* "minutes" relative time units */
  1788. {DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative time units */
  1789. {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative time units */
  1790. {"mon", UNITS, DTK_MONTH}, /* "months" relative time units */
  1791. {"mons", UNITS, DTK_MONTH}, /* "months" relative time units */
  1792. {DMONTH, UNITS, DTK_MONTH}, /* "month" relative time units */
  1793. {"months", UNITS, DTK_MONTH},
  1794. {"ms", UNITS, DTK_MILLISEC},
  1795. {"msec", UNITS, DTK_MILLISEC},
  1796. {DMILLISEC, UNITS, DTK_MILLISEC},
  1797. {"mseconds", UNITS, DTK_MILLISEC},
  1798. {"msecs", UNITS, DTK_MILLISEC},
  1799. {"qtr", UNITS, DTK_QUARTER},/* "quarter" relative time */
  1800. {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative time */
  1801. {"reltime", IGNORE, 0}, /* for pre-v6.1 "Undefined Reltime" */
  1802. {"s", UNITS, DTK_SECOND},
  1803. {"sec", UNITS, DTK_SECOND},
  1804. {DSECOND, UNITS, DTK_SECOND},
  1805. {"seconds", UNITS, DTK_SECOND},
  1806. {"secs", UNITS, DTK_SECOND},
  1807. {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
  1808. {"tz", UNITS, DTK_TZ}, /* "timezone" time offset */
  1809. {"tz_hour", UNITS, DTK_TZ_HOUR}, /* timezone hour units */
  1810. {"tz_minute", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */
  1811. {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
  1812. {"us", UNITS, DTK_MICROSEC},/* "microsecond" relative time units */
  1813. {"usec", UNITS, DTK_MICROSEC}, /* "microsecond" relative time
  1814.  * units */
  1815. {DMICROSEC, UNITS, DTK_MICROSEC}, /* "microsecond" relative time
  1816.  * units */
  1817. {"useconds", UNITS, DTK_MICROSEC}, /* "microseconds" relative time
  1818.  * units */
  1819. {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative time
  1820.  * units */
  1821. {"w", UNITS, DTK_WEEK}, /* "week" relative time units */
  1822. {DWEEK, UNITS, DTK_WEEK}, /* "week" relative time units */
  1823. {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative time units */
  1824. {"y", UNITS, DTK_YEAR}, /* "year" relative time units */
  1825. {DYEAR, UNITS, DTK_YEAR}, /* "year" relative time units */
  1826. {"years", UNITS, DTK_YEAR}, /* "years" relative time units */
  1827. {"yr", UNITS, DTK_YEAR}, /* "year" relative time units */
  1828. {"yrs", UNITS, DTK_YEAR}, /* "years" relative time units */
  1829. };
  1830. static unsigned int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
  1831. #if USE_DATE_CACHE
  1832. datetkn    *datecache[MAXDATEFIELDS] = {NULL};
  1833. datetkn    *deltacache[MAXDATEFIELDS] = {NULL};
  1834. #endif
  1835. /*
  1836.  * Calendar time to Julian date conversions.
  1837.  * Julian date is commonly used in astronomical applications,
  1838.  * since it is numerically accurate and computationally simple.
  1839.  * The algorithms here will accurately convert between Julian day
  1840.  * and calendar date for all non-negative Julian days
  1841.  * (i.e. from Nov 23, -4713 on).
  1842.  *
  1843.  * Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
  1844.  * University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
  1845.  *
  1846.  * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
  1847.  * now at Aerospace Corp. (hi, Henry!)
  1848.  *
  1849.  * These routines will be used by other date/time packages - tgl 97/02/25
  1850.  */
  1851. int
  1852. date2j(int y, int m, int d)
  1853. {
  1854. int m12 = (m - 14) / 12;
  1855. return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12
  1856. - (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075);
  1857. } /* date2j() */
  1858. void
  1859. j2date(int jd, int *year, int *month, int *day)
  1860. {
  1861. int j,
  1862. y,
  1863. m,
  1864. d;
  1865. int i,
  1866. l,
  1867. n;
  1868. l = jd + 68569;
  1869. n = (4 * l) / 146097;
  1870. l -= (146097 * n + 3) / 4;
  1871. i = (4000 * (l + 1)) / 1461001;
  1872. l += 31 - (1461 * i) / 4;
  1873. j = (80 * l) / 2447;
  1874. d = l - (2447 * j) / 80;
  1875. l = j / 11;
  1876. m = (j + 2) - (12 * l);
  1877. y = 100 * (n - 49) + i + l;
  1878. *year = y;
  1879. *month = m;
  1880. *day = d;
  1881. return;
  1882. } /* j2date() */
  1883. static int
  1884. j2day(int date)
  1885. {
  1886. int day;
  1887. day = (date + 1) % 7;
  1888. return day;
  1889. } /* j2day() */
  1890. /* datetime2tm()
  1891.  * Convert datetime data type to POSIX time structure.
  1892.  * Note that year is _not_ 1900-based, but is an explicit full value.
  1893.  * Also, month is one-based, _not_ zero-based.
  1894.  * Returns:
  1895.  *  0 on success
  1896.  * -1 on out of range
  1897.  *
  1898.  * For dates within the system-supported time_t range, convert to the
  1899.  * local time zone. If out of this range, leave as GMT. - tgl 97/05/27
  1900.  */
  1901. int
  1902. datetime2tm(DateTime dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
  1903. {
  1904. double date,
  1905. date0,
  1906. time,
  1907. sec;
  1908. time_t utime;
  1909. #ifdef USE_POSIX_TIME
  1910. struct tm  *tx;
  1911. #endif
  1912. date0 = date2j(2000, 1, 1);
  1913. time = dt;
  1914. TMODULO(time, date, 86400e0);
  1915. if (time < 0)
  1916. {
  1917. time += 86400;
  1918. date -= 1;
  1919. }
  1920. /* Julian day routine does not work for negative Julian days */
  1921. if (date < -date0)
  1922. return -1;
  1923. /* add offset to go from J2000 back to standard Julian date */
  1924. date += date0;
  1925. #ifdef DATEDEBUG
  1926. printf("datetime2tm- date is %f (%f %f)n", dt, date, time);
  1927. #endif
  1928. j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
  1929. dt2time(time, &tm->tm_hour, &tm->tm_min, &sec);
  1930. #ifdef DATEDEBUG
  1931. printf("datetime2tm- date is %d.%02d.%02dn", tm->tm_year, tm->tm_mon, tm->tm_mday);
  1932. printf("datetime2tm- time is %02d:%02d:%02.0fn", tm->tm_hour, tm->tm_min, sec);
  1933. #endif
  1934. *fsec = JROUND(sec);
  1935. TMODULO(*fsec, tm->tm_sec, 1e0);
  1936. #ifdef DATEDEBUG
  1937. printf("datetime2tm- time is %02d:%02d:%02d %.7fn", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
  1938. #endif
  1939. if (tzp != NULL)
  1940. {
  1941. if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
  1942. {
  1943. utime = (dt + (date0 - date2j(1970, 1, 1)) * 86400);
  1944. #ifdef USE_POSIX_TIME
  1945. tx = localtime(&utime);
  1946. #ifdef DATEDEBUG
  1947. #if defined(HAVE_TM_ZONE)
  1948. printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s dst=%dn",
  1949.    tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, sec,
  1950.    tx->tm_zone, tx->tm_isdst);
  1951. #elif defined(HAVE_INT_TIMEZONE)
  1952. printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s %s dst=%dn",
  1953.    tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, sec,
  1954.    tzname[0], tzname[1], tx->tm_isdst);
  1955. #else
  1956. #error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined
  1957. #endif
  1958. #endif
  1959. tm->tm_year = tx->tm_year + 1900;
  1960. tm->tm_mon = tx->tm_mon + 1;
  1961. tm->tm_mday = tx->tm_mday;
  1962. tm->tm_hour = tx->tm_hour;
  1963. tm->tm_min = tx->tm_min;
  1964. #if NOT_USED
  1965. /* XXX HACK
  1966.  * Argh! My Linux box puts in a 1 second offset for dates less than 1970
  1967.  * but only if the seconds field was non-zero. So, don't copy the seconds
  1968.  * field and instead carry forward from the original - tgl 97/06/18
  1969.  * Note that GNU/Linux uses the standard freeware zic package as do
  1970.  * many other platforms so this may not be GNU/Linux/ix86-specific.
  1971.  */
  1972. tm->tm_sec = tx->tm_sec;
  1973. #endif
  1974. tm->tm_isdst = tx->tm_isdst;
  1975. #if defined(HAVE_TM_ZONE)
  1976. tm->tm_gmtoff = tx->tm_gmtoff;
  1977. tm->tm_zone = tx->tm_zone;
  1978. *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
  1979. if (tzn != NULL)
  1980. *tzn = (char *) tm->tm_zone;
  1981. #elif defined(HAVE_INT_TIMEZONE)
  1982. #ifdef __CYGWIN__
  1983. *tzp = (tm->tm_isdst ? (_timezone - 3600) : _timezone);
  1984. #else
  1985. *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone);
  1986. #endif
  1987. if (tzn != NULL)
  1988. *tzn = tzname[(tm->tm_isdst > 0)];
  1989. #else
  1990. #error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined
  1991. #endif
  1992. #else /* !USE_POSIX_TIME */
  1993. *tzp = CTimeZone; /* V7 conventions; don't know timezone? */
  1994. if (tzn != NULL)
  1995. *tzn = CTZName;
  1996. #endif
  1997. }
  1998. else
  1999. {
  2000. *tzp = 0;
  2001. tm->tm_isdst = 0;
  2002. if (tzn != NULL)
  2003. *tzn = NULL;
  2004. }
  2005. dt = dt2local(dt, *tzp);
  2006. }
  2007. else
  2008. {
  2009. tm->tm_isdst = 0;
  2010. if (tzn != NULL)
  2011. *tzn = NULL;
  2012. }
  2013. #ifdef DATEDEBUG
  2014. printf("datetime2tm- date is %d.%02d.%02dn", tm->tm_year, tm->tm_mon, tm->tm_mday);
  2015. printf("datetime2tm- time is %02d:%02d:%02d %.7fn", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
  2016. #endif
  2017. #ifdef DATEDEBUG
  2018. #ifdef USE_POSIX_TIME
  2019. #if defined(HAVE_TM_ZONE)
  2020. printf("datetime2tm- timezone is %s; offset is %dn",
  2021.    tm->tm_zone, ((tzp != NULL) ? *tzp : 0));
  2022. #elif defined(HAVE_INT_TIMEZONE)
  2023. printf("datetime2tm- timezone is %s; offset is %d (%d); daylight is %dn",
  2024.    tzname[tm->tm_isdst != 0], ((tzp != NULL) ? *tzp : 0), CTimeZone, CDayLight);
  2025. #endif
  2026. #endif
  2027. #endif
  2028. return 0;
  2029. } /* datetime2tm() */
  2030. /* tm2datetime()
  2031.  * Convert a tm structure to a datetime data type.
  2032.  * Note that year is _not_ 1900-based, but is an explicit full value.
  2033.  * Also, month is one-based, _not_ zero-based.
  2034.  */
  2035. int
  2036. tm2datetime(struct tm * tm, double fsec, int *tzp, DateTime *result)
  2037. {
  2038. double date,
  2039. time;
  2040. /* Julian day routines are not correct for negative Julian days */
  2041. if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
  2042. return -1;
  2043. date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
  2044. time = time2t(tm->tm_hour, tm->tm_min, (tm->tm_sec + fsec));
  2045. *result = (date * 86400 + time);
  2046. #ifdef DATEDEBUG
  2047. printf("tm2datetime- date is %f (%f %f %d)n", *result, date, time, (((tm->tm_hour * 60) + tm->tm_min) * 60 + tm->tm_sec));
  2048. printf("tm2datetime- time is %f %02d:%02d:%02d %fn", time, tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
  2049. #endif
  2050. if (tzp != NULL)
  2051. *result = dt2local(*result, -(*tzp));
  2052. return 0;
  2053. } /* tm2datetime() */
  2054. /* timespan2tm()
  2055.  * Convert a timespan data type to a tm structure.
  2056.  */
  2057. static int
  2058. timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec)
  2059. {
  2060. double time;
  2061. if (span.month != 0)
  2062. {
  2063. tm->tm_year = span.month / 12;
  2064. tm->tm_mon = span.month % 12;
  2065. }
  2066. else
  2067. {
  2068. tm->tm_year = 0;
  2069. tm->tm_mon = 0;
  2070. }
  2071. #ifdef ROUND_ALL
  2072. time = JROUND(span.time);
  2073. #else
  2074. time = span.time;
  2075. #endif
  2076. TMODULO(time, tm->tm_mday, 86400e0);
  2077. TMODULO(time, tm->tm_hour, 3600e0);
  2078. TMODULO(time, tm->tm_min, 60e0);
  2079. TMODULO(time, tm->tm_sec, 1e0);
  2080. *fsec = time;
  2081. #ifdef DATEDEBUG
  2082. printf("timespan2tm- %d %f = %04d-%02d-%02d %02d:%02d:%02d %.2fn", span.month, span.time,
  2083.    tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
  2084. #endif
  2085. return 0;
  2086. } /* timespan2tm() */
  2087. static int
  2088. tm2timespan(struct tm * tm, double fsec, TimeSpan *span)
  2089. {
  2090. span->month = ((tm->tm_year * 12) + tm->tm_mon);
  2091. span->time = ((((((tm->tm_mday * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60) + tm->tm_sec);
  2092. span->time = JROUND(span->time + fsec);
  2093. #ifdef DATEDEBUG
  2094. printf("tm2timespan- %d %f = %04d-%02d-%02d %02d:%02d:%02d %.2fn", span->month, span->time,
  2095.    tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
  2096. #endif
  2097. return 0;
  2098. } /* tm2timespan() */
  2099. static DateTime
  2100. dt2local(DateTime dt, int tz)
  2101. {
  2102. dt -= tz;
  2103. dt = JROUND(dt);
  2104. return dt;
  2105. } /* dt2local() */
  2106. static double
  2107. time2t(const int hour, const int min, const double sec)
  2108. {
  2109. return (((hour * 60) + min) * 60) + sec;
  2110. } /* time2t() */
  2111. static void
  2112. dt2time(DateTime jd, int *hour, int *min, double *sec)
  2113. {
  2114. double time;
  2115. time = jd;
  2116. *hour = (time / 3600);
  2117. time -= ((*hour) * 3600);
  2118. *min = (time / 60);
  2119. time -= ((*min) * 60);
  2120. *sec = JROUND(time);
  2121. return;
  2122. } /* dt2time() */
  2123. /*
  2124.  * parse and convert date in timestr (the normal interface)
  2125.  *
  2126.  * Returns the number of seconds since epoch (J2000)
  2127.  */
  2128. /* ParseDateTime()
  2129.  * Break string into tokens based on a date/time context.
  2130.  */
  2131. int
  2132. ParseDateTime(char *timestr, char *lowstr,
  2133.   char **field, int *ftype, int maxfields, int *numfields)
  2134. {
  2135. int nf = 0;
  2136. char    *cp = timestr;
  2137. char    *lp = lowstr;
  2138. #ifdef DATEDEBUG
  2139. printf("ParseDateTime- input string is %sn", timestr);
  2140. #endif
  2141. /* outer loop through fields */
  2142. while (*cp != '')
  2143. {
  2144. field[nf] = lp;
  2145. /* leading digit? then date or time */
  2146. if (isdigit(*cp) || (*cp == '.'))
  2147. {
  2148. *lp++ = *cp++;
  2149. while (isdigit(*cp))
  2150. *lp++ = *cp++;
  2151. /* time field? */
  2152. if (*cp == ':')
  2153. {
  2154. ftype[nf] = DTK_TIME;
  2155. while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
  2156. *lp++ = *cp++;
  2157. }
  2158. /* date field? allow embedded text month */
  2159. else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
  2160. {
  2161. ftype[nf] = DTK_DATE;
  2162. while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
  2163. *lp++ = tolower(*cp++);
  2164. }
  2165. /*
  2166.  * otherwise, number only and will determine year, month, or
  2167.  * day later
  2168.  */
  2169. else
  2170. ftype[nf] = DTK_NUMBER;
  2171. }
  2172. /*
  2173.  * text? then date string, month, day of week, special, or
  2174.  * timezone
  2175.  */
  2176. else if (isalpha(*cp))
  2177. {
  2178. ftype[nf] = DTK_STRING;
  2179. *lp++ = tolower(*cp++);
  2180. while (isalpha(*cp))
  2181. *lp++ = tolower(*cp++);
  2182. /* full date string with leading text month? */
  2183. if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
  2184. {
  2185. ftype[nf] = DTK_DATE;
  2186. while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
  2187. *lp++ = tolower(*cp++);
  2188. }
  2189. /* skip leading spaces */
  2190. }
  2191. else if (isspace(*cp))
  2192. {
  2193. cp++;
  2194. continue;
  2195. /* sign? then special or numeric timezone */
  2196. }
  2197. else if ((*cp == '+') || (*cp == '-'))
  2198. {
  2199. *lp++ = *cp++;
  2200. /* soak up leading whitespace */
  2201. while (isspace(*cp))
  2202. cp++;
  2203. /* numeric timezone? */
  2204. if (isdigit(*cp))
  2205. {
  2206. ftype[nf] = DTK_TZ;
  2207. *lp++ = *cp++;
  2208. while (isdigit(*cp) || (*cp == ':'))
  2209. *lp++ = *cp++;
  2210. /* special? */
  2211. }
  2212. else if (isalpha(*cp))
  2213. {
  2214. ftype[nf] = DTK_SPECIAL;
  2215. *lp++ = tolower(*cp++);
  2216. while (isalpha(*cp))
  2217. *lp++ = tolower(*cp++);
  2218. /* otherwise something wrong... */
  2219. }
  2220. else
  2221. return -1;
  2222. /* ignore punctuation but use as delimiter */
  2223. }
  2224. else if (ispunct(*cp))
  2225. {
  2226. cp++;
  2227. continue;
  2228. }
  2229. else
  2230. return -1;
  2231. /* force in a delimiter */
  2232. *lp++ = '';
  2233. nf++;
  2234. if (nf > MAXDATEFIELDS)
  2235. return -1;
  2236. #ifdef DATEDEBUG
  2237. printf("ParseDateTime- set field[%d] to %s type %dn", (nf - 1), field[nf - 1], ftype[nf - 1]);
  2238. #endif
  2239. }
  2240. *numfields = nf;
  2241. return 0;
  2242. } /* ParseDateTime() */
  2243. /* DecodeDateTime()
  2244.  * Interpret previously parsed fields for general date and time.
  2245.  * Return 0 if full date, 1 if only time, and -1 if problems.
  2246.  * External format(s):
  2247.  * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
  2248.  * "Fri Feb-7-1997 15:23:27"
  2249.  * "Feb-7-1997 15:23:27"
  2250.  * "2-7-1997 15:23:27"
  2251.  * "1997-2-7 15:23:27"
  2252.  * "1997.038 15:23:27" (day of year 1-366)
  2253.  * Also supports input in compact time:
  2254.  * "970207 152327"
  2255.  * "97038 152327"
  2256.  *
  2257.  * Use the system-provided functions to get the current time zone
  2258.  * if not specified in the input string.
  2259.  * If the date is outside the time_t system-supported time range,
  2260.  * then assume GMT time zone. - tgl 97/05/27
  2261.  */
  2262. int
  2263. DecodeDateTime(char **field, int *ftype, int nf,
  2264.    int *dtype, struct tm * tm, double *fsec, int *tzp)
  2265. {
  2266. int fmask = 0,
  2267. tmask,
  2268. type;
  2269. int i;
  2270. int flen,
  2271. val;
  2272. int mer = HR24;
  2273. int haveTextMonth = FALSE;
  2274. int is2digits = FALSE;
  2275. int bc = FALSE;
  2276. *dtype = DTK_DATE;
  2277. tm->tm_hour = 0;
  2278. tm->tm_min = 0;
  2279. tm->tm_sec = 0;
  2280. *fsec = 0;
  2281. tm->tm_isdst = -1; /* don't know daylight savings time status
  2282.  * apriori */
  2283. if (tzp != NULL)
  2284. *tzp = 0;
  2285. for (i = 0; i < nf; i++)
  2286. {
  2287. #ifdef DATEDEBUG
  2288. printf("DecodeDateTime- field[%d] is %s (type %d)n", i, field[i], ftype[i]);
  2289. #endif
  2290. switch (ftype[i])
  2291. {
  2292. case DTK_DATE:
  2293. if (DecodeDate(field[i], fmask, &tmask, tm) != 0)
  2294. return -1;
  2295. break;
  2296. case DTK_TIME:
  2297. if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
  2298. return -1;
  2299. /*
  2300.  * check upper limit on hours; other limits checked in
  2301.  * DecodeTime()
  2302.  */
  2303. if (tm->tm_hour > 23)
  2304. return -1;
  2305. break;
  2306. case DTK_TZ:
  2307. if (tzp == NULL)
  2308. return -1;
  2309. if (DecodeTimezone(field[i], tzp) != 0)
  2310. return -1;
  2311. tmask = DTK_M(TZ);
  2312. break;
  2313. case DTK_NUMBER:
  2314. flen = strlen(field[i]);
  2315. /*
  2316.  * long numeric string and either no date or no time read
  2317.  * yet? then interpret as a concatenated date or time...
  2318.  */
  2319. if ((flen > 4) && !((fmask & DTK_DATE_M) && (fmask & DTK_TIME_M)))
  2320. {
  2321. if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
  2322. return -1;
  2323. }
  2324. /* otherwise it is a single date/time field... */
  2325. else
  2326. {
  2327. if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
  2328. return -1;
  2329. }
  2330. break;
  2331. case DTK_STRING:
  2332. case DTK_SPECIAL:
  2333. type = DecodeSpecial(i, field[i], &val);
  2334. #ifdef DATEDEBUG
  2335. printf("DecodeDateTime- special field[%d] %s type=%d value=%dn", i, field[i], type, val);
  2336. #endif
  2337. if (type == IGNORE)
  2338. continue;
  2339. tmask = DTK_M(type);
  2340. switch (type)
  2341. {
  2342. case RESERV:
  2343. #ifdef DATEDEBUG
  2344. printf("DecodeDateTime- RESERV field %s value is %dn", field[i], val);
  2345. #endif
  2346. switch (val)
  2347. {
  2348. case DTK_NOW:
  2349. tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
  2350. *dtype = DTK_DATE;
  2351. GetCurrentTime(tm);
  2352. if (tzp != NULL)
  2353. *tzp = CTimeZone;
  2354. break;
  2355. case DTK_YESTERDAY:
  2356. tmask = DTK_DATE_M;
  2357. *dtype = DTK_DATE;
  2358. GetCurrentTime(tm);
  2359. j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1),
  2360. &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
  2361. tm->tm_hour = 0;
  2362. tm->tm_min = 0;
  2363. tm->tm_sec = 0;
  2364. break;
  2365. case DTK_TODAY:
  2366. tmask = DTK_DATE_M;
  2367. *dtype = DTK_DATE;
  2368. GetCurrentTime(tm);
  2369. tm->tm_hour = 0;
  2370. tm->tm_min = 0;
  2371. tm->tm_sec = 0;
  2372. break;
  2373. case DTK_TOMORROW:
  2374. tmask = DTK_DATE_M;
  2375. *dtype = DTK_DATE;
  2376. GetCurrentTime(tm);
  2377. j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1),
  2378. &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
  2379. tm->tm_hour = 0;
  2380. tm->tm_min = 0;
  2381. tm->tm_sec = 0;
  2382. break;
  2383. case DTK_ZULU:
  2384. tmask = (DTK_TIME_M | DTK_M(TZ));
  2385. *dtype = DTK_DATE;
  2386. tm->tm_hour = 0;
  2387. tm->tm_min = 0;
  2388. tm->tm_sec = 0;
  2389. if (tzp != NULL)
  2390. *tzp = 0;
  2391. break;
  2392. default:
  2393. *dtype = val;
  2394. }
  2395. break;
  2396. case MONTH:
  2397. #ifdef DATEDEBUG
  2398. printf("DecodeDateTime- month field %s value is %dn", field[i], val);
  2399. #endif
  2400. /*
  2401.  * already have a (numeric) month? then see if we
  2402.  * can substitute...
  2403.  */
  2404. if ((fmask & DTK_M(MONTH)) && (!haveTextMonth)
  2405. && (!(fmask & DTK_M(DAY)))
  2406. && ((tm->tm_mon >= 1) && (tm->tm_mon <= 31)))
  2407. {
  2408. tm->tm_mday = tm->tm_mon;
  2409. tmask = DTK_M(DAY);
  2410. #ifdef DATEDEBUG
  2411. printf("DecodeNumber- misidentified month previously; assign as day %dn", tm->tm_mday);
  2412. #endif
  2413. }
  2414. haveTextMonth = TRUE;
  2415. tm->tm_mon = val;
  2416. break;
  2417. case DTZMOD:
  2418. /*
  2419.  * daylight savings time modifier (solves "MET
  2420.  * DST" syntax)
  2421.  */
  2422. tmask |= DTK_M(DTZ);
  2423. tm->tm_isdst = 1;
  2424. if (tzp == NULL)
  2425. return -1;
  2426. *tzp += val * 60;
  2427. break;
  2428. case DTZ:
  2429. /*
  2430.  * set mask for TZ here _or_ check for DTZ later
  2431.  * when getting default timezone
  2432.  */
  2433. tmask |= DTK_M(TZ);
  2434. tm->tm_isdst = 1;
  2435. if (tzp == NULL)
  2436. return -1;
  2437. *tzp = val * 60;
  2438. break;
  2439. case TZ:
  2440. tm->tm_isdst = 0;
  2441. if (tzp == NULL)
  2442. return -1;
  2443. *tzp = val * 60;
  2444. break;
  2445. case IGNORE:
  2446. break;
  2447. case AMPM:
  2448. mer = val;
  2449. break;
  2450. case ADBC:
  2451. bc = (val == BC);
  2452. break;
  2453. case DOW:
  2454. tm->tm_wday = val;
  2455. break;
  2456. default:
  2457. return -1;
  2458. }
  2459. break;
  2460. default:
  2461. return -1;
  2462. }
  2463. #ifdef DATEDEBUG
  2464. printf("DecodeDateTime- field[%d] %s (%08x/%08x) value is %dn",
  2465.    i, field[i], fmask, tmask, val);
  2466. #endif
  2467. if (tmask & fmask)
  2468. return -1;
  2469. fmask |= tmask;
  2470. }
  2471. /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
  2472. if (bc)
  2473. {
  2474. if (tm->tm_year > 0)
  2475. tm->tm_year = -(tm->tm_year - 1);
  2476. else
  2477. elog(ERROR, "Inconsistant use of year %04d and 'BC'", tm->tm_year);
  2478. }
  2479. else if (is2digits)
  2480. {
  2481. if (tm->tm_year < 70)
  2482. tm->tm_year += 2000;
  2483. else if (tm->tm_year < 100)
  2484. tm->tm_year += 1900;
  2485. }
  2486. if ((mer != HR24) && (tm->tm_hour > 12))
  2487. return -1;
  2488. if ((mer == AM) && (tm->tm_hour == 12))
  2489. tm->tm_hour = 0;
  2490. else if ((mer == PM) && (tm->tm_hour != 12))
  2491. tm->tm_hour += 12;
  2492. #ifdef DATEDEBUG
  2493. printf("DecodeDateTime- mask %08x (%08x)", fmask, DTK_DATE_M);
  2494. printf(" set y%04d m%02d d%02d", tm->tm_year, tm->tm_mon, tm->tm_mday);
  2495. printf(" %02d:%02d:%02dn", tm->tm_hour, tm->tm_min, tm->tm_sec);
  2496. #endif
  2497. /* do additional checking for full date specs... */
  2498. if (*dtype == DTK_DATE)
  2499. {
  2500. if ((fmask & DTK_DATE_M) != DTK_DATE_M)
  2501. return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
  2502. /*
  2503.  * check for valid day of month, now that we know for sure the
  2504.  * month and year...
  2505.  */
  2506. if ((tm->tm_mday < 1)
  2507.  || (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]))
  2508. return -1;
  2509. /* timezone not specified? then find local timezone if possible */
  2510. if (((fmask & DTK_DATE_M) == DTK_DATE_M)
  2511. && (tzp != NULL) && (!(fmask & DTK_M(TZ))))
  2512. {
  2513. /*
  2514.  * daylight savings time modifier but no standard timezone?
  2515.  * then error
  2516.  */
  2517. if (fmask & DTK_M(DTZMOD))
  2518. return -1;
  2519. if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
  2520. {
  2521. #ifdef USE_POSIX_TIME
  2522. tm->tm_year -= 1900;
  2523. tm->tm_mon -= 1;
  2524. tm->tm_isdst = -1;
  2525. mktime(tm);
  2526. tm->tm_year += 1900;
  2527. tm->tm_mon += 1;
  2528. #if defined(HAVE_TM_ZONE)
  2529. *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is
  2530.  * Sun/DEC-ism */
  2531. #elif defined(HAVE_INT_TIMEZONE)
  2532. #ifdef __CYGWIN__
  2533. *tzp = ((tm->tm_isdst > 0) ? (_timezone - 3600) : _timezone);
  2534. #else
  2535. *tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone);
  2536. #endif
  2537. #else
  2538. #error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined
  2539. #endif
  2540. #else /* !USE_POSIX_TIME */
  2541. *tzp = CTimeZone;
  2542. #endif
  2543. }
  2544. else
  2545. {
  2546. tm->tm_isdst = 0;
  2547. *tzp = 0;
  2548. }
  2549. }
  2550. }
  2551. return 0;
  2552. } /* DecodeDateTime() */
  2553. /* DecodeTimeOnly()
  2554.  * Interpret parsed string as time fields only.
  2555.  */
  2556. int
  2557. DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
  2558. {
  2559. int fmask,
  2560. tmask,
  2561. type;
  2562. int i;
  2563. int flen,
  2564. val;
  2565. int is2digits = FALSE;
  2566. int mer = HR24;
  2567. *dtype = DTK_TIME;
  2568. tm->tm_hour = 0;
  2569. tm->tm_min = 0;
  2570. tm->tm_sec = 0;
  2571. tm->tm_isdst = -1; /* don't know daylight savings time status
  2572.  * apriori */
  2573. *fsec = 0;
  2574. fmask = DTK_DATE_M;
  2575. for (i = 0; i < nf; i++)
  2576. {
  2577. #ifdef DATEDEBUG
  2578. printf("DecodeTimeOnly- field[%d] is %s (type %d)n", i, field[i], ftype[i]);
  2579. #endif
  2580. switch (ftype[i])
  2581. {
  2582. case DTK_TIME:
  2583. if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
  2584. return -1;
  2585. break;
  2586. case DTK_NUMBER:
  2587. flen = strlen(field[i]);
  2588. if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
  2589. return -1;
  2590. break;
  2591. case DTK_STRING:
  2592. case DTK_SPECIAL:
  2593. type = DecodeSpecial(i, field[i], &val);
  2594. #ifdef DATEDEBUG
  2595. printf("DecodeTimeOnly- special field[%d] %s type=%d value=%dn", i, field[i], type, val);
  2596. #endif
  2597. if (type == IGNORE)
  2598. continue;
  2599. tmask = DTK_M(type);
  2600. switch (type)
  2601. {
  2602. case RESERV:
  2603. #ifdef DATEDEBUG
  2604. printf("DecodeTimeOnly- RESERV field %s value is %dn", field[i], val);
  2605. #endif
  2606. switch (val)
  2607. {
  2608. case DTK_NOW:
  2609. tmask = DTK_TIME_M;
  2610. *dtype = DTK_TIME;
  2611. GetCurrentTime(tm);
  2612. break;
  2613. case DTK_ZULU:
  2614. tmask = (DTK_TIME_M | DTK_M(TZ));
  2615. *dtype = DTK_TIME;
  2616. tm->tm_hour = 0;
  2617. tm->tm_min = 0;
  2618. tm->tm_sec = 0;
  2619. tm->tm_isdst = 0;
  2620. break;
  2621. default:
  2622. return -1;
  2623. }
  2624. break;
  2625. case IGNORE:
  2626. break;
  2627. case AMPM:
  2628. mer = val;
  2629. break;
  2630. default:
  2631. return -1;
  2632. }
  2633. break;
  2634. default:
  2635. return -1;
  2636. }
  2637. if (tmask & fmask)
  2638. return -1;
  2639. fmask |= tmask;
  2640. #ifdef DATEDEBUG
  2641. printf("DecodeTimeOnly- field[%d] %s value is %dn", i, field[i], val);
  2642. #endif
  2643. }
  2644. #ifdef DATEDEBUG
  2645. printf("DecodeTimeOnly- mask %08x (%08x)", fmask, DTK_TIME_M);
  2646. printf(" %02d:%02d:%02d (%f)n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
  2647. #endif
  2648. if ((mer != HR24) && (tm->tm_hour > 12))
  2649. return -1;
  2650. if ((mer == AM) && (tm->tm_hour == 12))
  2651. tm->tm_hour = 0;
  2652. else if ((mer == PM) && (tm->tm_hour != 12))
  2653. tm->tm_hour += 12;
  2654. if (((tm->tm_hour < 0) || (tm->tm_hour > 23))
  2655. || ((tm->tm_min < 0) || (tm->tm_min > 59))
  2656. || ((tm->tm_sec < 0) || ((tm->tm_sec + *fsec) >= 60)))
  2657. return -1;
  2658. if ((fmask & DTK_TIME_M) != DTK_TIME_M)
  2659. return -1;
  2660. return 0;
  2661. } /* DecodeTimeOnly() */
  2662. /* DecodeDate()
  2663.  * Decode date string which includes delimiters.
  2664.  * Insist on a complete set of fields.
  2665.  */
  2666. static int
  2667. DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
  2668. {
  2669. double fsec;
  2670. int nf = 0;
  2671. int i,
  2672. len;
  2673. int bc = FALSE;
  2674. int is2digits = FALSE;
  2675. int type,
  2676. val,
  2677. dmask = 0;
  2678. char    *field[MAXDATEFIELDS];
  2679. /* parse this string... */
  2680. while ((*str != '') && (nf < MAXDATEFIELDS))
  2681. {
  2682. /* skip field separators */
  2683. while (!isalnum(*str))
  2684. str++;
  2685. field[nf] = str;
  2686. if (isdigit(*str))
  2687. {
  2688. while (isdigit(*str))
  2689. str++;
  2690. }
  2691. else if (isalpha(*str))
  2692. {
  2693. while (isalpha(*str))
  2694. str++;
  2695. }
  2696. if (*str != '')
  2697. *str++ = '';
  2698. nf++;
  2699. }
  2700. #if 0
  2701. /* don't allow too many fields */
  2702. if (nf > 3)
  2703. return -1;
  2704. #endif
  2705. *tmask = 0;
  2706. /* look first for text fields, since that will be unambiguous month */
  2707. for (i = 0; i < nf; i++)
  2708. {
  2709. if (isalpha(*field[i]))
  2710. {
  2711. type = DecodeSpecial(i, field[i], &val);
  2712. if (type == IGNORE)
  2713. continue;
  2714. dmask = DTK_M(type);
  2715. switch (type)
  2716. {
  2717. case MONTH:
  2718. #ifdef DATEDEBUG
  2719. printf("DecodeDate- month field %s value is %dn", field[i], val);
  2720. #endif
  2721. tm->tm_mon = val;
  2722. break;
  2723. case ADBC:
  2724. bc = (val == BC);
  2725. break;
  2726. default:
  2727. #ifdef DATEDEBUG
  2728. printf("DecodeDate- illegal field %s value is %dn", field[i], val);
  2729. #endif
  2730. return -1;
  2731. }
  2732. if (fmask & dmask)
  2733. return -1;
  2734. fmask |= dmask;
  2735. *tmask |= dmask;
  2736. /* mark this field as being completed */
  2737. field[i] = NULL;
  2738. }
  2739. }
  2740. /* now pick up remaining numeric fields */
  2741. for (i = 0; i < nf; i++)
  2742. {
  2743. if (field[i] == NULL)
  2744. continue;
  2745. if ((len = strlen(field[i])) <= 0)
  2746. return -1;
  2747. if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits) != 0)
  2748. return -1;
  2749. if (fmask & dmask)
  2750. return -1;
  2751. fmask |= dmask;
  2752. *tmask |= dmask;
  2753. }
  2754. if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
  2755. return -1;
  2756. /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
  2757. if (bc)
  2758. {
  2759. if (tm->tm_year > 0)
  2760. tm->tm_year = -(tm->tm_year - 1);
  2761. else
  2762. elog(ERROR, "Inconsistant use of year %04d and 'BC'", tm->tm_year);
  2763. }
  2764. else if (is2digits)
  2765. {
  2766. if (tm->tm_year < 70)
  2767. tm->tm_year += 2000;
  2768. else if (tm->tm_year < 100)
  2769. tm->tm_year += 1900;
  2770. }
  2771. return 0;
  2772. } /* DecodeDate() */
  2773. /* DecodeTime()
  2774.  * Decode time string which includes delimiters.
  2775.  * Only check the lower limit on hours, since this same code
  2776.  * can be used to represent time spans.
  2777.  */
  2778. static int
  2779. DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
  2780. {
  2781. char    *cp;
  2782. *tmask = DTK_TIME_M;
  2783. tm->tm_hour = strtol(str, &cp, 10);
  2784. if (*cp != ':')
  2785. return -1;
  2786. str = cp + 1;
  2787. tm->tm_min = strtol(str, &cp, 10);
  2788. if (*cp == '')
  2789. {
  2790. tm->tm_sec = 0;
  2791. *fsec = 0;
  2792. }
  2793. else if (*cp != ':')
  2794. {
  2795. return -1;
  2796. }
  2797. else
  2798. {
  2799. str = cp + 1;
  2800. tm->tm_sec = strtol(str, &cp, 10);
  2801. if (*cp == '')
  2802. *fsec = 0;
  2803. else if (*cp == '.')
  2804. {
  2805. str = cp;
  2806. *fsec = strtod(str, &cp);
  2807. if (cp == str)
  2808. return -1;
  2809. }
  2810. else
  2811. return -1;
  2812. }
  2813. /* do a sanity check */
  2814. if ((tm->tm_hour < 0)
  2815. || (tm->tm_min < 0) || (tm->tm_min > 59)
  2816. || (tm->tm_sec < 0) || (tm->tm_sec > 59))
  2817. return -1;
  2818. return 0;
  2819. } /* DecodeTime() */
  2820. /* DecodeNumber()
  2821.  * Interpret numeric field as a date value in context.
  2822.  */
  2823. static int
  2824. DecodeNumber(int flen, char *str, int fmask,
  2825.  int *tmask, struct tm * tm, double *fsec, int *is2digits)
  2826. {
  2827. int val;
  2828. char    *cp;
  2829. *tmask = 0;
  2830. val = strtol(str, &cp, 10);
  2831. if (cp == str)
  2832. return -1;
  2833. if (*cp == '.')
  2834. {
  2835. *fsec = strtod(cp, &cp);
  2836. if (*cp != '')
  2837. return -1;
  2838. }
  2839. #ifdef DATEDEBUG
  2840. printf("DecodeNumber- %s is %d fmask=%08x tmask=%08xn", str, val, fmask, *tmask);
  2841. #endif
  2842. /* Special case day of year? */
  2843. if ((flen == 3) && (fmask & DTK_M(YEAR))
  2844. && ((val >= 1) && (val <= 366)))
  2845. {
  2846. *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
  2847. tm->tm_yday = val;
  2848. j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1),
  2849.    &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
  2850. }
  2851. /*
  2852.  * Enough digits to be unequivocal year? Used to test for 4 digits or
  2853.  * more, but we now test first for a three-digit doy so anything
  2854.  * bigger than two digits had better be an explicit year. - thomas
  2855.  * 1999-01-09
  2856.  */
  2857. else if (flen > 2)
  2858. {
  2859. #ifdef DATEDEBUG
  2860. printf("DecodeNumber- match %d (%s) as yearn", val, str);
  2861. #endif
  2862. *tmask = DTK_M(YEAR);
  2863. /* already have a year? then see if we can substitute... */
  2864. if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
  2865. && ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
  2866. {
  2867. tm->tm_mday = tm->tm_year;
  2868. *tmask = DTK_M(DAY);
  2869. #ifdef DATEDEBUG
  2870. printf("DecodeNumber- misidentified year previously; assign as day %dn", tm->tm_mday);
  2871. #endif
  2872. }
  2873. tm->tm_year = val;
  2874. }
  2875. /* already have year? then could be month */
  2876. else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
  2877.  && ((val >= 1) && (val <= 12)))
  2878. {
  2879. #ifdef DATEDEBUG
  2880. printf("DecodeNumber- match %d (%s) as monthn", val, str);
  2881. #endif
  2882. *tmask = DTK_M(MONTH);
  2883. tm->tm_mon = val;
  2884. /* no year and EuroDates enabled? then could be day */
  2885. }
  2886. else if ((EuroDates || (fmask & DTK_M(MONTH)))
  2887.  && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
  2888.  && ((val >= 1) && (val <= 31)))
  2889. {
  2890. #ifdef DATEDEBUG
  2891. printf("DecodeNumber- match %d (%s) as dayn", val, str);
  2892. #endif
  2893. *tmask = DTK_M(DAY);
  2894. tm->tm_mday = val;
  2895. }
  2896. else if ((!(fmask & DTK_M(MONTH)))
  2897.  && ((val >= 1) && (val <= 12)))
  2898. {
  2899. #ifdef DATEDEBUG
  2900. printf("DecodeNumber- (2) match %d (%s) as monthn", val, str);
  2901. #endif
  2902. *tmask = DTK_M(MONTH);
  2903. tm->tm_mon = val;
  2904. }
  2905. else if ((!(fmask & DTK_M(DAY)))
  2906.  && ((val >= 1) && (val <= 31)))
  2907. {
  2908. #ifdef DATEDEBUG
  2909. printf("DecodeNumber- (2) match %d (%s) as dayn", val, str);
  2910. #endif
  2911. *tmask = DTK_M(DAY);
  2912. tm->tm_mday = val;
  2913. }
  2914. else if (!(fmask & DTK_M(YEAR)))
  2915. {
  2916. #ifdef DATEDEBUG
  2917. printf("DecodeNumber- (2) match %d (%s) as yearn", val, str);
  2918. #endif
  2919. *tmask = DTK_M(YEAR);
  2920. tm->tm_year = val;
  2921. /* adjust ONLY if exactly two digits... */
  2922. *is2digits = (flen == 2);
  2923. }
  2924. else
  2925. return -1;
  2926. return 0;
  2927. } /* DecodeNumber() */
  2928. /* DecodeNumberField()
  2929.  * Interpret numeric string as a concatenated date field.
  2930.  */
  2931. static int
  2932. DecodeNumberField(int len, char *str, int fmask,
  2933. int *tmask, struct tm * tm, double *fsec, int *is2digits)
  2934. {
  2935. char    *cp;
  2936. /* yyyymmdd? */
  2937. if (len == 8)
  2938. {
  2939. #ifdef DATEDEBUG
  2940. printf("DecodeNumberField- %s is 8 character date fmask=%08x tmask=%08xn", str, fmask, *tmask);
  2941. #endif
  2942. *tmask = DTK_DATE_M;
  2943. tm->tm_mday = atoi(str + 6);
  2944. *(str + 6) = '';
  2945. tm->tm_mon = atoi(str + 4);
  2946. *(str + 4) = '';
  2947. tm->tm_year = atoi(str + 0);
  2948. /* yymmdd or hhmmss? */
  2949. }
  2950. else if (len == 6)
  2951. {
  2952. #ifdef DATEDEBUG
  2953. printf("DecodeNumberField- %s is 6 characters fmask=%08x tmask=%08xn", str, fmask, *tmask);
  2954. #endif
  2955. if (fmask & DTK_DATE_M)
  2956. {
  2957. #ifdef DATEDEBUG
  2958. printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08xn", str, fmask, *tmask);
  2959. #endif
  2960. *tmask = DTK_TIME_M;
  2961. tm->tm_sec = atoi(str + 4);
  2962. *(str + 4) = '';
  2963. tm->tm_min = atoi(str + 2);
  2964. *(str + 2) = '';
  2965. tm->tm_hour = atoi(str + 0);
  2966. }
  2967. else
  2968. {
  2969. #ifdef DATEDEBUG
  2970. printf("DecodeNumberField- %s is date field fmask=%08x tmask=%08xn", str, fmask, *tmask);
  2971. #endif
  2972. *tmask = DTK_DATE_M;
  2973. tm->tm_mday = atoi(str + 4);
  2974. *(str + 4) = '';
  2975. tm->tm_mon = atoi(str + 2);
  2976. *(str + 2) = '';
  2977. tm->tm_year = atoi(str + 0);
  2978. *is2digits = TRUE;
  2979. }
  2980. }
  2981. else if ((len == 5) && !(fmask & DTK_DATE_M))
  2982. {
  2983. #ifdef DATEDEBUG
  2984. printf("DecodeNumberField- %s is 5 characters fmask=%08x tmask=%08xn", str, fmask, *tmask);
  2985. #endif
  2986. *tmask = DTK_DATE_M;
  2987. tm->tm_mday = atoi(str + 2);
  2988. *(str + 2) = '';
  2989. tm->tm_mon = 1;
  2990. tm->tm_year = atoi(str + 0);
  2991. *is2digits = TRUE;
  2992. }
  2993. else if (strchr(str, '.') != NULL)
  2994. {
  2995. #ifdef DATEDEBUG
  2996. printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08xn", str, fmask, *tmask);
  2997. #endif
  2998. *tmask = DTK_TIME_M;
  2999. tm->tm_sec = strtod((str + 4), &cp);
  3000. if (cp == (str + 4))
  3001. return -1;
  3002. if (*cp == '.')
  3003. *fsec = strtod(cp, NULL);
  3004. *(str + 4) = '';
  3005. tm->tm_min = strtod((str + 2), &cp);
  3006. *(str + 2) = '';
  3007. tm->tm_hour = strtod((str + 0), &cp);
  3008. }
  3009. else
  3010. return -1;
  3011. return 0;
  3012. } /* DecodeNumberField() */
  3013. /* DecodeTimezone()
  3014.  * Interpret string as a numeric timezone.
  3015.  */
  3016. static int
  3017. DecodeTimezone(char *str, int *tzp)
  3018. {
  3019. int tz;
  3020. int hr,
  3021. min;
  3022. char    *cp;
  3023. int len;
  3024. /* assume leading character is "+" or "-" */
  3025. hr = strtol((str + 1), &cp, 10);
  3026. /* explicit delimiter? */
  3027. if (*cp == ':')
  3028. {
  3029. min = strtol((cp + 1), &cp, 10);
  3030. /* otherwise, might have run things together... */
  3031. }
  3032. else if ((*cp == '') && ((len = strlen(str)) > 3))
  3033. {
  3034. min = strtol((str + len - 2), &cp, 10);
  3035. *(str + len - 2) = '';
  3036. hr = strtol((str + 1), &cp, 10);
  3037. }
  3038. else
  3039. min = 0;
  3040. tz = (hr * 60 + min) * 60;
  3041. if (*str == '-')
  3042. tz = -tz;
  3043. *tzp = -tz;
  3044. return *cp != '';
  3045. } /* DecodeTimezone() */
  3046. /* DecodeSpecial()
  3047.  * Decode text string using lookup table.
  3048.  * Implement a cache lookup since it is likely that dates
  3049.  * will be related in format.
  3050.  */
  3051. static int
  3052. DecodeSpecial(int field, char *lowtoken, int *val)
  3053. {
  3054. int type;
  3055. datetkn    *tp;
  3056. #if USE_DATE_CACHE
  3057. if ((datecache[field] != NULL)
  3058. && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0))
  3059. tp = datecache[field];
  3060. else
  3061. {
  3062. #endif
  3063. tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
  3064. #if USE_DATE_CACHE
  3065. }
  3066. datecache[field] = tp;
  3067. #endif
  3068. if (tp == NULL)
  3069. {
  3070. type = IGNORE;
  3071. *val = 0;
  3072. }
  3073. else
  3074. {
  3075. type = tp->type;
  3076. switch (type)
  3077. {
  3078. case TZ:
  3079. case DTZ:
  3080. case DTZMOD:
  3081. *val = FROMVAL(tp);
  3082. break;
  3083. default:
  3084. *val = tp->value;
  3085. break;
  3086. }
  3087. }
  3088. return type;
  3089. } /* DecodeSpecial() */
  3090. /* DecodeDateDelta()
  3091.  * Interpret previously parsed fields for general time interval.
  3092.  * Return 0 if decoded and -1 if problems.
  3093.  *
  3094.  * Allow "date" field DTK_DATE since this could be just
  3095.  * an unsigned floating point number. - thomas 1997-11-16
  3096.  *
  3097.  * Allow ISO-style time span, with implicit units on number of days
  3098.  * preceeding an hh:mm:ss field. - thomas 1998-04-30
  3099.  */
  3100. int
  3101. DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
  3102. {
  3103. int is_before = FALSE;
  3104. char    *cp;
  3105. int fmask = 0,
  3106. tmask,
  3107. type;
  3108. int i;
  3109. int flen,
  3110. val;
  3111. double fval;
  3112. double sec;
  3113. *dtype = DTK_DELTA;
  3114. type = DTK_SECOND;
  3115. tm->tm_year = 0;
  3116. tm->tm_mon = 0;
  3117. tm->tm_mday = 0;
  3118. tm->tm_hour = 0;
  3119. tm->tm_min = 0;
  3120. tm->tm_sec = 0;
  3121. *fsec = 0;
  3122. /* read through list backwards to pick up units before values */
  3123. for (i = nf - 1; i >= 0; i--)
  3124. {
  3125. #ifdef DATEDEBUG
  3126. printf("DecodeDateDelta- field[%d] is %s (type %d)n", i, field[i], ftype[i]);
  3127. #endif
  3128. switch (ftype[i])
  3129. {
  3130. case DTK_TIME:
  3131. if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
  3132. return -1;
  3133. type = DTK_DAY;
  3134. break;
  3135. case DTK_TZ:
  3136. /*
  3137.  * Timezone is a token with a leading sign character and
  3138.  * otherwise the same as a non-signed numeric field
  3139.  */
  3140. case DTK_DATE:
  3141. case DTK_NUMBER:
  3142. val = strtol(field[i], &cp, 10);
  3143. if (*cp == '.')
  3144. {
  3145. fval = strtod(cp, &cp);
  3146. if (*cp != '')
  3147. return -1;
  3148. if (val < 0)
  3149. fval = -(fval);
  3150. }
  3151. else if (*cp == '')
  3152. fval = 0;
  3153. else
  3154. return -1;
  3155. flen = strlen(field[i]);
  3156. tmask = 0; /* DTK_M(type); */
  3157. switch (type)
  3158. {
  3159. case DTK_MICROSEC:
  3160. *fsec += ((val + fval) * 1e-6);
  3161. break;
  3162. case DTK_MILLISEC:
  3163. *fsec += ((val + fval) * 1e-3);
  3164. break;
  3165. case DTK_SECOND:
  3166. tm->tm_sec += val;
  3167. *fsec += fval;
  3168. tmask = DTK_M(SECOND);
  3169. break;
  3170. case DTK_MINUTE:
  3171. tm->tm_min += val;
  3172. if (fval != 0)
  3173. tm->tm_sec += (fval * 60);
  3174. tmask = DTK_M(MINUTE);
  3175. break;
  3176. case DTK_HOUR:
  3177. tm->tm_hour += val;
  3178. if (fval != 0)
  3179. tm->tm_sec += (fval * 3600);
  3180. tmask = DTK_M(HOUR);
  3181. break;
  3182. case DTK_DAY:
  3183. tm->tm_mday += val;
  3184. if (fval != 0)
  3185. tm->tm_sec += (fval * 86400);
  3186. tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
  3187. break;
  3188. case DTK_WEEK:
  3189. tm->tm_mday += val * 7;
  3190. if (fval != 0)
  3191. tm->tm_sec += (fval * (7 * 86400));
  3192. tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
  3193. break;
  3194. case DTK_MONTH:
  3195. tm->tm_mon += val;
  3196. if (fval != 0)
  3197. tm->tm_sec += (fval * (30 * 86400));
  3198. tmask = DTK_M(MONTH);
  3199. break;
  3200. case DTK_YEAR:
  3201. tm->tm_year += val;
  3202. if (fval != 0)
  3203. tm->tm_mon += (fval * 12);
  3204. tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
  3205. break;
  3206. case DTK_DECADE:
  3207. tm->tm_year += val * 10;
  3208. if (fval != 0)
  3209. tm->tm_mon += (fval * 120);
  3210. tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
  3211. break;
  3212. case DTK_CENTURY:
  3213. tm->tm_year += val * 100;
  3214. if (fval != 0)
  3215. tm->tm_mon += (fval * 1200);
  3216. tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
  3217. break;
  3218. case DTK_MILLENIUM:
  3219. tm->tm_year += val * 1000;
  3220. if (fval != 0)
  3221. tm->tm_mon += (fval * 12000);
  3222. tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
  3223. break;
  3224. default:
  3225. return -1;
  3226. }
  3227. break;
  3228. case DTK_STRING:
  3229. case DTK_SPECIAL:
  3230. type = DecodeUnits(i, field[i], &val);
  3231. #ifdef DATEDEBUG
  3232. printf("DecodeDateDelta- special field[%d] %s type=%d value=%dn", i, field[i], type, val);
  3233. #endif
  3234. if (type == IGNORE)
  3235. continue;
  3236. tmask = 0; /* DTK_M(type); */
  3237. switch (type)
  3238. {
  3239. case UNITS:
  3240. #ifdef DATEDEBUG
  3241. printf("DecodeDateDelta- UNITS field %s value is %dn", field[i], val);
  3242. #endif
  3243. type = val;
  3244. break;
  3245. case AGO:
  3246. is_before = TRUE;
  3247. type = val;
  3248. break;
  3249. case RESERV:
  3250. tmask = (DTK_DATE_M || DTK_TIME_M);
  3251. *dtype = val;
  3252. break;
  3253. default:
  3254. return -1;
  3255. }
  3256. break;
  3257. default:
  3258. return -1;
  3259. }
  3260. #ifdef DATEDEBUG
  3261. printf("DecodeDateDelta- (%08x/%08x) field[%d] %s value is %dn",
  3262.    fmask, tmask, i, field[i], val);
  3263. #endif
  3264. if (tmask & fmask)
  3265. return -1;
  3266. fmask |= tmask;
  3267. }
  3268. if (*fsec != 0)
  3269. {
  3270. TMODULO(*fsec, sec, 1e0);
  3271. tm->tm_sec += sec;
  3272. }
  3273. if (is_before)
  3274. {
  3275. *fsec = -(*fsec);
  3276. tm->tm_sec = -(tm->tm_sec);
  3277. tm->tm_min = -(tm->tm_min);
  3278. tm->tm_hour = -(tm->tm_hour);
  3279. tm->tm_mday = -(tm->tm_mday);
  3280. tm->tm_mon = -(tm->tm_mon);
  3281. tm->tm_year = -(tm->tm_year);
  3282. }
  3283. #ifdef DATEDEBUG
  3284. printf("DecodeDateDelta- mask %08x (%08x)", fmask, DTK_DATE_M);
  3285. printf(" set y%04d m%02d d%02d", tm->tm_year, tm->tm_mon, tm->tm_mday);
  3286. printf(" %02d:%02d:%02dn", tm->tm_hour, tm->tm_min, tm->tm_sec);
  3287. #endif
  3288. /* ensure that at least one time field has been found */
  3289. return (fmask != 0) ? 0 : -1;
  3290. } /* DecodeDateDelta() */
  3291. /* DecodeUnits()
  3292.  * Decode text string using lookup table.
  3293.  * This routine supports time interval decoding.
  3294.  */
  3295. static int
  3296. DecodeUnits(int field, char *lowtoken, int *val)
  3297. {
  3298. int type;
  3299. datetkn    *tp;
  3300. #if USE_DATE_CACHE
  3301. if ((deltacache[field] != NULL)
  3302. && (strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0))
  3303. tp = deltacache[field];
  3304. else
  3305. {
  3306. #endif
  3307. tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
  3308. #if USE_DATE_CACHE
  3309. }
  3310. deltacache[field] = tp;
  3311. #endif
  3312. if (tp == NULL)
  3313. {
  3314. type = IGNORE;
  3315. *val = 0;
  3316. }
  3317. else
  3318. {
  3319. type = tp->type;
  3320. if ((type == TZ) || (type == DTZ))
  3321. *val = FROMVAL(tp);
  3322. else
  3323. *val = tp->value;
  3324. }
  3325. return type;
  3326. } /* DecodeUnits() */
  3327. /* datebsearch()
  3328.  * Binary search -- from Knuth (6.2.1) Algorithm B.  Special case like this
  3329.  * is WAY faster than the generic bsearch().
  3330.  */
  3331. static datetkn *
  3332. datebsearch(char *key, datetkn *base, unsigned int nel)
  3333. {
  3334. datetkn    *last = base + nel - 1,
  3335.    *position;
  3336. int result;
  3337. while (last >= base)
  3338. {
  3339. position = base + ((last - base) >> 1);
  3340. result = key[0] - position->token[0];
  3341. if (result == 0)
  3342. {
  3343. result = strncmp(key, position->token, TOKMAXLEN);
  3344. if (result == 0)
  3345. return position;
  3346. }
  3347. if (result < 0)
  3348. last = position - 1;
  3349. else
  3350. base = position + 1;
  3351. }
  3352. return NULL;
  3353. }
  3354. /* EncodeSpecialDateTime()
  3355.  * Convert reserved datetime data type to string.
  3356.  */
  3357. static int
  3358. EncodeSpecialDateTime(DateTime dt, char *str)
  3359. {
  3360. if (DATETIME_IS_RESERVED(dt))
  3361. {
  3362. if (DATETIME_IS_INVALID(dt))
  3363. {
  3364. strcpy(str, INVALID);
  3365. }
  3366. else if (DATETIME_IS_NOBEGIN(dt))
  3367. {
  3368. strcpy(str, EARLY);
  3369. }
  3370. else if (DATETIME_IS_NOEND(dt))
  3371. {
  3372. strcpy(str, LATE);
  3373. }
  3374. else if (DATETIME_IS_CURRENT(dt))
  3375. {
  3376. strcpy(str, DCURRENT);
  3377. }
  3378. else if (DATETIME_IS_EPOCH(dt))
  3379. {
  3380. strcpy(str, EPOCH);
  3381. }
  3382. else
  3383. {
  3384. #ifdef DATEDEBUG
  3385. printf("EncodeSpecialDateTime- unrecognized daten");
  3386. #endif
  3387. strcpy(str, INVALID);
  3388. }
  3389. return TRUE;
  3390. }
  3391. return FALSE;
  3392. } /* EncodeSpecialDateTime() */
  3393. /* EncodeDateOnly()
  3394.  * Encode date as local time.
  3395.  */
  3396. int
  3397. EncodeDateOnly(struct tm * tm, int style, char *str)
  3398. {
  3399. if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
  3400. return -1;
  3401. switch (style)
  3402. {
  3403. /* compatible with ISO date formats */
  3404. case USE_ISO_DATES:
  3405. if (tm->tm_year > 0)
  3406. sprintf(str, "%04d-%02d-%02d",
  3407. tm->tm_year, tm->tm_mon, tm->tm_mday);
  3408. else
  3409. sprintf(str, "%04d-%02d-%02d %s",
  3410.   -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
  3411. break;
  3412. /* compatible with Oracle/Ingres date formats */
  3413. case USE_SQL_DATES:
  3414. if (EuroDates)
  3415. sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
  3416. else
  3417. sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
  3418. if (tm->tm_year > 0)
  3419. sprintf((str + 5), "/%04d", tm->tm_year);
  3420. else
  3421. sprintf((str + 5), "/%04d %s", -(tm->tm_year - 1), "BC");
  3422. break;
  3423. /* German-style date format */
  3424. case USE_GERMAN_DATES:
  3425. sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
  3426. if (tm->tm_year > 0)
  3427. sprintf((str + 5), ".%04d", tm->tm_year);
  3428. else
  3429. sprintf((str + 5), ".%04d %s", -(tm->tm_year - 1), "BC");
  3430. break;
  3431. /* traditional date-only style for Postgres */
  3432. case USE_POSTGRES_DATES:
  3433. default:
  3434. if (EuroDates)
  3435. sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
  3436. else
  3437. sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
  3438. if (tm->tm_year > 0)
  3439. sprintf((str + 5), "-%04d", tm->tm_year);
  3440. else
  3441. sprintf((str + 5), "-%04d %s", -(tm->tm_year - 1), "BC");
  3442. break;
  3443. }
  3444. #ifdef DATEDEBUG
  3445. printf("EncodeDateOnly- date result is %sn", str);
  3446. #endif
  3447. return TRUE;
  3448. } /* EncodeDateOnly() */
  3449. /* EncodeTimeOnly()
  3450.  * Encode time fields only.
  3451.  */
  3452. int
  3453. EncodeTimeOnly(struct tm * tm, double fsec, int style, char *str)
  3454. {
  3455. double sec;
  3456. if ((tm->tm_hour < 0) || (tm->tm_hour > 24))
  3457. return -1;
  3458. sec = (tm->tm_sec + fsec);
  3459. sprintf(str, "%02d:%02d:", tm->tm_hour, tm->tm_min);
  3460. sprintf((str + 6), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec);
  3461. #ifdef DATEDEBUG
  3462. printf("EncodeTimeOnly- time result is %sn", str);
  3463. #endif
  3464. return TRUE;
  3465. } /* EncodeTimeOnly() */
  3466. /* EncodeDateTime()
  3467.  * Encode date and time interpreted as local time.
  3468.  * Support several date styles:
  3469.  * Postgres - day mon hh:mm:ss yyyy tz
  3470.  * SQL - mm/dd/yyyy hh:mm:ss.ss tz
  3471.  * ISO - yyyy-mm-dd hh:mm:ss+/-tz
  3472.  * German - dd.mm/yyyy hh:mm:ss tz
  3473.  * Variants (affects order of month and day for Postgres and SQL styles):
  3474.  * US - mm/dd/yyyy
  3475.  * European - dd/mm/yyyy
  3476.  */
  3477. int
  3478. EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str)
  3479. {
  3480. int day,
  3481. hour,
  3482. min;
  3483. double sec;
  3484. if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
  3485. return -1;
  3486. sec = (tm->tm_sec + fsec);
  3487. #ifdef DATEDEBUG
  3488. #ifdef USE_POSIX_TIME
  3489. #if defined(HAVE_TM_ZONE)
  3490. printf("EncodeDateTime- timezone is %s (%s); offset is %ld (%d); daylight is %d (%d)n",
  3491.    *tzn, tm->tm_zone, (-tm->tm_gmtoff), CTimeZone, tm->tm_isdst, CDayLight);
  3492. #elif defined(HAVE_INT_TIMEZONE)
  3493. printf("EncodeDateTime- timezone is %s (%s); offset is %d (%d); daylight is %d (%d)n",
  3494.    *tzn, tzname[0], *tzp, CTimeZone, tm->tm_isdst, CDayLight);
  3495. #else
  3496. #error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined
  3497. #endif
  3498. #else
  3499. printf("EncodeDateTime- timezone is %s (%s); offset is %d; daylight is %dn",
  3500.    *tzn, CTZName, CTimeZone, CDayLight);
  3501. #endif
  3502. #endif
  3503. switch (style)
  3504. {
  3505. /* compatible with ISO date formats */
  3506. case USE_ISO_DATES:
  3507. if (tm->tm_year > 0)
  3508. {
  3509. sprintf(str, "%04d-%02d-%02d %02d:%02d:",
  3510. tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
  3511. sprintf((str + 17), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec);
  3512. if ((*tzn != NULL) && (tm->tm_isdst >= 0))
  3513. {
  3514. if (tzp != NULL)
  3515. {
  3516. hour = -(*tzp / 3600);
  3517. min = ((abs(*tzp) / 60) % 60);
  3518. }
  3519. else
  3520. {
  3521. hour = 0;
  3522. min = 0;
  3523. }
  3524. sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
  3525. }
  3526. }
  3527. else
  3528. {
  3529. if (tm->tm_hour || tm->tm_min)
  3530. sprintf(str, "%04d-%02d-%02d %02d:%02d %s",
  3531. -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, "BC");
  3532. else
  3533. sprintf(str, "%04d-%02d-%02d %s",
  3534.   -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
  3535. }
  3536. break;
  3537. /* compatible with Oracle/Ingres date formats */
  3538. case USE_SQL_DATES:
  3539. if (EuroDates)
  3540. sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
  3541. else
  3542. sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
  3543. if (tm->tm_year > 0)
  3544. {
  3545. sprintf((str + 5), "/%04d %02d:%02d:%05.2f",
  3546. tm->tm_year, tm->tm_hour, tm->tm_min, sec);
  3547. if ((*tzn != NULL) && (tm->tm_isdst >= 0))
  3548. {
  3549. strcpy((str + 22), " ");
  3550. strcpy((str + 23), *tzn);
  3551. }
  3552. }
  3553. else
  3554. sprintf((str + 5), "/%04d %02d:%02d %s",
  3555.   -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC");
  3556. break;
  3557. /* German variant on European style */
  3558. case USE_GERMAN_DATES:
  3559. sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
  3560. if (tm->tm_year > 0)
  3561. {
  3562. sprintf((str + 5), ".%04d %02d:%02d:%05.2f",
  3563. tm->tm_year, tm->tm_hour, tm->tm_min, sec);
  3564. if ((*tzn != NULL) && (tm->tm_isdst >= 0))
  3565. {
  3566. strcpy((str + 22), " ");
  3567. strcpy((str + 23), *tzn);
  3568. }
  3569. }
  3570. else
  3571. sprintf((str + 5), ".%04d %02d:%02d %s",
  3572.   -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC");
  3573. break;
  3574. /* backward-compatible with traditional Postgres abstime dates */
  3575. case USE_POSTGRES_DATES:
  3576. default:
  3577. day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
  3578. #ifdef DATEDEBUG
  3579. printf("EncodeDateTime- day is %dn", day);
  3580. #endif
  3581. tm->tm_wday = j2day(day);
  3582. strncpy(str, days[tm->tm_wday], 3);
  3583. strcpy((str + 3), " ");
  3584. if (EuroDates)
  3585. sprintf((str + 4), "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
  3586. else
  3587. sprintf((str + 4), "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
  3588. if (tm->tm_year > 0)
  3589. {
  3590. sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);
  3591. if (fsec != 0)
  3592. {
  3593. sprintf((str + 16), ":%05.2f %04d", sec, tm->tm_year);
  3594. if ((*tzn != NULL) && (tm->tm_isdst >= 0))
  3595. {
  3596. strcpy((str + 27), " ");
  3597. strcpy((str + 28), *tzn);
  3598. }
  3599. }
  3600. else
  3601. {
  3602. sprintf((str + 16), ":%02.0f %04d", sec, tm->tm_year);
  3603. if ((*tzn != NULL) && (tm->tm_isdst >= 0))
  3604. {
  3605. strcpy((str + 24), " ");
  3606. strcpy((str + 25), *tzn);
  3607. }
  3608. }
  3609. }
  3610. else
  3611. {
  3612. sprintf((str + 10), " %02d:%02d %04d %s",
  3613.   tm->tm_hour, tm->tm_min, -(tm->tm_year - 1), "BC");
  3614. }
  3615. break;
  3616. }
  3617. #ifdef DATEDEBUG
  3618. printf("EncodeDateTime- date result is %sn", str);
  3619. #endif
  3620. return TRUE;
  3621. } /* EncodeDateTime() */
  3622. /* EncodeTimeSpan()
  3623.  * Interpret time structure as a delta time and convert to string.
  3624.  *
  3625.  * Support "traditional Postgres" and ISO-8601 styles.
  3626.  * Actually, afaik ISO does not address time interval formatting,
  3627.  * but this looks similar to the spec for absolute date/time.
  3628.  * - thomas 1998-04-30
  3629.  */
  3630. int
  3631. EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
  3632. {
  3633. int is_before = FALSE;
  3634. int is_nonzero = FALSE;
  3635. char    *cp = str;
  3636. switch (style)
  3637. {
  3638. /* compatible with ISO date formats */
  3639. case USE_ISO_DATES:
  3640. break;
  3641. default:
  3642. strcpy(cp, "@ ");
  3643. cp += strlen(cp);
  3644. break;
  3645. }
  3646. if (tm->tm_year != 0)
  3647. {
  3648. is_before |= (tm->tm_year < 0);
  3649. sprintf(cp, "%d year%s",
  3650. abs(tm->tm_year), ((abs(tm->tm_year) != 1) ? "s" : ""));
  3651. cp += strlen(cp);
  3652. is_nonzero = TRUE;
  3653. }
  3654. if (tm->tm_mon != 0)
  3655. {
  3656. is_before |= (tm->tm_mon < 0);
  3657. sprintf(cp, "%s%d mon%s", (is_nonzero ? " " : ""),
  3658. abs(tm->tm_mon), ((abs(tm->tm_mon) != 1) ? "s" : ""));
  3659. cp += strlen(cp);
  3660. is_nonzero = TRUE;
  3661. }
  3662. switch (style)
  3663. {
  3664. /* compatible with ISO date formats */
  3665. case USE_ISO_DATES:
  3666. if (tm->tm_mday != 0)
  3667. {
  3668. is_before |= (tm->tm_mday < 0);
  3669. sprintf(cp, "%s%d", (is_nonzero ? " " : ""), abs(tm->tm_mday));
  3670. cp += strlen(cp);
  3671. is_nonzero = TRUE;
  3672. }
  3673. is_before |= ((tm->tm_hour < 0) || (tm->tm_min < 0));
  3674. sprintf(cp, "%s%02d:%02d", (is_nonzero ? " " : ""),
  3675. abs(tm->tm_hour), abs(tm->tm_min));
  3676. cp += strlen(cp);
  3677. if ((tm->tm_hour != 0) || (tm->tm_min != 0))
  3678. is_nonzero = TRUE;
  3679. /* fractional seconds? */
  3680. if (fsec != 0)
  3681. {
  3682. fsec += tm->tm_sec;
  3683. is_before |= (fsec < 0);
  3684. sprintf(cp, ":%05.2f", fabs(fsec));
  3685. cp += strlen(cp);
  3686. is_nonzero = TRUE;
  3687. /* otherwise, integer seconds only? */
  3688. }
  3689. else if (tm->tm_sec != 0)
  3690. {
  3691. is_before |= (tm->tm_sec < 0);
  3692. sprintf(cp, ":%02d", abs(tm->tm_sec));
  3693. cp += strlen(cp);
  3694. is_nonzero = TRUE;
  3695. }
  3696. break;
  3697. case USE_POSTGRES_DATES:
  3698. default:
  3699. if (tm->tm_mday != 0)
  3700. {
  3701. is_before |= (tm->tm_mday < 0);
  3702. sprintf(cp, "%s%d day%s", (is_nonzero ? " " : ""),
  3703.  abs(tm->tm_mday), ((abs(tm->tm_mday) != 1) ? "s" : ""));
  3704. cp += strlen(cp);
  3705. is_nonzero = TRUE;
  3706. }
  3707. if (tm->tm_hour != 0)
  3708. {
  3709. is_before |= (tm->tm_hour < 0);
  3710. sprintf(cp, "%s%d hour%s", (is_nonzero ? " " : ""),
  3711.  abs(tm->tm_hour), ((abs(tm->tm_hour) != 1) ? "s" : ""));
  3712. cp += strlen(cp);
  3713. is_nonzero = TRUE;
  3714. }
  3715. if (tm->tm_min != 0)
  3716. {
  3717. is_before |= (tm->tm_min < 0);
  3718. sprintf(cp, "%s%d min%s", (is_nonzero ? " " : ""),
  3719.    abs(tm->tm_min), ((abs(tm->tm_min) != 1) ? "s" : ""));
  3720. cp += strlen(cp);
  3721. is_nonzero = TRUE;
  3722. }
  3723. /* fractional seconds? */
  3724. if (fsec != 0)
  3725. {
  3726. fsec += tm->tm_sec;
  3727. is_before |= (fsec < 0);
  3728. sprintf(cp, "%s%.2f secs", (is_nonzero ? " " : ""), fabs(fsec));
  3729. cp += strlen(cp);
  3730. is_nonzero = TRUE;
  3731. /* otherwise, integer seconds only? */
  3732. }
  3733. else if (tm->tm_sec != 0)
  3734. {
  3735. is_before |= (tm->tm_sec < 0);
  3736. sprintf(cp, "%s%d sec%s", (is_nonzero ? " " : ""),
  3737.    abs(tm->tm_sec), ((abs(tm->tm_sec) != 1) ? "s" : ""));
  3738. cp += strlen(cp);
  3739. is_nonzero = TRUE;
  3740. }
  3741. break;
  3742. }
  3743. /* identically zero? then put in a unitless zero... */
  3744. if (!is_nonzero)
  3745. {
  3746. strcat(cp, "0");
  3747. cp += strlen(cp);
  3748. }
  3749. if (is_before)
  3750. {
  3751. strcat(cp, " ago");
  3752. cp += strlen(cp);
  3753. }
  3754. #ifdef DATEDEBUG
  3755. printf("EncodeTimeSpan- result is %sn", str);
  3756. #endif
  3757. return 0;
  3758. } /* EncodeTimeSpan() */
  3759. #if defined(linux) && defined(__powerpc__)
  3760. int
  3761. datetime_is_epoch(double j)
  3762. {
  3763. static union
  3764. {
  3765. double epoch;
  3766. unsigned char c[8];
  3767. } u;
  3768. u.c[0] = 0x80; /* sign bit */
  3769. u.c[1] = 0x10; /* DBL_MIN */
  3770. return j == u.epoch;
  3771. }
  3772. int
  3773. datetime_is_current(double j)
  3774. {
  3775. static union
  3776. {
  3777. double current;
  3778. unsigned char c[8];
  3779. } u;
  3780. u.c[1] = 0x10; /* DBL_MIN */
  3781. return j == u.current;
  3782. }
  3783. #endif