Skip to content

Commit 4d745da

Browse files
author
Thomas G. Lockhart
committed
Modify date->timestamp conversion to use mktime().
This should do better than before around Daylight Savings Time transitions.
1 parent 3bb2838 commit 4d745da

File tree

2 files changed

+31
-102
lines changed

2 files changed

+31
-102
lines changed

src/backend/utils/adt/date.c

Lines changed: 28 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.49 2000/07/12 22:59:08 petere Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.50 2000/09/12 05:41:37 thomas Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -25,10 +25,6 @@
2525
#include "utils/nabstime.h"
2626

2727

28-
static int date2tm(DateADT dateVal, int *tzp, struct tm * tm,
29-
double *fsec, char **tzn);
30-
31-
3228
/*****************************************************************************
3329
* Date ADT
3430
*****************************************************************************/
@@ -230,15 +226,34 @@ date_timestamp(PG_FUNCTION_ARGS)
230226
Timestamp result;
231227
struct tm tt,
232228
*tm = &tt;
233-
int tz;
234-
double fsec = 0;
235-
char *tzn;
229+
time_t utime;
236230

237-
if (date2tm(dateVal, &tz, tm, &fsec, &tzn) != 0)
238-
elog(ERROR, "Unable to convert date to timestamp");
231+
j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
239232

240-
if (tm2timestamp(tm, fsec, &tz, &result) != 0)
241-
elog(ERROR, "Timestamp out of range");
233+
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
234+
{
235+
#ifdef USE_POSIX_TIME
236+
tm->tm_hour = 0;
237+
tm->tm_min = 0;
238+
tm->tm_sec = 0;
239+
tm->tm_isdst = -1;
240+
241+
tm->tm_year -= 1900;
242+
tm->tm_mon -= 1;
243+
utime = mktime(tm);
244+
if (utime == -1)
245+
elog(ERROR, "Unable to convert date to tm");
246+
247+
result = utime + ((date2j(1970,1,1)-date2j(2000,1,1))*86400.0);
248+
#else /* !USE_POSIX_TIME */
249+
result = dateVal*86400.0+CTimeZone;
250+
#endif
251+
}
252+
else
253+
{
254+
/* Outside of range for timezone support, so assume UTC */
255+
result = dateVal*86400.0;
256+
}
242257

243258
PG_RETURN_TIMESTAMP(result);
244259
}
@@ -324,81 +339,6 @@ abstime_date(PG_FUNCTION_ARGS)
324339
}
325340

326341

327-
/* date2tm()
328-
* Convert date to time structure.
329-
* Note that date is an implicit local time, but the system calls assume
330-
* that everything is GMT. So, convert to GMT, rotate to local time,
331-
* and then convert again to try to get the time zones correct.
332-
*/
333-
static int
334-
date2tm(DateADT dateVal, int *tzp, struct tm * tm, double *fsec, char **tzn)
335-
{
336-
struct tm *tx;
337-
time_t utime;
338-
339-
*fsec = 0;
340-
341-
j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
342-
tm->tm_hour = 0;
343-
tm->tm_min = 0;
344-
tm->tm_sec = 0;
345-
tm->tm_isdst = -1;
346-
347-
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
348-
{
349-
350-
/* convert to system time */
351-
utime = ((dateVal + (date2j(2000, 1, 1) - date2j(1970, 1, 1))) * 86400);
352-
/* rotate to noon to get the right day in time zone */
353-
utime += (12 * 60 * 60);
354-
355-
#ifdef USE_POSIX_TIME
356-
tx = localtime(&utime);
357-
358-
tm->tm_year = tx->tm_year + 1900;
359-
tm->tm_mon = tx->tm_mon + 1;
360-
tm->tm_mday = tx->tm_mday;
361-
tm->tm_isdst = tx->tm_isdst;
362-
363-
#if defined(HAVE_TM_ZONE)
364-
tm->tm_gmtoff = tx->tm_gmtoff;
365-
tm->tm_zone = tx->tm_zone;
366-
367-
/* tm_gmtoff is Sun/DEC-ism */
368-
*tzp = -(tm->tm_gmtoff);
369-
if (tzn != NULL)
370-
*tzn = (char *) tm->tm_zone;
371-
#elif defined(HAVE_INT_TIMEZONE)
372-
#ifdef __CYGWIN__
373-
*tzp = (tm->tm_isdst ? (_timezone - 3600) : _timezone);
374-
#else
375-
*tzp = (tm->tm_isdst ? (timezone - 3600) : timezone);
376-
#endif
377-
if (tzn != NULL)
378-
*tzn = tzname[(tm->tm_isdst > 0)];
379-
#else
380-
#error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined
381-
#endif
382-
#else /* !USE_POSIX_TIME */
383-
*tzp = CTimeZone; /* V7 conventions; don't know timezone? */
384-
if (tzn != NULL)
385-
*tzn = CTZName;
386-
#endif
387-
388-
/* otherwise, outside of timezone range so convert to GMT... */
389-
}
390-
else
391-
{
392-
*tzp = 0;
393-
tm->tm_isdst = 0;
394-
if (tzn != NULL)
395-
*tzn = NULL;
396-
}
397-
398-
return 0;
399-
} /* date2tm() */
400-
401-
402342
/*****************************************************************************
403343
* Time ADT
404344
*****************************************************************************/
@@ -906,19 +846,8 @@ datetimetz_timestamp(PG_FUNCTION_ARGS)
906846
DateADT date = PG_GETARG_DATEADT(0);
907847
TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
908848
Timestamp result;
909-
struct tm tt,
910-
*tm = &tt;
911-
int tz;
912-
double fsec = 0;
913-
char *tzn;
914-
915-
if (date2tm(date, &tz, tm, &fsec, &tzn) != 0)
916-
elog(ERROR, "Unable to convert date to timestamp");
917-
918-
if (tm2timestamp(tm, fsec, &time->zone, &result) != 0)
919-
elog(ERROR, "Timestamp out of range");
920849

921-
result += time->time;
850+
result = date*86400.0 + time->time + time->zone;
922851

923852
PG_RETURN_TIMESTAMP(result);
924853
}

src/backend/utils/adt/datetime.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.52 2000/07/14 15:33:33 thomas Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.53 2000/09/12 05:41:37 thomas Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -2247,8 +2247,8 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
22472247
sprintf(cp, "%s%02d:%02d", (is_nonzero ? " " : ""),
22482248
abs(tm->tm_hour), abs(tm->tm_min));
22492249
cp += strlen(cp);
2250-
if ((tm->tm_hour != 0) || (tm->tm_min != 0))
2251-
is_nonzero = TRUE;
2250+
/* Mark as "non-zero" since the fields are now filled in */
2251+
is_nonzero = TRUE;
22522252

22532253
/* fractional seconds? */
22542254
if (fsec != 0)

0 commit comments

Comments
 (0)