@@ -56,8 +56,9 @@ static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec,
56
56
int scale );
57
57
static int DetermineTimeZoneOffsetInternal (struct pg_tm * tm ,pg_tz * tzp ,
58
58
pg_time_t * tp );
59
- static int DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t ,const char * abbr ,
60
- pg_tz * tzp ,int * isdst );
59
+ static bool DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t ,
60
+ const char * abbr ,pg_tz * tzp ,
61
+ int * offset ,int * isdst );
61
62
static pg_tz * FetchDynamicTimeZone (TimeZoneAbbrevTable * tbl ,const datetkn * tp );
62
63
63
64
@@ -1689,19 +1690,40 @@ DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp, pg_time_t *tp)
1689
1690
* This differs from the behavior of DetermineTimeZoneOffset() in that a
1690
1691
* standard-time or daylight-time abbreviation forces use of the corresponding
1691
1692
* GMT offset even when the zone was then in DS or standard time respectively.
1693
+ * (However, that happens only if we can match the given abbreviation to some
1694
+ * abbreviation that appears in the IANA timezone data. Otherwise, we fall
1695
+ * back to doing DetermineTimeZoneOffset().)
1692
1696
*/
1693
1697
int
1694
1698
DetermineTimeZoneAbbrevOffset (struct pg_tm * tm ,const char * abbr ,pg_tz * tzp )
1695
1699
{
1696
1700
pg_time_t t ;
1701
+ int zone_offset ;
1702
+ int abbr_offset ;
1703
+ int abbr_isdst ;
1697
1704
1698
1705
/*
1699
1706
* Compute the UTC time we want to probe at. (In event of overflow, we'll
1700
1707
* probe at the epoch, which is a bit random but probably doesn't matter.)
1701
1708
*/
1702
- ( void ) DetermineTimeZoneOffsetInternal (tm ,tzp ,& t );
1709
+ zone_offset = DetermineTimeZoneOffsetInternal (tm ,tzp ,& t );
1703
1710
1704
- return DetermineTimeZoneAbbrevOffsetInternal (t ,abbr ,tzp ,& tm -> tm_isdst );
1711
+ /*
1712
+ * Try to match the abbreviation to something in the zone definition.
1713
+ */
1714
+ if (DetermineTimeZoneAbbrevOffsetInternal (t ,abbr ,tzp ,
1715
+ & abbr_offset ,& abbr_isdst ))
1716
+ {
1717
+ /* Success, so use the abbrev-specific answers. */
1718
+ tm -> tm_isdst = abbr_isdst ;
1719
+ return abbr_offset ;
1720
+ }
1721
+
1722
+ /*
1723
+ * No match, so use the answers we already got from
1724
+ * DetermineTimeZoneOffsetInternal.
1725
+ */
1726
+ return zone_offset ;
1705
1727
}
1706
1728
1707
1729
@@ -1715,19 +1737,41 @@ DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr,
1715
1737
pg_tz * tzp ,int * isdst )
1716
1738
{
1717
1739
pg_time_t t = timestamptz_to_time_t (ts );
1740
+ int zone_offset ;
1741
+ int abbr_offset ;
1742
+ int tz ;
1743
+ struct pg_tm tm ;
1744
+ fsec_t fsec ;
1718
1745
1719
- return DetermineTimeZoneAbbrevOffsetInternal (t ,abbr ,tzp ,isdst );
1746
+ /*
1747
+ * If the abbrev matches anything in the zone data, this is pretty easy.
1748
+ */
1749
+ if (DetermineTimeZoneAbbrevOffsetInternal (t ,abbr ,tzp ,
1750
+ & abbr_offset ,isdst ))
1751
+ return abbr_offset ;
1752
+
1753
+ /*
1754
+ * Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1755
+ */
1756
+ if (timestamp2tm (ts ,& tz ,& tm ,& fsec ,NULL ,tzp )!= 0 )
1757
+ ereport (ERROR ,
1758
+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
1759
+ errmsg ("timestamp out of range" )));
1760
+
1761
+ zone_offset = DetermineTimeZoneOffset (& tm ,tzp );
1762
+ * isdst = tm .tm_isdst ;
1763
+ return zone_offset ;
1720
1764
}
1721
1765
1722
1766
1723
1767
/* DetermineTimeZoneAbbrevOffsetInternal()
1724
1768
*
1725
1769
* Workhorse for above two functions: work from a pg_time_t probe instant.
1726
- * DST statusis returned into *isdst.
1770
+ *On success, return GMT offset and DST statusinto *offset and *isdst.
1727
1771
*/
1728
- static int
1729
- DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t ,const char * abbr ,
1730
- pg_tz * tzp ,int * isdst )
1772
+ static bool
1773
+ DetermineTimeZoneAbbrevOffsetInternal (pg_time_t t ,const char * abbr ,pg_tz * tzp ,
1774
+ int * offset ,int * isdst )
1731
1775
{
1732
1776
char upabbr [TZ_STRLEN_MAX + 1 ];
1733
1777
unsignedchar * p ;
@@ -1739,18 +1783,17 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr,
1739
1783
* p = pg_toupper (* p );
1740
1784
1741
1785
/* Look up the abbrev's meaning at this time in this zone */
1742
- if (!pg_interpret_timezone_abbrev (upabbr ,
1743
- & t ,
1744
- & gmtoff ,
1745
- isdst ,
1746
- tzp ))
1747
- ereport (ERROR ,
1748
- (errcode (ERRCODE_CONFIG_FILE_ERROR ),
1749
- errmsg ("time zone abbreviation \"%s\" is not used in time zone \"%s\"" ,
1750
- abbr ,pg_get_timezone_name (tzp ))));
1751
-
1752
- /* Change sign to agree with DetermineTimeZoneOffset() */
1753
- return (int )- gmtoff ;
1786
+ if (pg_interpret_timezone_abbrev (upabbr ,
1787
+ & t ,
1788
+ & gmtoff ,
1789
+ isdst ,
1790
+ tzp ))
1791
+ {
1792
+ /* Change sign to agree with DetermineTimeZoneOffset() */
1793
+ * offset = (int )- gmtoff ;
1794
+ return true;
1795
+ }
1796
+ return false;
1754
1797
}
1755
1798
1756
1799