]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/nabstime.c
Fix for when POSIX time not defined.
[postgresql] / src / backend / utils / adt / nabstime.c
1 /*-------------------------------------------------------------------------
2  *
3  * nabstime.c--
4  *        parse almost any absolute date getdate(3) can (& some it can't)
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.36 1997/10/30 14:06:47 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <sys/types.h>
18
19 #include "postgres.h"
20 #include <miscadmin.h>
21 #ifdef HAVE_FLOAT_H
22 #include <float.h>
23 #endif
24 #ifdef HAVE_LIMITS_H
25 #include <limits.h>
26 #endif
27 #ifndef USE_POSIX_TIME
28 #include <sys/timeb.h>
29 #endif
30 #include "utils/builtins.h"
31 #include "access/xact.h"
32
33 static AbsoluteTime tm2abstime(struct tm * tm, int tz);
34
35 #define MIN_DAYNUM -24856               /* December 13, 1901 */
36 #define MAX_DAYNUM 24854                /* January 18, 2038 */
37
38
39 /* GetCurrentAbsoluteTime()
40  * Get the current system time. Set timezone parameters if not specified elsewhere.
41  * Define HasTZSet to allow clients to specify the default timezone.
42  *
43  * Returns the number of seconds since epoch (January 1 1970 GMT)
44  */
45 AbsoluteTime
46 GetCurrentAbsoluteTime(void)
47 {
48         time_t          now;
49
50 #ifdef USE_POSIX_TIME
51         struct tm  *tm;
52
53         now = time(NULL);
54 #else                                                   /* ! USE_POSIX_TIME */
55         struct timeb tb;                        /* the old V7-ism */
56
57         ftime(&tb);
58         now = tb.time;
59 #endif
60
61         if (!HasCTZSet)
62         {
63 #ifdef USE_POSIX_TIME
64 #if defined(HAVE_TZSET) && defined(HAVE_INT_TIMEZONE)
65                 tm = localtime(&now);
66
67                 CDayLight = tm->tm_isdst;
68                 CTimeZone = (tm->tm_isdst ? (timezone - 3600) : timezone);
69                 strcpy(CTZName, tzname[tm->tm_isdst]);
70 #else                                                   /* !HAVE_TZSET */
71                 tm = localtime(&now);
72
73                 CTimeZone = -tm->tm_gmtoff;             /* tm_gmtoff is Sun/DEC-ism */
74                 CDayLight = (tm->tm_isdst > 0);
75
76                 /*
77                  * XXX is there a better way to get local timezone string w/o
78                  * tzname? - tgl 97/03/18
79                  */
80                 strftime(CTZName, MAXTZLEN, "%Z", tm);
81
82                 /*
83                  * XXX FreeBSD man pages indicate that this should work - tgl
84                  * 97/04/23
85                  */
86                 strcpy(CTZName, tm->tm_zone);
87 #endif
88 #else                                                   /* ! USE_POSIX_TIME */
89                 CTimeZone = tb.timezone * 60;
90                 CDayLight = (tb.dstflag != 0);
91
92                 /*
93                  * XXX does this work to get the local timezone string in V7? -
94                  * tgl 97/03/18
95                  */
96                 strftime(CTZName, MAXTZLEN, "%Z", localtime(&now));
97 #endif
98         };
99
100 #ifdef DATEDEBUG
101         printf("GetCurrentAbsoluteTime- timezone is %s -> %d seconds from UTC\n",
102                    CTZName, CTimeZone);
103 #endif
104
105         return ((AbsoluteTime) now);
106 }                                                               /* GetCurrentAbsoluteTime() */
107
108
109 void
110 GetCurrentTime(struct tm * tm)
111 {
112         int                     tz;
113
114         abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
115
116         return;
117 }                                                               /* GetCurrentTime() */
118
119
120 void
121 abstime2tm(AbsoluteTime time, int *tzp, struct tm * tm, char *tzn)
122 {
123 #ifdef USE_POSIX_TIME
124         struct tm  *tx;
125
126 #else                                                   /* ! USE_POSIX_TIME */
127         struct timeb tb;                        /* the old V7-ism */
128
129         ftime(&tb);
130 #endif
131
132 #ifdef USE_POSIX_TIME
133         if (tzp != NULL)
134         {
135                 tx = localtime((time_t *) &time);
136         }
137         else
138         {
139                 tx = gmtime((time_t *) &time);
140         };
141 #else
142 #endif
143
144 #ifdef DATEDEBUG
145 #ifdef HAVE_INT_TIMEZONE
146         printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s %s dst=%d\n",
147                    tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
148                    tzname[0], tzname[1], tx->tm_isdst);
149 #else
150         printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s dst=%d\n",
151                    tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
152                    tx->tm_zone, tx->tm_isdst);
153 #endif
154 #else
155 #endif
156
157 #ifdef USE_POSIX_TIME
158
159         tm->tm_year = tx->tm_year + 1900;
160         tm->tm_mon = tx->tm_mon + 1;
161         tm->tm_mday = tx->tm_mday;
162         tm->tm_hour = tx->tm_hour;
163         tm->tm_min = tx->tm_min;
164         tm->tm_sec = tx->tm_sec;
165         tm->tm_isdst = tx->tm_isdst;
166
167 #ifdef HAVE_INT_TIMEZONE
168         if (tzp != NULL)
169                 *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone);
170         if (tzn != NULL)
171                 strcpy(tzn, tzname[tm->tm_isdst]);
172 #else                                                   /* !HAVE_INT_TIMEZONE */
173         tm->tm_gmtoff = tx->tm_gmtoff;
174         tm->tm_zone = tx->tm_zone;
175
176         if (tzp != NULL)
177                 *tzp = -tm->tm_gmtoff;  /* tm_gmtoff is Sun/DEC-ism */
178         /* XXX FreeBSD man pages indicate that this should work - tgl 97/04/23 */
179         if (tzn != NULL)
180                 strcpy(tzn, tm->tm_zone);
181 #endif
182 #else                                                   /* ! USE_POSIX_TIME */
183         if (tzp != NULL)
184                 *tzp = tb.timezone * 60;
185
186         /*
187          * XXX does this work to get the local timezone string in V7? - tgl
188          * 97/03/18
189          */
190         if (tzn != NULL)
191                 strftime(tzn, MAXTZLEN, "%Z", localtime(&now));
192 #endif
193
194         return;
195 }                                                               /* abstime2tm() */
196
197
198 /* tm2abstime()
199  * Convert a tm structure to abstime.
200  * Note that tm has full year (not 1900-based) and 1-based month.
201  */
202 static AbsoluteTime
203 tm2abstime(struct tm * tm, int tz)
204 {
205         int                     day,
206                                 sec;
207
208         /* validate, before going out of range on some members */
209         if (tm->tm_year < 1901 || tm->tm_year > 2038
210                 || tm->tm_mon < 1 || tm->tm_mon > 12
211                 || tm->tm_mday < 1 || tm->tm_mday > 31
212                 || tm->tm_hour < 0 || tm->tm_hour >= 24
213                 || tm->tm_min < 0 || tm->tm_min > 59
214                 || tm->tm_sec < 0 || tm->tm_sec > 59)
215                 return (INVALID_ABSTIME);
216
217         day = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(1970, 1, 1));
218
219         /* check for time out of range */
220         if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
221                 return (INVALID_ABSTIME);
222
223         /* convert to seconds */
224         sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
225
226         /* check for overflow */
227         if ((day == MAX_DAYNUM && sec < 0) ||
228                 (day == MIN_DAYNUM && sec > 0))
229                 return (INVALID_ABSTIME);
230
231         /* check for reserved values (e.g. "current" on edge of usual range */
232         if (!AbsoluteTimeIsReal(sec))
233                 return (INVALID_ABSTIME);
234
235         return (sec);
236 }                                                               /* tm2abstime() */
237
238
239 /* nabstimein()
240  * Decode date/time string and return abstime.
241  */
242 AbsoluteTime
243 nabstimein(char *str)
244 {
245         AbsoluteTime result;
246
247         double          fsec;
248         int                     tz = 0;
249         struct tm       date,
250                            *tm = &date;
251
252         char       *field[MAXDATEFIELDS];
253         char            lowstr[MAXDATELEN + 1];
254         int                     dtype;
255         int                     nf,
256                                 ftype[MAXDATEFIELDS];
257
258         if (!PointerIsValid(str))
259                 elog(WARN, "Bad (null) abstime external representation", NULL);
260
261         if (strlen(str) > MAXDATELEN)
262                 elog(WARN, "Bad (length) abstime external representation '%s'", str);
263
264         if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
265           || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
266                 elog(WARN, "Bad abstime external representation '%s'", str);
267
268 #ifdef DATEDEBUG
269         printf("nabstimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE);
270 #endif
271
272         switch (dtype)
273         {
274                 case DTK_DATE:
275                         result = tm2abstime(tm, tz);
276                         break;
277
278                 case DTK_EPOCH:
279                         result = EPOCH_ABSTIME;
280                         break;
281
282                 case DTK_CURRENT:
283                         result = CURRENT_ABSTIME;
284                         break;
285
286                 case DTK_LATE:
287                         result = NOEND_ABSTIME;
288                         break;
289
290                 case DTK_EARLY:
291                         result = NOSTART_ABSTIME;
292                         break;
293
294                 case DTK_INVALID:
295                         result = INVALID_ABSTIME;
296                         break;
297
298                 default:
299                         elog(WARN, "Bad abstime (internal coding error) '%s'", str);
300                         result = INVALID_ABSTIME;
301                         break;
302         };
303
304         return result;
305 }                                                               /* nabstimein() */
306
307
308 /* nabstimeout()
309  * Given an AbsoluteTime return the English text version of the date
310  */
311 char       *
312 nabstimeout(AbsoluteTime time)
313 {
314         char       *result;
315         int                     tz;
316         double          fsec = 0;
317         struct tm       tt,
318                            *tm = &tt;
319         char            buf[MAXDATELEN + 1];
320         char            zone[MAXDATELEN + 1],
321                            *tzn = zone;
322
323         switch (time)
324         {
325                 case EPOCH_ABSTIME:
326                         strcpy(buf, EPOCH);
327                         break;
328                 case INVALID_ABSTIME:
329                         strcpy(buf, INVALID);
330                         break;
331                 case CURRENT_ABSTIME:
332                         strcpy(buf, DCURRENT);
333                         break;
334                 case NOEND_ABSTIME:
335                         strcpy(buf, LATE);
336                         break;
337                 case NOSTART_ABSTIME:
338                         strcpy(buf, EARLY);
339                         break;
340                 default:
341                         abstime2tm(time, &tz, tm, tzn);
342 #if DATEDEBUG
343 #endif
344                         EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
345                         break;
346         }
347
348         result = PALLOC(strlen(buf) + 1);
349         strcpy(result, buf);
350
351         return (result);
352 }                                                               /* nabstimeout() */
353
354
355 /*
356  *      AbsoluteTimeIsBefore -- true iff time1 is before time2.
357  *      AbsoluteTimeIsBefore -- true iff time1 is after time2.
358  */
359 bool
360 AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2)
361 {
362         Assert(AbsoluteTimeIsValid(time1));
363         Assert(AbsoluteTimeIsValid(time2));
364
365         if (time1 == CURRENT_ABSTIME)
366                 time1 = GetCurrentTransactionStartTime();
367
368         if (time2 == CURRENT_ABSTIME)
369                 time2 = GetCurrentTransactionStartTime();
370
371         return (time1 < time2);
372 }
373
374 bool
375 AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
376 {
377         Assert(AbsoluteTimeIsValid(time1));
378         Assert(AbsoluteTimeIsValid(time2));
379
380         if (time1 == CURRENT_ABSTIME)
381                 time1 = GetCurrentTransactionStartTime();
382
383         if (time2 == CURRENT_ABSTIME)
384                 time2 = GetCurrentTransactionStartTime();
385
386         return (time1 > time2);
387 }
388
389
390 /* abstime_finite()
391  */
392 bool
393 abstime_finite(AbsoluteTime abstime)
394 {
395         return ((abstime != INVALID_ABSTIME)
396                   && (abstime != NOSTART_ABSTIME) && (abstime != NOEND_ABSTIME));
397 } /* abstime_finite() */
398
399
400 /*
401  *              abstimeeq               - returns 1, iff arguments are equal
402  *              abstimene               - returns 1, iff arguments are not equal
403  *              abstimelt               - returns 1, iff t1 less than t2
404  *              abstimegt               - returns 1, iff t1 greater than t2
405  *              abstimele               - returns 1, iff t1 less than or equal to t2
406  *              abstimege               - returns 1, iff t1 greater than or equal to t2
407  */
408 bool
409 abstimeeq(AbsoluteTime t1, AbsoluteTime t2)
410 {
411         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
412                 return (FALSE);
413         if (t1 == CURRENT_ABSTIME)
414                 t1 = GetCurrentTransactionStartTime();
415         if (t2 == CURRENT_ABSTIME)
416                 t2 = GetCurrentTransactionStartTime();
417
418         return (t1 == t2);
419 }
420
421 bool
422 abstimene(AbsoluteTime t1, AbsoluteTime t2)
423 {
424         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
425                 return (FALSE);
426         if (t1 == CURRENT_ABSTIME)
427                 t1 = GetCurrentTransactionStartTime();
428         if (t2 == CURRENT_ABSTIME)
429                 t2 = GetCurrentTransactionStartTime();
430
431         return (t1 != t2);
432 }
433
434 bool
435 abstimelt(AbsoluteTime t1, AbsoluteTime t2)
436 {
437         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
438                 return (FALSE);
439         if (t1 == CURRENT_ABSTIME)
440                 t1 = GetCurrentTransactionStartTime();
441         if (t2 == CURRENT_ABSTIME)
442                 t2 = GetCurrentTransactionStartTime();
443
444         return (t1 < t2);
445 }
446
447 bool
448 abstimegt(AbsoluteTime t1, AbsoluteTime t2)
449 {
450         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
451                 return (FALSE);
452         if (t1 == CURRENT_ABSTIME)
453                 t1 = GetCurrentTransactionStartTime();
454         if (t2 == CURRENT_ABSTIME)
455                 t2 = GetCurrentTransactionStartTime();
456
457         return (t1 > t2);
458 }
459
460 bool
461 abstimele(AbsoluteTime t1, AbsoluteTime t2)
462 {
463         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
464                 return (FALSE);
465         if (t1 == CURRENT_ABSTIME)
466                 t1 = GetCurrentTransactionStartTime();
467         if (t2 == CURRENT_ABSTIME)
468                 t2 = GetCurrentTransactionStartTime();
469
470         return (t1 <= t2);
471 }
472
473 bool
474 abstimege(AbsoluteTime t1, AbsoluteTime t2)
475 {
476         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
477                 return (FALSE);
478         if (t1 == CURRENT_ABSTIME)
479                 t1 = GetCurrentTransactionStartTime();
480         if (t2 == CURRENT_ABSTIME)
481                 t2 = GetCurrentTransactionStartTime();
482
483         return (t1 >= t2);
484 }
485
486
487 /* datetime_abstime()
488  * Convert datetime to abstime.
489  */
490 AbsoluteTime
491 datetime_abstime(DateTime *datetime)
492 {
493         AbsoluteTime result;
494
495         double          fsec;
496         struct tm       tt,
497                            *tm = &tt;
498
499         if (!PointerIsValid(datetime))
500         {
501                 result = INVALID_ABSTIME;
502
503         }
504         else if (DATETIME_IS_INVALID(*datetime))
505         {
506                 result = INVALID_ABSTIME;
507
508         }
509         else if (DATETIME_IS_NOBEGIN(*datetime))
510         {
511                 result = NOSTART_ABSTIME;
512
513         }
514         else if (DATETIME_IS_NOEND(*datetime))
515         {
516                 result = NOEND_ABSTIME;
517
518         }
519         else
520         {
521                 if (DATETIME_IS_RELATIVE(*datetime))
522                 {
523                         datetime2tm(SetDateTime(*datetime), NULL, tm, &fsec, NULL);
524                         result = tm2abstime(tm, 0);
525
526                 }
527                 else if (datetime2tm(*datetime, NULL, tm, &fsec, NULL) == 0)
528                 {
529                         result = tm2abstime(tm, 0);
530
531                 }
532                 else
533                 {
534                         result = INVALID_ABSTIME;
535                 };
536         };
537
538         return (result);
539 } /* datetime_abstime() */
540
541 /* abstime_datetime()
542  * Convert abstime to datetime.
543  */
544 DateTime   *
545 abstime_datetime(AbsoluteTime abstime)
546 {
547         DateTime   *result;
548
549         if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
550                 elog(WARN, "Unable to allocate space to convert abstime to datetime", NULL);
551
552         switch (abstime)
553         {
554                 case INVALID_ABSTIME:
555                         DATETIME_INVALID(*result);
556                         break;
557
558                 case NOSTART_ABSTIME:
559                         DATETIME_NOBEGIN(*result);
560                         break;
561
562                 case NOEND_ABSTIME:
563                         DATETIME_NOEND(*result);
564                         break;
565
566                 case EPOCH_ABSTIME:
567                         DATETIME_EPOCH(*result);
568                         break;
569
570                 case CURRENT_ABSTIME:
571                         DATETIME_CURRENT(*result);
572                         break;
573
574                 default:
575                         *result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400);
576                         break;
577         };
578
579         return (result);
580 } /* abstime_datetime() */