nabstime.c 12.1 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * nabstime.c--
4
 *	  parse almost any absolute date getdate(3) can (& some it can't)
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
T
Thomas G. Lockhart 已提交
10
 *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.35 1997/10/25 05:21:10 thomas Exp $
11 12 13 14 15 16 17
 *
 *-------------------------------------------------------------------------
 */
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#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 28 29
#ifndef USE_POSIX_TIME
#include <sys/timeb.h>
#endif
30
#include "utils/builtins.h"
31 32
#include "access/xact.h"

33
static AbsoluteTime tm2abstime(struct tm * tm, int tz);
34

35 36
#define MIN_DAYNUM -24856		/* December 13, 1901 */
#define MAX_DAYNUM 24854		/* January 18, 2038 */
37 38


39 40 41
/* GetCurrentAbsoluteTime()
 * Get the current system time. Set timezone parameters if not specified elsewhere.
 * Define HasTZSet to allow clients to specify the default timezone.
42 43 44 45
 *
 * Returns the number of seconds since epoch (January 1 1970 GMT)
 */
AbsoluteTime
46
GetCurrentAbsoluteTime(void)
47
{
48
	time_t		now;
49

50
#ifdef USE_POSIX_TIME
51
	struct tm  *tm;
52

53 54
	now = time(NULL);
#else							/* ! USE_POSIX_TIME */
55
	struct timeb tb;			/* the old V7-ism */
56

57 58
	ftime(&tb);
	now = tb.time;
59
#endif
60

61 62
	if (!HasCTZSet)
	{
63
#ifdef USE_POSIX_TIME
64
#if defined(HAVE_TZSET) && defined(HAVE_INT_TIMEZONE)
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
		tm = localtime(&now);

		CDayLight = tm->tm_isdst;
		CTimeZone = (tm->tm_isdst ? (timezone - 3600) : timezone);
		strcpy(CTZName, tzname[tm->tm_isdst]);
#else							/* !HAVE_TZSET */
		tm = localtime(&now);

		CTimeZone = -tm->tm_gmtoff;		/* tm_gmtoff is Sun/DEC-ism */
		CDayLight = (tm->tm_isdst > 0);

		/*
		 * XXX is there a better way to get local timezone string w/o
		 * tzname? - tgl 97/03/18
		 */
		strftime(CTZName, MAXTZLEN, "%Z", tm);

		/*
		 * XXX FreeBSD man pages indicate that this should work - tgl
		 * 97/04/23
		 */
		strcpy(CTZName, tm->tm_zone);
#endif
#else							/* ! USE_POSIX_TIME */
		CTimeZone = tb.timezone * 60;
		CDayLight = (tb.dstflag != 0);

		/*
		 * XXX does this work to get the local timezone string in V7? -
		 * tgl 97/03/18
		 */
		strftime(CTZName, MAXTZLEN, "%Z", localtime(&now));
97
#endif
98
	};
99 100

#ifdef DATEDEBUG
101 102
	printf("GetCurrentAbsoluteTime- timezone is %s -> %d seconds from UTC\n",
		   CTZName, CTimeZone);
103
#endif
104

105 106
	return ((AbsoluteTime) now);
}								/* GetCurrentAbsoluteTime() */
107 108


109
void
110
GetCurrentTime(struct tm * tm)
111
{
112
	int			tz;
113

114
	abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
115

116 117
	return;
}								/* 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 134
	if (tzp != NULL)
	{
135
		tx = localtime((time_t *) &time);
136 137 138
	}
	else
	{
139
		tx = gmtime((time_t *) &time);
140
	};
141 142
#else
#endif
143

144 145
#ifdef DATEDEBUG
#ifdef HAVE_INT_TIMEZONE
146 147 148
	printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s %s dst=%d\n",
		   tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
		   tzname[0], tzname[1], tx->tm_isdst);
149
#else
150 151 152
	printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s dst=%d\n",
		   tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
		   tx->tm_zone, tx->tm_isdst);
153 154 155 156
#endif
#else
#endif

157 158 159 160 161 162 163
	tm->tm_year = tx->tm_year + 1900;
	tm->tm_mon = tx->tm_mon + 1;
	tm->tm_mday = tx->tm_mday;
	tm->tm_hour = tx->tm_hour;
	tm->tm_min = tx->tm_min;
	tm->tm_sec = tx->tm_sec;
	tm->tm_isdst = tx->tm_isdst;
164 165 166

#ifdef USE_POSIX_TIME
#ifdef HAVE_INT_TIMEZONE
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
	if (tzp != NULL)
		*tzp = (tm->tm_isdst ? (timezone - 3600) : timezone);
	if (tzn != NULL)
		strcpy(tzn, tzname[tm->tm_isdst]);
#else							/* !HAVE_INT_TIMEZONE */
	tm->tm_gmtoff = tx->tm_gmtoff;
	tm->tm_zone = tx->tm_zone;

	if (tzp != NULL)
		*tzp = -tm->tm_gmtoff;	/* tm_gmtoff is Sun/DEC-ism */
	/* XXX FreeBSD man pages indicate that this should work - tgl 97/04/23 */
	if (tzn != NULL)
		strcpy(tzn, tm->tm_zone);
#endif
#else							/* ! USE_POSIX_TIME */
	if (tzp != NULL)
		*tzp = tb.timezone * 60;

	/*
	 * XXX does this work to get the local timezone string in V7? - tgl
	 * 97/03/18
	 */
	if (tzn != NULL)
		strftime(tzn, MAXTZLEN, "%Z", localtime(&now));
191
#endif
192

193 194
	return;
}								/* abstime2tm() */
195 196


197 198 199 200
/* tm2abstime()
 * Convert a tm structure to abstime.
 * Note that tm has full year (not 1900-based) and 1-based month.
 */
201
static AbsoluteTime
202
tm2abstime(struct tm * tm, int tz)
203
{
204 205
	int			day,
				sec;
206

207 208 209 210 211 212 213 214
	/* validate, before going out of range on some members */
	if (tm->tm_year < 1901 || tm->tm_year > 2038
		|| tm->tm_mon < 1 || tm->tm_mon > 12
		|| tm->tm_mday < 1 || tm->tm_mday > 31
		|| tm->tm_hour < 0 || tm->tm_hour >= 24
		|| tm->tm_min < 0 || tm->tm_min > 59
		|| tm->tm_sec < 0 || tm->tm_sec > 59)
		return (INVALID_ABSTIME);
215

216
	day = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(1970, 1, 1));
217

218 219 220
	/* check for time out of range */
	if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
		return (INVALID_ABSTIME);
221

222 223
	/* convert to seconds */
	sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
224

225 226 227 228
	/* check for overflow */
	if ((day == MAX_DAYNUM && sec < 0) ||
		(day == MIN_DAYNUM && sec > 0))
		return (INVALID_ABSTIME);
229

230 231 232
	/* check for reserved values (e.g. "current" on edge of usual range */
	if (!AbsoluteTimeIsReal(sec))
		return (INVALID_ABSTIME);
233

234 235
	return (sec);
}								/* tm2abstime() */
236 237


238 239
/* nabstimein()
 * Decode date/time string and return abstime.
240
 */
241
AbsoluteTime
242
nabstimein(char *str)
243
{
244
	AbsoluteTime result;
245

246 247 248 249
	double		fsec;
	int			tz = 0;
	struct tm	date,
			   *tm = &date;
250

251 252 253 254 255
	char	   *field[MAXDATEFIELDS];
	char		lowstr[MAXDATELEN + 1];
	int			dtype;
	int			nf,
				ftype[MAXDATEFIELDS];
256

257 258
	if (!PointerIsValid(str))
		elog(WARN, "Bad (null) abstime external representation", NULL);
259

260 261
	if (strlen(str) > MAXDATELEN)
		elog(WARN, "Bad (length) abstime external representation '%s'", str);
262

263 264 265
	if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
	  || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
		elog(WARN, "Bad abstime external representation '%s'", str);
266 267

#ifdef DATEDEBUG
268
	printf("nabstimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE);
269 270
#endif

271 272
	switch (dtype)
	{
273 274 275
		case DTK_DATE:
			result = tm2abstime(tm, tz);
			break;
276

277 278 279
		case DTK_EPOCH:
			result = EPOCH_ABSTIME;
			break;
280

281 282 283
		case DTK_CURRENT:
			result = CURRENT_ABSTIME;
			break;
284

285 286 287
		case DTK_LATE:
			result = NOEND_ABSTIME;
			break;
288

289 290 291
		case DTK_EARLY:
			result = NOSTART_ABSTIME;
			break;
292

293 294 295
		case DTK_INVALID:
			result = INVALID_ABSTIME;
			break;
296

297 298 299 300
		default:
			elog(WARN, "Bad abstime (internal coding error) '%s'", str);
			result = INVALID_ABSTIME;
			break;
301
	};
302

303 304
	return result;
}								/* nabstimein() */
305

306

307
/* nabstimeout()
308 309
 * Given an AbsoluteTime return the English text version of the date
 */
310
char	   *
311 312
nabstimeout(AbsoluteTime time)
{
313 314 315 316 317 318 319 320
	char	   *result;
	int			tz;
	double		fsec = 0;
	struct tm	tt,
			   *tm = &tt;
	char		buf[MAXDATELEN + 1];
	char		zone[MAXDATELEN + 1],
			   *tzn = zone;
321 322 323

	switch (time)
	{
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
		case EPOCH_ABSTIME:
			strcpy(buf, EPOCH);
			break;
		case INVALID_ABSTIME:
			strcpy(buf, INVALID);
			break;
		case CURRENT_ABSTIME:
			strcpy(buf, DCURRENT);
			break;
		case NOEND_ABSTIME:
			strcpy(buf, LATE);
			break;
		case NOSTART_ABSTIME:
			strcpy(buf, EARLY);
			break;
		default:
			abstime2tm(time, &tz, tm, tzn);
341 342
#if DATEDEBUG
#endif
343 344
			EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
			break;
345
	}
346

347 348
	result = PALLOC(strlen(buf) + 1);
	strcpy(result, buf);
349

350 351
	return (result);
}								/* nabstimeout() */
352 353 354


/*
355 356
 *	AbsoluteTimeIsBefore -- true iff time1 is before time2.
 *	AbsoluteTimeIsBefore -- true iff time1 is after time2.
357 358 359 360
 */
bool
AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2)
{
361 362
	Assert(AbsoluteTimeIsValid(time1));
	Assert(AbsoluteTimeIsValid(time2));
363

364 365
	if (time1 == CURRENT_ABSTIME)
		time1 = GetCurrentTransactionStartTime();
366

367 368
	if (time2 == CURRENT_ABSTIME)
		time2 = GetCurrentTransactionStartTime();
369

370
	return (time1 < time2);
371 372 373 374 375
}

bool
AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
{
376 377
	Assert(AbsoluteTimeIsValid(time1));
	Assert(AbsoluteTimeIsValid(time2));
378

379 380
	if (time1 == CURRENT_ABSTIME)
		time1 = GetCurrentTransactionStartTime();
381

382 383
	if (time2 == CURRENT_ABSTIME)
		time2 = GetCurrentTransactionStartTime();
384

385
	return (time1 > time2);
386 387 388
}


389 390 391 392 393
/* abstime_finite()
 */
bool
abstime_finite(AbsoluteTime abstime)
{
394 395
	return ((abstime != INVALID_ABSTIME)
		  && (abstime != NOSTART_ABSTIME) && (abstime != NOEND_ABSTIME));
T
Thomas G. Lockhart 已提交
396
} /* abstime_finite() */
397 398


399
/*
400 401 402 403 404 405
 *		abstimeeq		- returns 1, iff arguments are equal
 *		abstimene		- returns 1, iff arguments are not equal
 *		abstimelt		- returns 1, iff t1 less than t2
 *		abstimegt		- returns 1, iff t1 greater than t2
 *		abstimele		- returns 1, iff t1 less than or equal to t2
 *		abstimege		- returns 1, iff t1 greater than or equal to t2
406
 */
407
bool
408 409
abstimeeq(AbsoluteTime t1, AbsoluteTime t2)
{
410 411 412 413 414 415 416 417
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
		return (FALSE);
	if (t1 == CURRENT_ABSTIME)
		t1 = GetCurrentTransactionStartTime();
	if (t2 == CURRENT_ABSTIME)
		t2 = GetCurrentTransactionStartTime();

	return (t1 == t2);
418 419
}

420
bool
421
abstimene(AbsoluteTime t1, AbsoluteTime t2)
422 423 424 425 426 427 428 429 430
{
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
		return (FALSE);
	if (t1 == CURRENT_ABSTIME)
		t1 = GetCurrentTransactionStartTime();
	if (t2 == CURRENT_ABSTIME)
		t2 = GetCurrentTransactionStartTime();

	return (t1 != t2);
431 432
}

433
bool
434
abstimelt(AbsoluteTime t1, AbsoluteTime t2)
435 436 437 438 439 440 441 442 443
{
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
		return (FALSE);
	if (t1 == CURRENT_ABSTIME)
		t1 = GetCurrentTransactionStartTime();
	if (t2 == CURRENT_ABSTIME)
		t2 = GetCurrentTransactionStartTime();

	return (t1 < t2);
444 445
}

446
bool
447
abstimegt(AbsoluteTime t1, AbsoluteTime t2)
448 449 450 451 452 453 454 455 456
{
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
		return (FALSE);
	if (t1 == CURRENT_ABSTIME)
		t1 = GetCurrentTransactionStartTime();
	if (t2 == CURRENT_ABSTIME)
		t2 = GetCurrentTransactionStartTime();

	return (t1 > t2);
457 458
}

459
bool
460
abstimele(AbsoluteTime t1, AbsoluteTime t2)
461 462 463 464 465 466 467 468 469
{
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
		return (FALSE);
	if (t1 == CURRENT_ABSTIME)
		t1 = GetCurrentTransactionStartTime();
	if (t2 == CURRENT_ABSTIME)
		t2 = GetCurrentTransactionStartTime();

	return (t1 <= t2);
470 471
}

472
bool
473
abstimege(AbsoluteTime t1, AbsoluteTime t2)
474 475 476 477 478 479 480 481 482
{
	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
		return (FALSE);
	if (t1 == CURRENT_ABSTIME)
		t1 = GetCurrentTransactionStartTime();
	if (t2 == CURRENT_ABSTIME)
		t2 = GetCurrentTransactionStartTime();

	return (t1 >= t2);
483
}
484

485

486 487 488 489
/* datetime_abstime()
 * Convert datetime to abstime.
 */
AbsoluteTime
490
datetime_abstime(DateTime *datetime)
491
{
492
	AbsoluteTime result;
493

494 495 496
	double		fsec;
	struct tm	tt,
			   *tm = &tt;
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534

	if (!PointerIsValid(datetime))
	{
		result = INVALID_ABSTIME;

	}
	else if (DATETIME_IS_INVALID(*datetime))
	{
		result = INVALID_ABSTIME;

	}
	else if (DATETIME_IS_NOBEGIN(*datetime))
	{
		result = NOSTART_ABSTIME;

	}
	else if (DATETIME_IS_NOEND(*datetime))
	{
		result = NOEND_ABSTIME;

	}
	else
	{
		if (DATETIME_IS_RELATIVE(*datetime))
		{
			datetime2tm(SetDateTime(*datetime), NULL, tm, &fsec, NULL);
			result = tm2abstime(tm, 0);

		}
		else if (datetime2tm(*datetime, NULL, tm, &fsec, NULL) == 0)
		{
			result = tm2abstime(tm, 0);

		}
		else
		{
			result = INVALID_ABSTIME;
		};
535 536
	};

537
	return (result);
T
Thomas G. Lockhart 已提交
538
} /* datetime_abstime() */
539 540

/* abstime_datetime()
T
Thomas G. Lockhart 已提交
541
 * Convert abstime to datetime.
542
 */
543
DateTime   *
544 545
abstime_datetime(AbsoluteTime abstime)
{
546
	DateTime   *result;
547

548 549
	if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
		elog(WARN, "Unable to allocate space to convert abstime to datetime", NULL);
550

551 552
	switch (abstime)
	{
553 554 555
		case INVALID_ABSTIME:
			DATETIME_INVALID(*result);
			break;
556

557 558 559
		case NOSTART_ABSTIME:
			DATETIME_NOBEGIN(*result);
			break;
560

561 562 563
		case NOEND_ABSTIME:
			DATETIME_NOEND(*result);
			break;
564

565 566 567
		case EPOCH_ABSTIME:
			DATETIME_EPOCH(*result);
			break;
568

569 570 571
		case CURRENT_ABSTIME:
			DATETIME_CURRENT(*result);
			break;
572

573 574 575
		default:
			*result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400);
			break;
576
	};
577

578
	return (result);
T
Thomas G. Lockhart 已提交
579
} /* abstime_datetime() */