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