]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/nabstime.c
pgindent run before 6.3 release, with Thomas' requested changes.
[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.42 1998/02/26 04:37:12 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 #endif
142
143 #if defined(DATEDEBUG)
144 #if defined(HAVE_INT_TIMEZONE)
145         printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s %s dst=%d\n",
146                    tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
147                    tzname[0], tzname[1], tx->tm_isdst);
148 #else
149         printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s dst=%d\n",
150                    tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
151                    tx->tm_zone, tx->tm_isdst);
152 #endif
153 #endif
154
155 #ifdef USE_POSIX_TIME
156
157         tm->tm_year = tx->tm_year + 1900;
158         tm->tm_mon = tx->tm_mon + 1;
159         tm->tm_mday = tx->tm_mday;
160         tm->tm_hour = tx->tm_hour;
161         tm->tm_min = tx->tm_min;
162         tm->tm_sec = tx->tm_sec;
163         tm->tm_isdst = tx->tm_isdst;
164
165 #ifdef HAVE_INT_TIMEZONE
166         if (tzp != NULL)
167                 *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone);
168         if (tzn != NULL)
169                 strcpy(tzn, tzname[tm->tm_isdst]);
170 #else                                                   /* !HAVE_INT_TIMEZONE */
171         tm->tm_gmtoff = tx->tm_gmtoff;
172         tm->tm_zone = tx->tm_zone;
173
174         if (tzp != NULL)
175                 *tzp = -tm->tm_gmtoff;  /* tm_gmtoff is Sun/DEC-ism */
176         /* XXX FreeBSD man pages indicate that this should work - tgl 97/04/23 */
177         if (tzn != NULL)
178                 strcpy(tzn, tm->tm_zone);
179 #endif
180 #else                                                   /* ! USE_POSIX_TIME */
181         if (tzp != NULL)
182                 *tzp = tb.timezone * 60;
183
184         /*
185          * XXX does this work to get the local timezone string in V7? - tgl
186          * 97/03/18
187          */
188         if (tzn != NULL)
189                 strftime(tzn, MAXTZLEN, "%Z", localtime(&now));
190 #endif
191
192         return;
193 }       /* abstime2tm() */
194
195
196 /* tm2abstime()
197  * Convert a tm structure to abstime.
198  * Note that tm has full year (not 1900-based) and 1-based month.
199  */
200 static AbsoluteTime
201 tm2abstime(struct tm * tm, int tz)
202 {
203         int                     day,
204                                 sec;
205
206         /* validate, before going out of range on some members */
207         if (tm->tm_year < 1901 || tm->tm_year > 2038
208                 || tm->tm_mon < 1 || tm->tm_mon > 12
209                 || tm->tm_mday < 1 || tm->tm_mday > 31
210                 || tm->tm_hour < 0 || tm->tm_hour >= 24
211                 || tm->tm_min < 0 || tm->tm_min > 59
212                 || tm->tm_sec < 0 || tm->tm_sec > 59)
213                 return (INVALID_ABSTIME);
214
215         day = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(1970, 1, 1));
216
217         /* check for time out of range */
218         if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
219                 return (INVALID_ABSTIME);
220
221         /* convert to seconds */
222         sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
223
224         /* check for overflow */
225         if ((day == MAX_DAYNUM && sec < 0) ||
226                 (day == MIN_DAYNUM && sec > 0))
227                 return (INVALID_ABSTIME);
228
229         /* check for reserved values (e.g. "current" on edge of usual range */
230         if (!AbsoluteTimeIsReal(sec))
231                 return (INVALID_ABSTIME);
232
233         return (sec);
234 }       /* tm2abstime() */
235
236
237 /* nabstimein()
238  * Decode date/time string and return abstime.
239  */
240 AbsoluteTime
241 nabstimein(char *str)
242 {
243         AbsoluteTime result;
244
245         double          fsec;
246         int                     tz = 0;
247         struct tm       date,
248                            *tm = &date;
249
250         char       *field[MAXDATEFIELDS];
251         char            lowstr[MAXDATELEN + 1];
252         int                     dtype;
253         int                     nf,
254                                 ftype[MAXDATEFIELDS];
255
256         if (!PointerIsValid(str))
257                 elog(ERROR, "Bad (null) abstime external representation", NULL);
258
259         if (strlen(str) > MAXDATELEN)
260                 elog(ERROR, "Bad (length) abstime external representation '%s'", str);
261
262         if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
263           || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
264                 elog(ERROR, "Bad abstime external representation '%s'", str);
265
266 #ifdef DATEDEBUG
267         printf("nabstimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE);
268 #endif
269
270         switch (dtype)
271         {
272                 case DTK_DATE:
273                         result = tm2abstime(tm, tz);
274                         break;
275
276                 case DTK_EPOCH:
277                         result = EPOCH_ABSTIME;
278                         break;
279
280                 case DTK_CURRENT:
281                         result = CURRENT_ABSTIME;
282                         break;
283
284                 case DTK_LATE:
285                         result = NOEND_ABSTIME;
286                         break;
287
288                 case DTK_EARLY:
289                         result = NOSTART_ABSTIME;
290                         break;
291
292                 case DTK_INVALID:
293                         result = INVALID_ABSTIME;
294                         break;
295
296                 default:
297                         elog(ERROR, "Bad abstime (internal coding error) '%s'", str);
298                         result = INVALID_ABSTIME;
299                         break;
300         };
301
302         return result;
303 }       /* nabstimein() */
304
305
306 /* nabstimeout()
307  * Given an AbsoluteTime return the English text version of the date
308  */
309 char *
310 nabstimeout(AbsoluteTime time)
311 {
312         char       *result;
313         int                     tz;
314         double          fsec = 0;
315         struct tm       tt,
316                            *tm = &tt;
317         char            buf[MAXDATELEN + 1];
318         char            zone[MAXDATELEN + 1],
319                            *tzn = zone;
320
321         switch (time)
322         {
323                 case EPOCH_ABSTIME:
324                         strcpy(buf, EPOCH);
325                         break;
326                 case INVALID_ABSTIME:
327                         strcpy(buf, INVALID);
328                         break;
329                 case CURRENT_ABSTIME:
330                         strcpy(buf, DCURRENT);
331                         break;
332                 case NOEND_ABSTIME:
333                         strcpy(buf, LATE);
334                         break;
335                 case NOSTART_ABSTIME:
336                         strcpy(buf, EARLY);
337                         break;
338                 default:
339                         abstime2tm(time, &tz, tm, tzn);
340 #if DATEDEBUG
341 #endif
342                         EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
343                         break;
344         }
345
346         result = palloc(strlen(buf) + 1);
347         strcpy(result, buf);
348
349         return (result);
350 }       /* nabstimeout() */
351
352
353 /*
354  *      AbsoluteTimeIsBefore -- true iff time1 is before time2.
355  *      AbsoluteTimeIsBefore -- true iff time1 is after time2.
356  */
357 bool
358 AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2)
359 {
360         Assert(AbsoluteTimeIsValid(time1));
361         Assert(AbsoluteTimeIsValid(time2));
362
363         if (time1 == CURRENT_ABSTIME)
364                 time1 = GetCurrentTransactionStartTime();
365
366         if (time2 == CURRENT_ABSTIME)
367                 time2 = GetCurrentTransactionStartTime();
368
369         return (time1 < time2);
370 }
371
372 bool
373 AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
374 {
375         Assert(AbsoluteTimeIsValid(time1));
376         Assert(AbsoluteTimeIsValid(time2));
377
378         if (time1 == CURRENT_ABSTIME)
379                 time1 = GetCurrentTransactionStartTime();
380
381         if (time2 == CURRENT_ABSTIME)
382                 time2 = GetCurrentTransactionStartTime();
383
384         return (time1 > time2);
385 }
386
387
388 /* abstime_finite()
389  */
390 bool
391 abstime_finite(AbsoluteTime abstime)
392 {
393         return ((abstime != INVALID_ABSTIME)
394                   && (abstime != NOSTART_ABSTIME) && (abstime != NOEND_ABSTIME));
395 }       /* abstime_finite() */
396
397
398 /*
399  *              abstimeeq               - returns 1, iff arguments are equal
400  *              abstimene               - returns 1, iff arguments are not equal
401  *              abstimelt               - returns 1, iff t1 less than t2
402  *              abstimegt               - returns 1, iff t1 greater than t2
403  *              abstimele               - returns 1, iff t1 less than or equal to t2
404  *              abstimege               - returns 1, iff t1 greater than or equal to t2
405  */
406 bool
407 abstimeeq(AbsoluteTime t1, AbsoluteTime t2)
408 {
409         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
410                 return (FALSE);
411         if (t1 == CURRENT_ABSTIME)
412                 t1 = GetCurrentTransactionStartTime();
413         if (t2 == CURRENT_ABSTIME)
414                 t2 = GetCurrentTransactionStartTime();
415
416         return (t1 == t2);
417 }
418
419 bool
420 abstimene(AbsoluteTime t1, AbsoluteTime t2)
421 {
422         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
423                 return (FALSE);
424         if (t1 == CURRENT_ABSTIME)
425                 t1 = GetCurrentTransactionStartTime();
426         if (t2 == CURRENT_ABSTIME)
427                 t2 = GetCurrentTransactionStartTime();
428
429         return (t1 != t2);
430 }
431
432 bool
433 abstimelt(AbsoluteTime t1, AbsoluteTime t2)
434 {
435         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
436                 return (FALSE);
437         if (t1 == CURRENT_ABSTIME)
438                 t1 = GetCurrentTransactionStartTime();
439         if (t2 == CURRENT_ABSTIME)
440                 t2 = GetCurrentTransactionStartTime();
441
442         return (t1 < t2);
443 }
444
445 bool
446 abstimegt(AbsoluteTime t1, AbsoluteTime t2)
447 {
448         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
449                 return (FALSE);
450         if (t1 == CURRENT_ABSTIME)
451                 t1 = GetCurrentTransactionStartTime();
452         if (t2 == CURRENT_ABSTIME)
453                 t2 = GetCurrentTransactionStartTime();
454
455         return (t1 > t2);
456 }
457
458 bool
459 abstimele(AbsoluteTime t1, AbsoluteTime t2)
460 {
461         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
462                 return (FALSE);
463         if (t1 == CURRENT_ABSTIME)
464                 t1 = GetCurrentTransactionStartTime();
465         if (t2 == CURRENT_ABSTIME)
466                 t2 = GetCurrentTransactionStartTime();
467
468         return (t1 <= t2);
469 }
470
471 bool
472 abstimege(AbsoluteTime t1, AbsoluteTime t2)
473 {
474         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
475                 return (FALSE);
476         if (t1 == CURRENT_ABSTIME)
477                 t1 = GetCurrentTransactionStartTime();
478         if (t2 == CURRENT_ABSTIME)
479                 t2 = GetCurrentTransactionStartTime();
480
481         return (t1 >= t2);
482 }
483
484
485 /* datetime_abstime()
486  * Convert datetime to abstime.
487  */
488 AbsoluteTime
489 datetime_abstime(DateTime *datetime)
490 {
491         AbsoluteTime result;
492
493         double          fsec;
494         struct tm       tt,
495                            *tm = &tt;
496
497         if (!PointerIsValid(datetime))
498         {
499                 result = INVALID_ABSTIME;
500
501         }
502         else if (DATETIME_IS_INVALID(*datetime))
503         {
504                 result = INVALID_ABSTIME;
505
506         }
507         else if (DATETIME_IS_NOBEGIN(*datetime))
508         {
509                 result = NOSTART_ABSTIME;
510
511         }
512         else if (DATETIME_IS_NOEND(*datetime))
513         {
514                 result = NOEND_ABSTIME;
515
516         }
517         else
518         {
519                 if (DATETIME_IS_RELATIVE(*datetime))
520                 {
521                         datetime2tm(SetDateTime(*datetime), NULL, tm, &fsec, NULL);
522                         result = tm2abstime(tm, 0);
523
524                 }
525                 else if (datetime2tm(*datetime, NULL, tm, &fsec, NULL) == 0)
526                 {
527                         result = tm2abstime(tm, 0);
528
529                 }
530                 else
531                 {
532                         result = INVALID_ABSTIME;
533                 };
534         };
535
536         return (result);
537 }       /* datetime_abstime() */
538
539 /* abstime_datetime()
540  * Convert abstime to datetime.
541  */
542 DateTime   *
543 abstime_datetime(AbsoluteTime abstime)
544 {
545         DateTime   *result;
546
547         if (!PointerIsValid(result = palloc(sizeof(DateTime))))
548                 elog(ERROR, "Unable to allocate space to convert abstime to datetime", NULL);
549
550         switch (abstime)
551         {
552                 case INVALID_ABSTIME:
553                         DATETIME_INVALID(*result);
554                         break;
555
556                 case NOSTART_ABSTIME:
557                         DATETIME_NOBEGIN(*result);
558                         break;
559
560                 case NOEND_ABSTIME:
561                         DATETIME_NOEND(*result);
562                         break;
563
564                 case EPOCH_ABSTIME:
565                         DATETIME_EPOCH(*result);
566                         break;
567
568                 case CURRENT_ABSTIME:
569                         DATETIME_CURRENT(*result);
570                         break;
571
572                 default:
573                         *result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400);
574                         break;
575         };
576
577         return (result);
578 }       /* abstime_datetime() */