8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.116 2003/08/27 23:29:28 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.117 2003/09/13 21:12:38 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -1570,9 +1570,10 @@ DecodeDateTime(char **field, int *ftype, int nf,
1570
1570
* (ie, regular or daylight-savings time) at that time. Set the struct tm's
1571
1571
* tm_isdst field accordingly, and return the actual timezone offset.
1572
1572
*
1573
- * This subroutine exists to centralize uses of mktime() and defend against
1574
- * mktime() bugs/restrictions on various platforms. This should be
1575
- * the *only* call of mktime() in the backend.
1573
+ * Note: this subroutine exists because mktime() has such a spectacular
1574
+ * variety of, ahem, odd behaviors on various platforms. We used to try to
1575
+ * use mktime() here, but finally gave it up as a bad job. Avoid using
1576
+ * mktime() anywhere else.
1576
1577
*/
1577
1578
int
1578
1579
DetermineLocalTimeZone (struct tm * tm )
@@ -1586,117 +1587,78 @@ DetermineLocalTimeZone(struct tm * tm)
1586
1587
}
1587
1588
else if (IS_VALID_UTIME (tm -> tm_year , tm -> tm_mon , tm -> tm_mday ))
1588
1589
{
1589
- #if defined(HAVE_TM_ZONE ) || defined(HAVE_INT_TIMEZONE )
1590
+ /*
1591
+ * First, generate the time_t value corresponding to the given
1592
+ * y/m/d/h/m/s taken as GMT time. This will not overflow (at
1593
+ * least not for time_t taken as signed) because of the range
1594
+ * check we did above.
1595
+ */
1596
+ long day ,
1597
+ mysec ,
1598
+ locsec ,
1599
+ delta1 ,
1600
+ delta2 ;
1601
+ time_t mytime ;
1602
+ struct tm * tx ;
1603
+
1604
+ day = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday ) - UNIX_EPOCH_JDATE ;
1605
+ mysec = tm -> tm_sec + (tm -> tm_min + (day * 24 + tm -> tm_hour ) * 60 ) * 60 ;
1606
+ mytime = (time_t ) mysec ;
1590
1607
1591
1608
/*
1592
- * Some buggy mktime() implementations may change the
1593
- * year/month/day when given a time right at a DST boundary. To
1594
- * prevent corruption of the caller's data, give mktime() a
1595
- * copy...
1609
+ * Use localtime to convert that time_t to broken-down time,
1610
+ * and reassemble to get a representation of local time.
1596
1611
*/
1597
- struct tm tt ,
1598
- * tmp = & tt ;
1612
+ tx = localtime (& mytime );
1613
+ day = date2j (tx -> tm_year + 1900 , tx -> tm_mon + 1 , tx -> tm_mday ) -
1614
+ UNIX_EPOCH_JDATE ;
1615
+ locsec = tx -> tm_sec + (tx -> tm_min + (day * 24 + tx -> tm_hour ) * 60 ) * 60 ;
1599
1616
1600
- * tmp = * tm ;
1601
- /* change to Unix conventions for year/month */
1602
- tmp -> tm_year -= 1900 ;
1603
- tmp -> tm_mon -= 1 ;
1617
+ /*
1618
+ * The local time offset corresponding to that GMT time is now
1619
+ * computable as mysec - locsec.
1620
+ */
1621
+ delta1 = mysec - locsec ;
1604
1622
1605
- /* indicate timezone unknown */
1606
- tmp -> tm_isdst = -1 ;
1623
+ /*
1624
+ * However, if that GMT time and the local time we are
1625
+ * actually interested in are on opposite sides of a
1626
+ * daylight-savings-time transition, then this is not the time
1627
+ * offset we want. So, adjust the time_t to be what we think
1628
+ * the GMT time corresponding to our target local time is, and
1629
+ * repeat the localtime() call and delta calculation.
1630
+ */
1631
+ mysec += delta1 ;
1632
+ mytime = (time_t ) mysec ;
1633
+ tx = localtime (& mytime );
1634
+ day = date2j (tx -> tm_year + 1900 , tx -> tm_mon + 1 , tx -> tm_mday ) -
1635
+ UNIX_EPOCH_JDATE ;
1636
+ locsec = tx -> tm_sec + (tx -> tm_min + (day * 24 + tx -> tm_hour ) * 60 ) * 60 ;
1637
+ delta2 = mysec - locsec ;
1607
1638
1608
- if (mktime (tmp ) != ((time_t ) - 1 ) &&
1609
- tmp -> tm_isdst >= 0 )
1610
- {
1611
- /* mktime() succeeded, trust its result */
1612
- tm -> tm_isdst = tmp -> tm_isdst ;
1613
-
1614
- #if defined(HAVE_TM_ZONE )
1615
- /* tm_gmtoff is Sun/DEC-ism */
1616
- tz = - (tmp -> tm_gmtoff );
1617
- #elif defined(HAVE_INT_TIMEZONE )
1618
- tz = ((tmp -> tm_isdst > 0 ) ? (TIMEZONE_GLOBAL - 3600 ) : TIMEZONE_GLOBAL );
1619
- #endif /* HAVE_INT_TIMEZONE */
1620
- }
1621
- else
1639
+ /*
1640
+ * We may have to do it again to get the correct delta.
1641
+ *
1642
+ * It might seem we should just loop until we get the same delta
1643
+ * twice in a row, but if we've been given an "impossible" local
1644
+ * time (in the gap during a spring-forward transition) we'd never
1645
+ * get out of the loop. The behavior we want is that "impossible"
1646
+ * times are taken as standard time, and also that ambiguous times
1647
+ * (during a fall-back transition) are taken as standard time.
1648
+ * Therefore, we bias the code to prefer the standard-time solution.
1649
+ */
1650
+ if (delta2 != delta1 && tx -> tm_isdst != 0 )
1622
1651
{
1623
- /*
1624
- * We have a buggy (not to say deliberately brain damaged)
1625
- * mktime(). Work around it by using localtime() instead.
1626
- *
1627
- * First, generate the time_t value corresponding to the given
1628
- * y/m/d/h/m/s taken as GMT time. This will not overflow (at
1629
- * least not for time_t taken as signed) because of the range
1630
- * check we did above.
1631
- */
1632
- long day ,
1633
- mysec ,
1634
- locsec ,
1635
- delta1 ,
1636
- delta2 ;
1637
- time_t mytime ;
1638
-
1639
- day = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday ) - UNIX_EPOCH_JDATE ;
1640
- mysec = tm -> tm_sec + (tm -> tm_min + (day * 24 + tm -> tm_hour ) * 60 ) * 60 ;
1652
+ mysec += (delta2 - delta1 );
1641
1653
mytime = (time_t ) mysec ;
1642
-
1643
- /*
1644
- * Use localtime to convert that time_t to broken-down time,
1645
- * and reassemble to get a representation of local time.
1646
- */
1647
- tmp = localtime (& mytime );
1648
- day = date2j (tmp -> tm_year + 1900 , tmp -> tm_mon + 1 , tmp -> tm_mday ) -
1649
- UNIX_EPOCH_JDATE ;
1650
- locsec = tmp -> tm_sec + (tmp -> tm_min + (day * 24 + tmp -> tm_hour ) * 60 ) * 60 ;
1651
-
1652
- /*
1653
- * The local time offset corresponding to that GMT time is now
1654
- * computable as mysec - locsec.
1655
- */
1656
- delta1 = mysec - locsec ;
1657
-
1658
- /*
1659
- * However, if that GMT time and the local time we are
1660
- * actually interested in are on opposite sides of a
1661
- * daylight-savings-time transition, then this is not the time
1662
- * offset we want. So, adjust the time_t to be what we think
1663
- * the GMT time corresponding to our target local time is, and
1664
- * repeat the localtime() call and delta calculation. We may
1665
- * have to do it twice before we have a trustworthy delta.
1666
- *
1667
- * Note: think not to put a loop here, since if we've been given
1668
- * an "impossible" local time (in the gap during a
1669
- * spring-forward transition) we'd never get out of the loop.
1670
- * Twice is enough to give the behavior we want, which is that
1671
- * "impossible" times are taken as standard time, while at a
1672
- * fall-back boundary ambiguous times are also taken as
1673
- * standard.
1674
- */
1675
- mysec += delta1 ;
1676
- mytime = (time_t ) mysec ;
1677
- tmp = localtime (& mytime );
1678
- day = date2j (tmp -> tm_year + 1900 , tmp -> tm_mon + 1 , tmp -> tm_mday ) -
1654
+ tx = localtime (& mytime );
1655
+ day = date2j (tx -> tm_year + 1900 , tx -> tm_mon + 1 , tx -> tm_mday ) -
1679
1656
UNIX_EPOCH_JDATE ;
1680
- locsec = tmp -> tm_sec + (tmp -> tm_min + (day * 24 + tmp -> tm_hour ) * 60 ) * 60 ;
1657
+ locsec = tx -> tm_sec + (tx -> tm_min + (day * 24 + tx -> tm_hour ) * 60 ) * 60 ;
1681
1658
delta2 = mysec - locsec ;
1682
- if (delta2 != delta1 )
1683
- {
1684
- mysec += (delta2 - delta1 );
1685
- mytime = (time_t ) mysec ;
1686
- tmp = localtime (& mytime );
1687
- day = date2j (tmp -> tm_year + 1900 , tmp -> tm_mon + 1 , tmp -> tm_mday ) -
1688
- UNIX_EPOCH_JDATE ;
1689
- locsec = tmp -> tm_sec + (tmp -> tm_min + (day * 24 + tmp -> tm_hour ) * 60 ) * 60 ;
1690
- delta2 = mysec - locsec ;
1691
- }
1692
- tm -> tm_isdst = tmp -> tm_isdst ;
1693
- tz = (int ) delta2 ;
1694
1659
}
1695
- #else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
1696
- /* Assume UTC if no system timezone info available */
1697
- tm -> tm_isdst = 0 ;
1698
- tz = 0 ;
1699
- #endif
1660
+ tm -> tm_isdst = tx -> tm_isdst ;
1661
+ tz = (int ) delta2 ;
1700
1662
}
1701
1663
else
1702
1664
{
0 commit comments