]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/nabstime.c
Katherine Ward wrote:
[postgresql] / src / backend / utils / adt / nabstime.c
1 /*-------------------------------------------------------------------------
2  * nabstime.c
3  *        Utilities for the built-in type "AbsoluteTime".
4  *        Functions for the built-in type "RelativeTime".
5  *        Functions for the built-in type "TimeInterval".
6  *
7  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.94 2002/06/11 13:40:52 wieck Exp $
13  *
14  * NOTES
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19
20 #include <ctype.h>
21 #include <time.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <float.h>
25 #include <limits.h>
26
27 #if !(defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE))
28 #include <sys/timeb.h>
29 #endif
30
31 #include "access/xact.h"
32 #include "miscadmin.h"
33 #include "utils/builtins.h"
34
35
36 #define MIN_DAYNUM -24856               /* December 13, 1901 */
37 #define MAX_DAYNUM 24854                /* January 18, 2038 */
38
39 #define INVALID_RELTIME_STR             "Undefined RelTime"
40 #define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
41 #define RELTIME_LABEL                   '@'
42 #define RELTIME_PAST                    "ago"
43 #define DIRMAXLEN                               (sizeof(RELTIME_PAST)-1)
44
45 /*
46  * Unix epoch is Jan  1 00:00:00 1970.
47  * Postgres knows about times sixty-eight years on either side of that
48  * for these 4-byte types.
49  *
50  * "tinterval" is two 4-byte fields.
51  * Definitions for parsing tinterval.
52  */
53
54 #define IsSpace(C)                              ((C) == ' ')
55
56 #define T_INTERVAL_INVAL   0    /* data represents no valid interval */
57 #define T_INTERVAL_VALID   1    /* data represents a valid interval */
58 /*
59  * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
60  * 0            1                 2                     3                 4                     5                 6
61  * 1234567890123456789012345678901234567890123456789012345678901234
62  *
63  * we allocate some extra -- timezones are usually 3 characters but
64  * this is not in the POSIX standard...
65  */
66 #define T_INTERVAL_LEN                                  80
67 #define INVALID_INTERVAL_STR                    "Undefined Range"
68 #define INVALID_INTERVAL_STR_LEN                (sizeof(INVALID_INTERVAL_STR)-1)
69
70 #define ABSTIMEMIN(t1, t2) \
71         (DatumGetBool(DirectFunctionCall2(abstimele, \
72                                   AbsoluteTimeGetDatum(t1), \
73                                   AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
74 #define ABSTIMEMAX(t1, t2) \
75         (DatumGetBool(DirectFunctionCall2(abstimelt, \
76                                   AbsoluteTimeGetDatum(t1), \
77                                   AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
78
79
80 /*
81  * Function prototypes -- internal to this file only
82  */
83
84 static AbsoluteTime tm2abstime(struct tm * tm, int tz);
85 static void reltime2tm(RelativeTime time, struct tm * tm);
86 static int istinterval(char *i_string,
87                         AbsoluteTime *i_start,
88                         AbsoluteTime *i_end);
89
90
91 /* GetCurrentAbsoluteTime()
92  * Get the current system time. Set timezone parameters if not specified elsewhere.
93  * Define HasCTZSet to allow clients to specify the default timezone.
94  *
95  * Returns the number of seconds since epoch (January 1 1970 GMT)
96  */
97 AbsoluteTime
98 GetCurrentAbsoluteTime(void)
99 {
100         time_t          now;
101
102 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
103         struct tm  *tm;
104
105         now = time(NULL);
106 #else
107         struct timeb tb;                        /* the old V7-ism */
108
109         ftime(&tb);
110         now = tb.time;
111 #endif
112
113         if (!HasCTZSet)
114         {
115 #if defined(HAVE_TM_ZONE)
116                 tm = localtime(&now);
117
118                 CTimeZone = -tm->tm_gmtoff;             /* tm_gmtoff is Sun/DEC-ism */
119                 CDayLight = (tm->tm_isdst > 0);
120
121 #ifdef NOT_USED
122
123                 /*
124                  * XXX is there a better way to get local timezone string w/o
125                  * tzname? - tgl 97/03/18
126                  */
127                 strftime(CTZName, MAXTZLEN, "%Z", tm);
128 #endif
129
130                 /*
131                  * XXX FreeBSD man pages indicate that this should work - thomas
132                  * 1998-12-12
133                  */
134                 strcpy(CTZName, tm->tm_zone);
135
136 #elif defined(HAVE_INT_TIMEZONE)
137                 tm = localtime(&now);
138
139                 CDayLight = tm->tm_isdst;
140                 CTimeZone = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
141                 strcpy(CTZName, tzname[tm->tm_isdst]);
142 #else                                                   /* neither HAVE_TM_ZONE nor
143                                                                  * HAVE_INT_TIMEZONE */
144                 CTimeZone = tb.timezone * 60;
145                 CDayLight = (tb.dstflag != 0);
146
147                 /*
148                  * XXX does this work to get the local timezone string in V7? -
149                  * tgl 97/03/18
150                  */
151                 strftime(CTZName, MAXTZLEN, "%Z", localtime(&now));
152 #endif
153         }
154
155         return (AbsoluteTime) now;
156 }       /* GetCurrentAbsoluteTime() */
157
158
159 /* GetCurrentAbsoluteTimeUsec()
160  * Get the current system time. Set timezone parameters if not specified elsewhere.
161  * Define HasCTZSet to allow clients to specify the default timezone.
162  *
163  * Returns the number of seconds since epoch (January 1 1970 GMT)
164  */
165 AbsoluteTime
166 GetCurrentAbsoluteTimeUsec(int *usec)
167 {
168         time_t          now;
169         struct timeval tp;
170
171 #ifdef NOT_USED
172         struct timezone tpz;
173 #endif
174 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
175         struct tm  *tm;
176
177 #else
178         struct timeb tb;                        /* the old V7-ism */
179 #endif
180
181         gettimeofday(&tp, NULL);
182
183         now = tp.tv_sec;
184         *usec = tp.tv_usec;
185
186 #ifdef NOT_USED
187 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
188         now = time(NULL);
189 #else
190         ftime(&tb);
191         now = tb.time;
192 #endif
193 #endif
194
195         if (!HasCTZSet)
196         {
197 #if defined(HAVE_TM_ZONE)
198                 tm = localtime(&now);
199
200                 CTimeZone = -tm->tm_gmtoff;             /* tm_gmtoff is Sun/DEC-ism */
201                 CDayLight = (tm->tm_isdst > 0);
202
203 #ifdef NOT_USED
204
205                 /*
206                  * XXX is there a better way to get local timezone string w/o
207                  * tzname? - tgl 97/03/18
208                  */
209                 strftime(CTZName, MAXTZLEN, "%Z", tm);
210 #endif
211
212                 /*
213                  * XXX FreeBSD man pages indicate that this should work - thomas
214                  * 1998-12-12
215                  */
216                 strcpy(CTZName, tm->tm_zone);
217
218 #elif defined(HAVE_INT_TIMEZONE)
219                 tm = localtime(&now);
220
221                 CDayLight = tm->tm_isdst;
222                 CTimeZone = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
223                 strcpy(CTZName, tzname[tm->tm_isdst]);
224 #else                                                   /* neither HAVE_TM_ZONE nor
225                                                                  * HAVE_INT_TIMEZONE */
226                 CTimeZone = tb.timezone * 60;
227                 CDayLight = (tb.dstflag != 0);
228
229                 /*
230                  * XXX does this work to get the local timezone string in V7? -
231                  * tgl 97/03/18
232                  */
233                 strftime(CTZName, MAXTZLEN, "%Z", localtime(&now));
234 #endif
235         };
236
237         return (AbsoluteTime) now;
238 }       /* GetCurrentAbsoluteTimeUsec() */
239
240
241 void
242 GetCurrentDateTime(struct tm * tm)
243 {
244         int                     tz;
245
246         abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
247
248         return;
249 }       /* GetCurrentDateTime() */
250
251
252 void
253 GetCurrentTimeUsec(struct tm * tm, fsec_t *fsec)
254 {
255         int                     tz;
256         int                     usec;
257
258         abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);
259 #ifdef HAVE_INT64_TIMESTAMP
260         *fsec = usec;
261 #else
262         *fsec = usec * 1.0e-6;
263 #endif
264
265         return;
266 }       /* GetCurrentTimeUsec() */
267
268
269 void
270 abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
271 {
272         time_t          time = (time_t) _time;
273
274 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
275         struct tm  *tx;
276
277 #else
278         struct timeb tb;                        /* the old V7-ism */
279
280         ftime(&tb);
281 #endif
282
283         /*
284          * If HasCTZSet is true then we have a brute force time zone
285          * specified. Go ahead and rotate to the local time zone since we will
286          * later bypass any calls which adjust the tm fields.
287          */
288         if (HasCTZSet && (tzp != NULL))
289                 time -= CTimeZone;
290
291 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
292         if ((!HasCTZSet) && (tzp != NULL))
293         {
294                 tx = localtime((time_t *) &time);
295 #ifdef NO_MKTIME_BEFORE_1970
296                 if (tx->tm_year < 70 && tx->tm_isdst == 1)
297                 {
298                         time -= 3600;
299                         tx = localtime((time_t *) &time);
300                         tx->tm_isdst = 0;
301                 }
302 #endif
303         }
304         else
305         {
306                 tx = gmtime((time_t *) &time);
307         };
308
309         tm->tm_year = tx->tm_year + 1900;
310         tm->tm_mon = tx->tm_mon + 1;
311         tm->tm_mday = tx->tm_mday;
312         tm->tm_hour = tx->tm_hour;
313         tm->tm_min = tx->tm_min;
314         tm->tm_sec = tx->tm_sec;
315         tm->tm_isdst = tx->tm_isdst;
316
317 #if defined(HAVE_TM_ZONE)
318         tm->tm_gmtoff = tx->tm_gmtoff;
319         tm->tm_zone = tx->tm_zone;
320
321         if (tzp != NULL)
322         {
323                 /*
324                  * We have a brute force time zone per SQL99? Then use it without
325                  * change since we have already rotated to the time zone.
326                  */
327                 if (HasCTZSet)
328                 {
329                         *tzp = CTimeZone;
330                         tm->tm_gmtoff = CTimeZone;
331                         tm->tm_isdst = 0;
332                         tm->tm_zone = NULL;
333                         if (tzn != NULL)
334                                 *tzn = NULL;
335                 }
336                 else
337                 {
338                         *tzp = -tm->tm_gmtoff;          /* tm_gmtoff is Sun/DEC-ism */
339
340                         /*
341                          * XXX FreeBSD man pages indicate that this should work - tgl
342                          * 97/04/23
343                          */
344                         if (tzn != NULL)
345                         {
346                                 /*
347                                  * Copy no more than MAXTZLEN bytes of timezone to tzn, in
348                                  * case it contains an error message, which doesn't fit in
349                                  * the buffer
350                                  */
351                                 StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
352                                 if (strlen(tm->tm_zone) > MAXTZLEN)
353                                         elog(WARNING, "Invalid timezone \'%s\'", tm->tm_zone);
354                         }
355                 }
356         }
357         else
358                 tm->tm_isdst = -1;
359 #elif defined(HAVE_INT_TIMEZONE)
360         if (tzp != NULL)
361         {
362                 /*
363                  * We have a brute force time zone per SQL99? Then use it without
364                  * change since we have already rotated to the time zone.
365                  */
366                 if (HasCTZSet)
367                 {
368                         *tzp = CTimeZone;
369                         tm->tm_isdst = 0;
370                         if (tzn != NULL)
371                                 *tzn = NULL;
372                 }
373                 else
374                 {
375                         *tzp = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
376
377                         if (tzn != NULL)
378                         {
379                                 /*
380                                  * Copy no more than MAXTZLEN bytes of timezone to tzn, in
381                                  * case it contains an error message, which doesn't fit in
382                                  * the buffer
383                                  */
384                                 StrNCpy(*tzn, tzname[tm->tm_isdst], MAXTZLEN + 1);
385                                 if (strlen(tzname[tm->tm_isdst]) > MAXTZLEN)
386                                         elog(WARNING, "Invalid timezone \'%s\'", tzname[tm->tm_isdst]);
387                         }
388                 }
389         }
390         else
391                 tm->tm_isdst = -1;
392 #endif
393 #else                                                   /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
394         if (tzp != NULL)
395         {
396                 /*
397                  * We have a brute force time zone per SQL99? Then use it without
398                  * change since we have already rotated to the time zone.
399                  */
400                 if (HasCTZSet)
401                 {
402                         *tzp = CTimeZone;
403                         if (tzn != NULL)
404                                 *tzn = NULL;
405                 }
406                 else
407                 {
408                         *tzp = tb.timezone * 60;
409
410                         /*
411                          * XXX does this work to get the local timezone string in V7?
412                          * - tgl 97/03/18
413                          */
414                         if (tzn != NULL)
415                         {
416                                 strftime(*tzn, MAXTZLEN, "%Z", localtime(&now));
417                                 tzn[MAXTZLEN] = '\0';   /* let's just be sure it's
418                                                                                  * null-terminated */
419                         }
420                 }
421         }
422         else
423                 tm->tm_isdst = -1;
424 #endif
425
426         return;
427 }       /* abstime2tm() */
428
429
430 /* tm2abstime()
431  * Convert a tm structure to abstime.
432  * Note that tm has full year (not 1900-based) and 1-based month.
433  */
434 static AbsoluteTime
435 tm2abstime(struct tm * tm, int tz)
436 {
437         int                     day;
438         AbsoluteTime sec;
439
440         /* validate, before going out of range on some members */
441         if (tm->tm_year < 1901 || tm->tm_year > 2038
442                 || tm->tm_mon < 1 || tm->tm_mon > 12
443                 || tm->tm_mday < 1 || tm->tm_mday > 31
444                 || tm->tm_hour < 0 || tm->tm_hour >= 24
445                 || tm->tm_min < 0 || tm->tm_min > 59
446                 || tm->tm_sec < 0 || tm->tm_sec > 59)
447                 return INVALID_ABSTIME;
448
449         day = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(1970, 1, 1));
450
451         /* check for time out of range */
452         if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
453                 return INVALID_ABSTIME;
454
455         /* convert to seconds */
456         sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
457
458         /* check for overflow */
459         if ((day == MAX_DAYNUM && sec < 0) ||
460                 (day == MIN_DAYNUM && sec > 0))
461                 return INVALID_ABSTIME;
462
463         /* check for reserved values (e.g. "current" on edge of usual range */
464         if (!AbsoluteTimeIsReal(sec))
465                 return INVALID_ABSTIME;
466
467         return sec;
468 }       /* tm2abstime() */
469
470
471 /* nabstimein()
472  * Decode date/time string and return abstime.
473  */
474 Datum
475 nabstimein(PG_FUNCTION_ARGS)
476 {
477         char       *str = PG_GETARG_CSTRING(0);
478         AbsoluteTime result;
479         fsec_t          fsec;
480         int                     tz = 0;
481         struct tm       date,
482                            *tm = &date;
483         char       *field[MAXDATEFIELDS];
484         char            lowstr[MAXDATELEN + 1];
485         int                     dtype;
486         int                     nf,
487                                 ftype[MAXDATEFIELDS];
488
489         if (strlen(str) > MAXDATELEN)
490                 elog(ERROR, "Bad (length) abstime external representation '%s'", str);
491
492         if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
493           || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
494                 elog(ERROR, "Bad abstime external representation '%s'", str);
495
496         switch (dtype)
497         {
498                 case DTK_DATE:
499                         result = tm2abstime(tm, tz);
500                         break;
501
502                 case DTK_EPOCH:
503
504                         /*
505                          * Don't bother retaining this as a reserved value, but
506                          * instead just set to the actual epoch time (1970-01-01)
507                          */
508                         result = 0;
509                         break;
510
511                 case DTK_LATE:
512                         result = NOEND_ABSTIME;
513                         break;
514
515                 case DTK_EARLY:
516                         result = NOSTART_ABSTIME;
517                         break;
518
519                 case DTK_INVALID:
520                         result = INVALID_ABSTIME;
521                         break;
522
523                 default:
524                         elog(ERROR, "Bad abstime (internal coding error) '%s'", str);
525                         result = INVALID_ABSTIME;
526                         break;
527         };
528
529         PG_RETURN_ABSOLUTETIME(result);
530 }
531
532
533 /* nabstimeout()
534  * Given an AbsoluteTime return the English text version of the date
535  */
536 Datum
537 nabstimeout(PG_FUNCTION_ARGS)
538 {
539         AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
540         char       *result;
541         int                     tz;
542         double          fsec = 0;
543         struct tm       tt,
544                            *tm = &tt;
545         char            buf[MAXDATELEN + 1];
546         char            zone[MAXDATELEN + 1],
547                            *tzn = zone;
548
549         switch (time)
550         {
551                         /*
552                          * Note that timestamp no longer supports 'invalid'. Retain
553                          * 'invalid' for abstime for now, but dump it someday.
554                          */
555                 case INVALID_ABSTIME:
556                         strcpy(buf, INVALID);
557                         break;
558                 case NOEND_ABSTIME:
559                         strcpy(buf, LATE);
560                         break;
561                 case NOSTART_ABSTIME:
562                         strcpy(buf, EARLY);
563                         break;
564                 default:
565                         abstime2tm(time, &tz, tm, &tzn);
566                         EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
567                         break;
568         }
569
570         result = pstrdup(buf);
571         PG_RETURN_CSTRING(result);
572 }
573
574
575 /* abstime_finite()
576  */
577 Datum
578 abstime_finite(PG_FUNCTION_ARGS)
579 {
580         AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
581
582         PG_RETURN_BOOL((abstime != INVALID_ABSTIME) &&
583                                    (abstime != NOSTART_ABSTIME) &&
584                                    (abstime != NOEND_ABSTIME));
585 }
586
587
588 /*
589  * abstime comparison routines
590  */
591 static int
592 abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
593 {
594 /*
595  * We consider all INVALIDs to be equal and larger than any non-INVALID.
596  * This is somewhat arbitrary; the important thing is to have a
597  * consistent sort order.
598  */
599         if (a == INVALID_ABSTIME)
600         {
601                 if (b == INVALID_ABSTIME)
602                         return 0;                       /* INVALID = INVALID */
603                 else
604                         return 1;                       /* INVALID > non-INVALID */
605         }
606
607         if (b == INVALID_ABSTIME)
608                 return -1;                              /* non-INVALID < INVALID */
609
610 #if 0
611 /* CURRENT is no longer stored internally... */
612         /* XXX this is broken, should go away: */
613         if (a == CURRENT_ABSTIME)
614                 a = GetCurrentTransactionStartTime();
615         if (b == CURRENT_ABSTIME)
616                 b = GetCurrentTransactionStartTime();
617 #endif
618
619         if (a > b)
620                 return 1;
621         else if (a == b)
622                 return 0;
623         else
624                 return -1;
625 }
626
627 Datum
628 abstimeeq(PG_FUNCTION_ARGS)
629 {
630         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
631         AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
632
633         PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
634 }
635
636 Datum
637 abstimene(PG_FUNCTION_ARGS)
638 {
639         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
640         AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
641
642         PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
643 }
644
645 Datum
646 abstimelt(PG_FUNCTION_ARGS)
647 {
648         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
649         AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
650
651         PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
652 }
653
654 Datum
655 abstimegt(PG_FUNCTION_ARGS)
656 {
657         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
658         AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
659
660         PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
661 }
662
663 Datum
664 abstimele(PG_FUNCTION_ARGS)
665 {
666         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
667         AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
668
669         PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
670 }
671
672 Datum
673 abstimege(PG_FUNCTION_ARGS)
674 {
675         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
676         AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
677
678         PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
679 }
680
681 Datum
682 btabstimecmp(PG_FUNCTION_ARGS)
683 {
684         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
685         AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
686
687         PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
688 }
689
690
691 /* timestamp_abstime()
692  * Convert timestamp to abstime.
693  */
694 Datum
695 timestamp_abstime(PG_FUNCTION_ARGS)
696 {
697         Timestamp       timestamp = PG_GETARG_TIMESTAMP(0);
698         AbsoluteTime result;
699         fsec_t          fsec;
700         int                     tz;
701         struct tm       tt,
702                            *tm = &tt;
703
704         if (TIMESTAMP_IS_NOBEGIN(timestamp))
705                 result = NOSTART_ABSTIME;
706         else if (TIMESTAMP_IS_NOEND(timestamp))
707                 result = NOEND_ABSTIME;
708         else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
709         {
710                 tz = DetermineLocalTimeZone(tm);
711                 result = tm2abstime(tm, tz);
712         }
713         else
714         {
715                 elog(ERROR, "Unable to convert timestamp to abstime");
716                 result = INVALID_ABSTIME;
717         }
718
719         PG_RETURN_ABSOLUTETIME(result);
720 }
721
722 /* abstime_timestamp()
723  * Convert abstime to timestamp.
724  */
725 Datum
726 abstime_timestamp(PG_FUNCTION_ARGS)
727 {
728         AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
729         Timestamp       result;
730         struct tm       tt,
731                            *tm = &tt;
732         int                     tz;
733         char            zone[MAXDATELEN + 1],
734                            *tzn = zone;
735
736         switch (abstime)
737         {
738                 case INVALID_ABSTIME:
739                         elog(ERROR, "Unable to convert abstime 'invalid' to timestamp");
740                         TIMESTAMP_NOBEGIN(result);
741                         break;
742
743                 case NOSTART_ABSTIME:
744                         TIMESTAMP_NOBEGIN(result);
745                         break;
746
747                 case NOEND_ABSTIME:
748                         TIMESTAMP_NOEND(result);
749                         break;
750
751                 default:
752                         abstime2tm(abstime, &tz, tm, &tzn);
753                         if (tm2timestamp(tm, 0, NULL, &result) != 0)
754                                 elog(ERROR, "Unable convert ABSTIME to TIMESTAMP"
755                                          "\n\tabstime_timestamp() internal error");
756                         break;
757         };
758
759         PG_RETURN_TIMESTAMP(result);
760 }
761
762
763 /* timestamptz_abstime()
764  * Convert timestamp with time zone to abstime.
765  */
766 Datum
767 timestamptz_abstime(PG_FUNCTION_ARGS)
768 {
769         TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
770         AbsoluteTime result;
771         fsec_t          fsec;
772         struct tm       tt,
773                            *tm = &tt;
774
775         if (TIMESTAMP_IS_NOBEGIN(timestamp))
776                 result = NOSTART_ABSTIME;
777         else if (TIMESTAMP_IS_NOEND(timestamp))
778                 result = NOEND_ABSTIME;
779         else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
780                 result = tm2abstime(tm, 0);
781         else
782         {
783                 elog(ERROR, "Unable to convert timestamp to abstime");
784                 result = INVALID_ABSTIME;
785         }
786
787         PG_RETURN_ABSOLUTETIME(result);
788 }
789
790 /* abstime_timestamptz()
791  * Convert abstime to timestamp.
792  */
793 Datum
794 abstime_timestamptz(PG_FUNCTION_ARGS)
795 {
796         AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
797         TimestampTz result;
798         struct tm       tt,
799                            *tm = &tt;
800         int                     tz;
801         char            zone[MAXDATELEN + 1],
802                            *tzn = zone;
803
804         switch (abstime)
805         {
806                 case INVALID_ABSTIME:
807                         elog(ERROR, "Unable to convert abstime 'invalid' to timestamptz");
808                         TIMESTAMP_NOBEGIN(result);
809                         break;
810
811                 case NOSTART_ABSTIME:
812                         TIMESTAMP_NOBEGIN(result);
813                         break;
814
815                 case NOEND_ABSTIME:
816                         TIMESTAMP_NOEND(result);
817                         break;
818
819                 default:
820                         abstime2tm(abstime, &tz, tm, &tzn);
821                         if (tm2timestamp(tm, 0, &tz, &result) != 0)
822                                 elog(ERROR, "Unable convert ABSTIME to TIMESTAMP WITH TIME ZONE"
823                                          "\n\tabstime_timestamp() internal error");
824                         break;
825         };
826
827         PG_RETURN_TIMESTAMP(result);
828 }
829
830
831 /*****************************************************************************
832  *       USER I/O ROUTINES                                                                                                               *
833  *****************************************************************************/
834
835 /*
836  *              reltimein               - converts a reltime string in an internal format
837  */
838 Datum
839 reltimein(PG_FUNCTION_ARGS)
840 {
841         char       *str = PG_GETARG_CSTRING(0);
842         RelativeTime result;
843         struct tm       tt,
844                            *tm = &tt;
845         fsec_t          fsec;
846         int                     dtype;
847         char       *field[MAXDATEFIELDS];
848         int                     nf,
849                                 ftype[MAXDATEFIELDS];
850         char            lowstr[MAXDATELEN + 1];
851
852         if (strlen(str) > MAXDATELEN)
853                 elog(ERROR, "Bad (length) reltime external representation '%s'", str);
854
855         if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
856                 || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
857                 elog(ERROR, "Bad reltime external representation '%s'", str);
858
859         switch (dtype)
860         {
861                 case DTK_DELTA:
862                         result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec);
863                         result += ((tm->tm_year * 36525 * 864) + (((tm->tm_mon * 30) + tm->tm_mday) * 86400));
864                         break;
865
866                 default:
867                         elog(ERROR, "Bad reltime (internal coding error) '%s'", str);
868                         result = INVALID_RELTIME;
869                         break;
870         }
871
872         PG_RETURN_RELATIVETIME(result);
873 }
874
875
876 /*
877  *              reltimeout              - converts the internal format to a reltime string
878  */
879 Datum
880 reltimeout(PG_FUNCTION_ARGS)
881 {
882         RelativeTime time = PG_GETARG_RELATIVETIME(0);
883         char       *result;
884         struct tm       tt,
885                            *tm = &tt;
886         char            buf[MAXDATELEN + 1];
887
888         reltime2tm(time, tm);
889         EncodeInterval(tm, 0, DateStyle, buf);
890
891         result = pstrdup(buf);
892         PG_RETURN_CSTRING(result);
893 }
894
895
896 static void
897 reltime2tm(RelativeTime time, struct tm * tm)
898 {
899         TMODULO(time, tm->tm_year, 31557600);
900         TMODULO(time, tm->tm_mon, 2592000);
901         TMODULO(time, tm->tm_mday, 86400);
902         TMODULO(time, tm->tm_hour, 3600);
903         TMODULO(time, tm->tm_min, 60);
904         TMODULO(time, tm->tm_sec, 1);
905
906         return;
907 }       /* reltime2tm() */
908
909
910 /*
911  *              tintervalin             - converts an interval string to internal format
912  */
913 Datum
914 tintervalin(PG_FUNCTION_ARGS)
915 {
916         char       *intervalstr = PG_GETARG_CSTRING(0);
917         TimeInterval interval;
918         AbsoluteTime i_start,
919                                 i_end,
920                                 t1,
921                                 t2;
922
923         interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
924         if (istinterval(intervalstr, &t1, &t2) == 0)
925                 elog(ERROR, "Unable to decode tinterval '%s'", intervalstr);
926
927         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
928                 interval->status = T_INTERVAL_INVAL;    /* undefined  */
929         else
930                 interval->status = T_INTERVAL_VALID;
931
932         i_start = ABSTIMEMIN(t1, t2);
933         i_end = ABSTIMEMAX(t1, t2);
934         interval->data[0] = i_start;
935         interval->data[1] = i_end;
936
937         PG_RETURN_TIMEINTERVAL(interval);
938 }
939
940
941 /*
942  *              tintervalout    - converts an internal interval format to a string
943  *
944  */
945 Datum
946 tintervalout(PG_FUNCTION_ARGS)
947 {
948         TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
949         char       *i_str,
950                            *p;
951
952         i_str = (char *) palloc(T_INTERVAL_LEN);        /* ['...' '...'] */
953         strcpy(i_str, "[\"");
954         if (interval->status == T_INTERVAL_INVAL)
955                 strcat(i_str, INVALID_INTERVAL_STR);
956         else
957         {
958                 p = DatumGetCString(DirectFunctionCall1(nabstimeout,
959                                                            AbsoluteTimeGetDatum(interval->data[0])));
960                 strcat(i_str, p);
961                 pfree(p);
962                 strcat(i_str, "\" \"");
963                 p = DatumGetCString(DirectFunctionCall1(nabstimeout,
964                                                            AbsoluteTimeGetDatum(interval->data[1])));
965                 strcat(i_str, p);
966                 pfree(p);
967         }
968         strcat(i_str, "\"]\0");
969         PG_RETURN_CSTRING(i_str);
970 }
971
972
973 /*****************************************************************************
974  *       PUBLIC ROUTINES                                                                                                                 *
975  *****************************************************************************/
976
977 Datum
978 interval_reltime(PG_FUNCTION_ARGS)
979 {
980         Interval   *interval = PG_GETARG_INTERVAL_P(0);
981         RelativeTime time;
982         int                     year,
983                                 month;
984 #ifdef HAVE_INT64_TIMESTAMP
985         int64           span;
986 #else
987         double          span;
988 #endif
989
990         if (interval->month == 0)
991         {
992                 year = 0;
993                 month = 0;
994         }
995         else if (abs(interval->month) >= 12)
996         {
997                 year = (interval->month / 12);
998                 month = (interval->month % 12);
999         }
1000         else
1001         {
1002                 year = 0;
1003                 month = interval->month;
1004         }
1005
1006 #ifdef HAVE_INT64_TIMESTAMP
1007         span = ((((INT64CONST(365250000) * year) + (INT64CONST(30000000) * month))
1008                          * INT64CONST(86400)) + interval->time);
1009         span /= INT64CONST(1000000);
1010 #else
1011         span = (((((double) 365.25 * year) + ((double) 30 * month)) * 86400) + interval->time);
1012 #endif
1013
1014         if ((span < INT_MIN) || (span > INT_MAX))
1015                 time = INVALID_RELTIME;
1016         else
1017                 time = span;
1018
1019         PG_RETURN_RELATIVETIME(time);
1020 }
1021
1022
1023 Datum
1024 reltime_interval(PG_FUNCTION_ARGS)
1025 {
1026         RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
1027         Interval   *result;
1028         int                     year,
1029                                 month;
1030
1031         result = (Interval *) palloc(sizeof(Interval));
1032
1033         switch (reltime)
1034         {
1035                 case INVALID_RELTIME:
1036                         elog(ERROR, "Unable to convert reltime 'invalid' to interval");
1037                         result->time = 0;
1038                         result->month = 0;
1039                         break;
1040
1041                 default:
1042 #ifdef HAVE_INT64_TIMESTAMP
1043                         year = (reltime / (36525 * 864));
1044                         reltime -= (year * (36525 * 864));
1045                         month = (reltime / (30 * 86400));
1046                         reltime -= (month * (30 * 86400));
1047
1048                         result->time = (reltime * INT64CONST(1000000));
1049 #else
1050                         TMODULO(reltime, year, (36525 * 864));
1051                         TMODULO(reltime, month, (30 * 86400));
1052
1053                         result->time = reltime;
1054 #endif
1055                         result->month = ((12 * year) + month);
1056                         break;
1057         }
1058
1059         PG_RETURN_INTERVAL_P(result);
1060 }
1061
1062
1063 /*
1064  *              mktinterval             - creates a time interval with endpoints t1 and t2
1065  */
1066 Datum
1067 mktinterval(PG_FUNCTION_ARGS)
1068 {
1069         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1070         AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
1071         AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
1072         AbsoluteTime tend = ABSTIMEMAX(t1, t2);
1073         TimeInterval interval;
1074
1075         interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
1076
1077         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
1078                 interval->status = T_INTERVAL_INVAL;
1079         else
1080         {
1081                 interval->status = T_INTERVAL_VALID;
1082                 interval->data[0] = tstart;
1083                 interval->data[1] = tend;
1084         }
1085
1086         PG_RETURN_TIMEINTERVAL(interval);
1087 }
1088
1089 /*
1090  *              timepl, timemi and abstimemi use the formula
1091  *                              abstime + reltime = abstime
1092  *              so              abstime - reltime = abstime
1093  *              and             abstime - abstime = reltime
1094  */
1095
1096 /*
1097  *              timepl                  - returns the value of (abstime t1 + reltime t2)
1098  */
1099 Datum
1100 timepl(PG_FUNCTION_ARGS)
1101 {
1102         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1103         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1104
1105         if (AbsoluteTimeIsReal(t1) &&
1106                 RelativeTimeIsValid(t2) &&
1107                 ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
1108                  : (t1 > NOSTART_ABSTIME - t2)))                /* prevent overflow */
1109                 PG_RETURN_ABSOLUTETIME(t1 + t2);
1110
1111         PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1112 }
1113
1114
1115 /*
1116  *              timemi                  - returns the value of (abstime t1 - reltime t2)
1117  */
1118 Datum
1119 timemi(PG_FUNCTION_ARGS)
1120 {
1121         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1122         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1123
1124         if (AbsoluteTimeIsReal(t1) &&
1125                 RelativeTimeIsValid(t2) &&
1126                 ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
1127                  : (t1 < NOEND_ABSTIME + t2)))  /* prevent overflow */
1128                 PG_RETURN_ABSOLUTETIME(t1 - t2);
1129
1130         PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1131 }
1132
1133
1134 /*
1135  *              intinterval             - returns true iff absolute date is in the interval
1136  */
1137 Datum
1138 intinterval(PG_FUNCTION_ARGS)
1139 {
1140         AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
1141         TimeInterval interval = PG_GETARG_TIMEINTERVAL(1);
1142
1143         if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
1144         {
1145                 if (DatumGetBool(DirectFunctionCall2(abstimege,
1146                                                                                          AbsoluteTimeGetDatum(t),
1147                                                          AbsoluteTimeGetDatum(interval->data[0]))) &&
1148                         DatumGetBool(DirectFunctionCall2(abstimele,
1149                                                                                          AbsoluteTimeGetDatum(t),
1150                                                            AbsoluteTimeGetDatum(interval->data[1]))))
1151                         PG_RETURN_BOOL(true);
1152         }
1153         PG_RETURN_BOOL(false);
1154 }
1155
1156 /*
1157  *              tintervalrel            - returns  relative time corresponding to interval
1158  */
1159 Datum
1160 tintervalrel(PG_FUNCTION_ARGS)
1161 {
1162         TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
1163         AbsoluteTime t1 = interval->data[0];
1164         AbsoluteTime t2 = interval->data[1];
1165
1166         if (interval->status != T_INTERVAL_VALID)
1167                 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1168
1169         if (AbsoluteTimeIsReal(t1) &&
1170                 AbsoluteTimeIsReal(t2))
1171                 PG_RETURN_RELATIVETIME(t2 - t1);
1172
1173         PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1174 }
1175
1176
1177 /*
1178  *              timenow                 - returns  time "now", internal format
1179  *
1180  *              Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
1181  */
1182 Datum
1183 timenow(PG_FUNCTION_ARGS)
1184 {
1185         time_t          sec;
1186
1187         if (time(&sec) < 0)
1188                 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1189
1190         PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
1191 }
1192
1193 /*
1194  *              reltimeeq               - returns true iff arguments are equal
1195  *              reltimene               - returns true iff arguments are not equal
1196  *              reltimelt               - returns true iff t1 less than t2
1197  *              reltimegt               - returns true iff t1 greater than t2
1198  *              reltimele               - returns true iff t1 less than or equal to t2
1199  *              reltimege               - returns true iff t1 greater than or equal to t2
1200  */
1201 Datum
1202 reltimeeq(PG_FUNCTION_ARGS)
1203 {
1204         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1205         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1206
1207         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1208                 PG_RETURN_BOOL(false);
1209         PG_RETURN_BOOL(t1 == t2);
1210 }
1211
1212 Datum
1213 reltimene(PG_FUNCTION_ARGS)
1214 {
1215         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1216         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1217
1218         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1219                 PG_RETURN_BOOL(false);
1220         PG_RETURN_BOOL(t1 != t2);
1221 }
1222
1223 Datum
1224 reltimelt(PG_FUNCTION_ARGS)
1225 {
1226         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1227         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1228
1229         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1230                 PG_RETURN_BOOL(false);
1231         PG_RETURN_BOOL(t1 < t2);
1232 }
1233
1234 Datum
1235 reltimegt(PG_FUNCTION_ARGS)
1236 {
1237         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1238         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1239
1240         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1241                 PG_RETURN_BOOL(false);
1242         PG_RETURN_BOOL(t1 > t2);
1243 }
1244
1245 Datum
1246 reltimele(PG_FUNCTION_ARGS)
1247 {
1248         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1249         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1250
1251         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1252                 PG_RETURN_BOOL(false);
1253         PG_RETURN_BOOL(t1 <= t2);
1254 }
1255
1256 Datum
1257 reltimege(PG_FUNCTION_ARGS)
1258 {
1259         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1260         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1261
1262         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1263                 PG_RETURN_BOOL(false);
1264         PG_RETURN_BOOL(t1 >= t2);
1265 }
1266
1267
1268 /*
1269  *              tintervalsame   - returns true iff interval i1 is same as interval i2
1270  *              Check begin and end time.
1271  */
1272 Datum
1273 tintervalsame(PG_FUNCTION_ARGS)
1274 {
1275         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1276         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1277
1278         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1279                 PG_RETURN_BOOL(false);
1280
1281         if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1282                                                                            AbsoluteTimeGetDatum(i1->data[0]),
1283                                                                    AbsoluteTimeGetDatum(i2->data[0]))) &&
1284                 DatumGetBool(DirectFunctionCall2(abstimeeq,
1285                                                                            AbsoluteTimeGetDatum(i1->data[1]),
1286                                                                          AbsoluteTimeGetDatum(i2->data[1]))))
1287                 PG_RETURN_BOOL(true);
1288         PG_RETURN_BOOL(false);
1289 }
1290
1291
1292 /*
1293  *              tintervaleq             - returns true iff interval i1 is equal to interval i2
1294  *              Check length of intervals.
1295  */
1296 Datum
1297 tintervaleq(PG_FUNCTION_ARGS)
1298 {
1299         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1300         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1301         AbsoluteTime t10,
1302                                 t11,
1303                                 t20,
1304                                 t21;
1305
1306         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1307                 PG_RETURN_BOOL(false);
1308
1309         t10 = i1->data[0];
1310         t11 = i1->data[1];
1311         t20 = i2->data[0];
1312         t21 = i2->data[1];
1313
1314         if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1315                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1316                 PG_RETURN_BOOL(false);
1317
1318         PG_RETURN_BOOL((t11 - t10) == (t21 - t20));
1319 }
1320
1321 Datum
1322 tintervalne(PG_FUNCTION_ARGS)
1323 {
1324         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1325         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1326         AbsoluteTime t10,
1327                                 t11,
1328                                 t20,
1329                                 t21;
1330
1331         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1332                 PG_RETURN_BOOL(false);
1333
1334         t10 = i1->data[0];
1335         t11 = i1->data[1];
1336         t20 = i2->data[0];
1337         t21 = i2->data[1];
1338
1339         if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1340                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1341                 PG_RETURN_BOOL(false);
1342
1343         PG_RETURN_BOOL((t11 - t10) != (t21 - t20));
1344 }
1345
1346 Datum
1347 tintervallt(PG_FUNCTION_ARGS)
1348 {
1349         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1350         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1351         AbsoluteTime t10,
1352                                 t11,
1353                                 t20,
1354                                 t21;
1355
1356         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1357                 PG_RETURN_BOOL(false);
1358
1359         t10 = i1->data[0];
1360         t11 = i1->data[1];
1361         t20 = i2->data[0];
1362         t21 = i2->data[1];
1363
1364         if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1365                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1366                 PG_RETURN_BOOL(false);
1367
1368         PG_RETURN_BOOL((t11 - t10) < (t21 - t20));
1369 }
1370
1371 Datum
1372 tintervalle(PG_FUNCTION_ARGS)
1373 {
1374         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1375         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1376         AbsoluteTime t10,
1377                                 t11,
1378                                 t20,
1379                                 t21;
1380
1381         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1382                 PG_RETURN_BOOL(false);
1383
1384         t10 = i1->data[0];
1385         t11 = i1->data[1];
1386         t20 = i2->data[0];
1387         t21 = i2->data[1];
1388
1389         if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1390                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1391                 PG_RETURN_BOOL(false);
1392
1393         PG_RETURN_BOOL((t11 - t10) <= (t21 - t20));
1394 }
1395
1396 Datum
1397 tintervalgt(PG_FUNCTION_ARGS)
1398 {
1399         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1400         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1401         AbsoluteTime t10,
1402                                 t11,
1403                                 t20,
1404                                 t21;
1405
1406         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1407                 PG_RETURN_BOOL(false);
1408
1409         t10 = i1->data[0];
1410         t11 = i1->data[1];
1411         t20 = i2->data[0];
1412         t21 = i2->data[1];
1413
1414         if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1415                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1416                 PG_RETURN_BOOL(false);
1417
1418         PG_RETURN_BOOL((t11 - t10) > (t21 - t20));
1419 }
1420
1421 Datum
1422 tintervalge(PG_FUNCTION_ARGS)
1423 {
1424         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1425         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1426         AbsoluteTime t10,
1427                                 t11,
1428                                 t20,
1429                                 t21;
1430
1431         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1432                 PG_RETURN_BOOL(false);
1433
1434         t10 = i1->data[0];
1435         t11 = i1->data[1];
1436         t20 = i2->data[0];
1437         t21 = i2->data[1];
1438
1439         if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1440                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1441                 PG_RETURN_BOOL(false);
1442
1443         PG_RETURN_BOOL((t11 - t10) >= (t21 - t20));
1444 }
1445
1446
1447 /*
1448  *              tintervalleneq  - returns true iff length of interval i is equal to
1449  *                                                              reltime t
1450  *              tintervallenne  - returns true iff length of interval i is not equal
1451  *                                                              to reltime t
1452  *              tintervallenlt  - returns true iff length of interval i is less than
1453  *                                                              reltime t
1454  *              tintervallengt  - returns true iff length of interval i is greater
1455  *                                                              than reltime t
1456  *              tintervallenle  - returns true iff length of interval i is less or
1457  *                                                              equal than reltime t
1458  *              tintervallenge  - returns true iff length of interval i is greater or
1459  *                                                              equal than reltime t
1460  */
1461 Datum
1462 tintervalleneq(PG_FUNCTION_ARGS)
1463 {
1464         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1465         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1466         RelativeTime rt;
1467
1468         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1469                 PG_RETURN_BOOL(false);
1470         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1471                                                                                            TimeIntervalGetDatum(i)));
1472         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt == t));
1473 }
1474
1475 Datum
1476 tintervallenne(PG_FUNCTION_ARGS)
1477 {
1478         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1479         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1480         RelativeTime rt;
1481
1482         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1483                 PG_RETURN_BOOL(false);
1484         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1485                                                                                            TimeIntervalGetDatum(i)));
1486         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt != t));
1487 }
1488
1489 Datum
1490 tintervallenlt(PG_FUNCTION_ARGS)
1491 {
1492         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1493         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1494         RelativeTime rt;
1495
1496         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1497                 PG_RETURN_BOOL(false);
1498         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1499                                                                                            TimeIntervalGetDatum(i)));
1500         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt < t));
1501 }
1502
1503 Datum
1504 tintervallengt(PG_FUNCTION_ARGS)
1505 {
1506         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1507         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1508         RelativeTime rt;
1509
1510         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1511                 PG_RETURN_BOOL(false);
1512         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1513                                                                                            TimeIntervalGetDatum(i)));
1514         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt > t));
1515 }
1516
1517 Datum
1518 tintervallenle(PG_FUNCTION_ARGS)
1519 {
1520         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1521         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1522         RelativeTime rt;
1523
1524         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1525                 PG_RETURN_BOOL(false);
1526         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1527                                                                                            TimeIntervalGetDatum(i)));
1528         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt <= t));
1529 }
1530
1531 Datum
1532 tintervallenge(PG_FUNCTION_ARGS)
1533 {
1534         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1535         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1536         RelativeTime rt;
1537
1538         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1539                 PG_RETURN_BOOL(false);
1540         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1541                                                                                            TimeIntervalGetDatum(i)));
1542         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt >= t));
1543 }
1544
1545 /*
1546  *              tintervalct             - returns true iff interval i1 contains interval i2
1547  */
1548 Datum
1549 tintervalct(PG_FUNCTION_ARGS)
1550 {
1551         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1552         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1553
1554         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1555                 PG_RETURN_BOOL(false);
1556         if (DatumGetBool(DirectFunctionCall2(abstimele,
1557                                                                            AbsoluteTimeGetDatum(i1->data[0]),
1558                                                                    AbsoluteTimeGetDatum(i2->data[0]))) &&
1559                 DatumGetBool(DirectFunctionCall2(abstimege,
1560                                                                            AbsoluteTimeGetDatum(i1->data[1]),
1561                                                                          AbsoluteTimeGetDatum(i2->data[1]))))
1562                 PG_RETURN_BOOL(true);
1563         PG_RETURN_BOOL(false);
1564 }
1565
1566 /*
1567  *              tintervalov             - returns true iff interval i1 (partially) overlaps i2
1568  */
1569 Datum
1570 tintervalov(PG_FUNCTION_ARGS)
1571 {
1572         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1573         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1574
1575         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1576                 PG_RETURN_BOOL(false);
1577         if (DatumGetBool(DirectFunctionCall2(abstimelt,
1578                                                                            AbsoluteTimeGetDatum(i1->data[1]),
1579                                                                    AbsoluteTimeGetDatum(i2->data[0]))) ||
1580                 DatumGetBool(DirectFunctionCall2(abstimegt,
1581                                                                            AbsoluteTimeGetDatum(i1->data[0]),
1582                                                                          AbsoluteTimeGetDatum(i2->data[1]))))
1583                 PG_RETURN_BOOL(false);
1584         PG_RETURN_BOOL(true);
1585 }
1586
1587 /*
1588  *              tintervalstart  - returns  the start of interval i
1589  */
1590 Datum
1591 tintervalstart(PG_FUNCTION_ARGS)
1592 {
1593         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1594
1595         if (i->status == T_INTERVAL_INVAL)
1596                 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1597         PG_RETURN_ABSOLUTETIME(i->data[0]);
1598 }
1599
1600 /*
1601  *              tintervalend            - returns  the end of interval i
1602  */
1603 Datum
1604 tintervalend(PG_FUNCTION_ARGS)
1605 {
1606         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1607
1608         if (i->status == T_INTERVAL_INVAL)
1609                 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1610         PG_RETURN_ABSOLUTETIME(i->data[1]);
1611 }
1612
1613
1614 /*****************************************************************************
1615  *       PRIVATE ROUTINES                                                                                                                *
1616  *****************************************************************************/
1617
1618 /*
1619  *              istinterval             - returns 1, iff i_string is a valid interval descr.
1620  *                                                                0, iff i_string is NOT a valid interval desc.
1621  *                                                                2, iff any time is INVALID_ABSTIME
1622  *
1623  *              output parameter:
1624  *                              i_start, i_end: interval margins
1625  *
1626  *              Time interval:
1627  *              `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1628  *
1629  *              OR      `Undefined Range'       (see also INVALID_INTERVAL_STR)
1630  *
1631  *              where <AbsTime> satisfies the syntax of absolute time.
1632  *
1633  *              e.g.  [  '  Jan 18 1902'   'Jan 1 00:00:00 1970']
1634  */
1635 static int
1636 istinterval(char *i_string,
1637                         AbsoluteTime *i_start,
1638                         AbsoluteTime *i_end)
1639 {
1640         char       *p,
1641                            *p1;
1642         char            c;
1643
1644         p = i_string;
1645         /* skip leading blanks up to '[' */
1646         while ((c = *p) != '\0')
1647         {
1648                 if (IsSpace(c))
1649                         p++;
1650                 else if (c != '[')
1651                         return 0;                       /* syntax error */
1652                 else
1653                         break;
1654         }
1655         p++;
1656         /* skip leading blanks up to "'" */
1657         while ((c = *p) != '\0')
1658         {
1659                 if (IsSpace(c))
1660                         p++;
1661                 else if (c != '"')
1662                         return 0;                       /* syntax error */
1663                 else
1664                         break;
1665         }
1666         p++;
1667         if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1668                 return 0;                               /* undefined range, handled like a syntax
1669                                                                  * err. */
1670         /* search for the end of the first date and change it to a NULL */
1671         p1 = p;
1672         while ((c = *p1) != '\0')
1673         {
1674                 if (c == '"')
1675                 {
1676                         *p1 = '\0';
1677                         break;
1678                 }
1679                 p1++;
1680         }
1681         /* get the first date */
1682         *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(nabstimein,
1683                                                                                                         CStringGetDatum(p)));
1684         /* rechange NULL at the end of the first date to a "'" */
1685         *p1 = '"';
1686         p = ++p1;
1687         /* skip blanks up to "'", beginning of second date */
1688         while ((c = *p) != '\0')
1689         {
1690                 if (IsSpace(c))
1691                         p++;
1692                 else if (c != '"')
1693                         return 0;                       /* syntax error */
1694                 else
1695                         break;
1696         }
1697         p++;
1698         /* search for the end of the second date and change it to a NULL */
1699         p1 = p;
1700         while ((c = *p1) != '\0')
1701         {
1702                 if (c == '"')
1703                 {
1704                         *p1 = '\0';
1705                         break;
1706                 }
1707                 p1++;
1708         }
1709         /* get the second date */
1710         *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(nabstimein,
1711                                                                                                         CStringGetDatum(p)));
1712         /* rechange NULL at the end of the first date to a ''' */
1713         *p1 = '"';
1714         p = ++p1;
1715         /* skip blanks up to ']' */
1716         while ((c = *p) != '\0')
1717         {
1718                 if (IsSpace(c))
1719                         p++;
1720                 else if (c != ']')
1721                         return 0;                       /* syntax error */
1722                 else
1723                         break;
1724         }
1725         p++;
1726         c = *p;
1727         if (c != '\0')
1728                 return 0;                               /* syntax error */
1729         /* it seems to be a valid interval */
1730         return 1;
1731 }
1732
1733
1734 /*****************************************************************************
1735  *
1736  *****************************************************************************/
1737
1738 Datum
1739 int4reltime(PG_FUNCTION_ARGS)
1740 {
1741         int32           timevalue = PG_GETARG_INT32(0);
1742
1743         /* Just coerce it directly to RelativeTime ... */
1744         PG_RETURN_RELATIVETIME((RelativeTime) timevalue);
1745 }
1746
1747 /*
1748  * timeofday -
1749  *         returns the current time as a text. similar to timenow() but returns
1750  *         seconds with more precision (up to microsecs). (I need this to compare
1751  *         the Wisconsin benchmark with Illustra whose TimeNow() shows current
1752  *         time with precision up to microsecs.)                          - ay 3/95
1753  */
1754 Datum
1755 timeofday(PG_FUNCTION_ARGS)
1756 {
1757         struct timeval tp;
1758         struct timezone tpz;
1759         char            templ[100];
1760         char            buf[100];
1761         text       *result;
1762         int                     len;
1763
1764         gettimeofday(&tp, &tpz);
1765         strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1766                          localtime((time_t *) &tp.tv_sec));
1767         snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1768
1769         len = VARHDRSZ + strlen(buf);
1770         result = (text *) palloc(len);
1771         VARATT_SIZEP(result) = len;
1772         memcpy(VARDATA(result), buf, strlen(buf));
1773         PG_RETURN_TEXT_P(result);
1774 }