@@ -52,8 +52,9 @@ static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec,
52
52
int scale );
53
53
static int DetermineTimeZoneOffsetInternal (struct pg_tm * tm ,pg_tz * tzp ,
54
54
pg_time_t * tp );
55
- static int DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t ,const char * abbr ,
56
- pg_tz * tzp ,int * isdst );
55
+ static bool DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t ,
56
+ const char * abbr ,pg_tz * tzp ,
57
+ int * offset ,int * isdst );
57
58
static pg_tz * FetchDynamicTimeZone (TimeZoneAbbrevTable * tbl ,const datetkn * tp );
58
59
59
60
@@ -1620,19 +1621,40 @@ DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp, pg_time_t *tp)
1620
1621
* This differs from the behavior of DetermineTimeZoneOffset() in that a
1621
1622
* standard-time or daylight-time abbreviation forces use of the corresponding
1622
1623
* GMT offset even when the zone was then in DS or standard time respectively.
1624
+ * (However, that happens only if we can match the given abbreviation to some
1625
+ * abbreviation that appears in the IANA timezone data. Otherwise, we fall
1626
+ * back to doing DetermineTimeZoneOffset().)
1623
1627
*/
1624
1628
int
1625
1629
DetermineTimeZoneAbbrevOffset (struct pg_tm * tm ,const char * abbr ,pg_tz * tzp )
1626
1630
{
1627
1631
pg_time_t t ;
1632
+ int zone_offset ;
1633
+ int abbr_offset ;
1634
+ int abbr_isdst ;
1628
1635
1629
1636
/*
1630
1637
* Compute the UTC time we want to probe at. (In event of overflow, we'll
1631
1638
* probe at the epoch, which is a bit random but probably doesn't matter.)
1632
1639
*/
1633
- ( void ) DetermineTimeZoneOffsetInternal (tm ,tzp ,& t );
1640
+ zone_offset = DetermineTimeZoneOffsetInternal (tm ,tzp ,& t );
1634
1641
1635
- return DetermineTimeZoneAbbrevOffsetInternal (t ,abbr ,tzp ,& tm -> tm_isdst );
1642
+ /*
1643
+ * Try to match the abbreviation to something in the zone definition.
1644
+ */
1645
+ if (DetermineTimeZoneAbbrevOffsetInternal (t ,abbr ,tzp ,
1646
+ & abbr_offset ,& abbr_isdst ))
1647
+ {
1648
+ /* Success, so use the abbrev-specific answers. */
1649
+ tm -> tm_isdst = abbr_isdst ;
1650
+ return abbr_offset ;
1651
+ }
1652
+
1653
+ /*
1654
+ * No match, so use the answers we already got from
1655
+ * DetermineTimeZoneOffsetInternal.
1656
+ */
1657
+ return zone_offset ;
1636
1658
}
1637
1659
1638
1660
@@ -1646,19 +1668,41 @@ DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr,
1646
1668
pg_tz * tzp ,int * isdst )
1647
1669
{
1648
1670
pg_time_t t = timestamptz_to_time_t (ts );
1671
+ int zone_offset ;
1672
+ int abbr_offset ;
1673
+ int tz ;
1674
+ struct pg_tm tm ;
1675
+ fsec_t fsec ;
1649
1676
1650
- return DetermineTimeZoneAbbrevOffsetInternal (t ,abbr ,tzp ,isdst );
1677
+ /*
1678
+ * If the abbrev matches anything in the zone data, this is pretty easy.
1679
+ */
1680
+ if (DetermineTimeZoneAbbrevOffsetInternal (t ,abbr ,tzp ,
1681
+ & abbr_offset ,isdst ))
1682
+ return abbr_offset ;
1683
+
1684
+ /*
1685
+ * Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1686
+ */
1687
+ if (timestamp2tm (ts ,& tz ,& tm ,& fsec ,NULL ,tzp )!= 0 )
1688
+ ereport (ERROR ,
1689
+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
1690
+ errmsg ("timestamp out of range" )));
1691
+
1692
+ zone_offset = DetermineTimeZoneOffset (& tm ,tzp );
1693
+ * isdst = tm .tm_isdst ;
1694
+ return zone_offset ;
1651
1695
}
1652
1696
1653
1697
1654
1698
/* DetermineTimeZoneAbbrevOffsetInternal()
1655
1699
*
1656
1700
* Workhorse for above two functions: work from a pg_time_t probe instant.
1657
- * DST statusis returned into *isdst.
1701
+ *On success, return GMT offset and DST statusinto *offset and *isdst.
1658
1702
*/
1659
- static int
1660
- DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t ,const char * abbr ,
1661
- pg_tz * tzp ,int * isdst )
1703
+ static bool
1704
+ DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t ,const char * abbr ,pg_tz * tzp ,
1705
+ int * offset ,int * isdst )
1662
1706
{
1663
1707
char upabbr [TZ_STRLEN_MAX + 1 ];
1664
1708
unsignedchar * p ;
@@ -1670,18 +1714,17 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr,
1670
1714
* p = pg_toupper (* p );
1671
1715
1672
1716
/* Look up the abbrev's meaning at this time in this zone */
1673
- if (!pg_interpret_timezone_abbrev (upabbr ,
1674
- & t ,
1675
- & gmtoff ,
1676
- isdst ,
1677
- tzp ))
1678
- ereport (ERROR ,
1679
- (errcode (ERRCODE_CONFIG_FILE_ERROR ),
1680
- errmsg ("time zone abbreviation \"%s\" is not used in time zone \"%s\"" ,
1681
- abbr ,pg_get_timezone_name (tzp ))));
1682
-
1683
- /* Change sign to agree with DetermineTimeZoneOffset() */
1684
- return (int )- gmtoff ;
1717
+ if (pg_interpret_timezone_abbrev (upabbr ,
1718
+ & t ,
1719
+ & gmtoff ,
1720
+ isdst ,
1721
+ tzp ))
1722
+ {
1723
+ /* Change sign to agree with DetermineTimeZoneOffset() */
1724
+ * offset = (int )- gmtoff ;
1725
+ return true;
1726
+ }
1727
+ return false;
1685
1728
}
1686
1729
1687
1730