Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 55c3a04

Browse files
committed
Fix assorted breakage in to_char()'s OF format option.
In HEAD, fix incorrect field width for hours part of OF when tm_gmtoff is negative. This was introduced by commit 2d87eed as a result of falsely applying a pattern that's correct when + signs are omitted, which is not the case for OF. In 9.4, fix missing abs() call that allowed a sign to be attached to the minutes part of OF. This was fixed in 9.5 by 9b43d73, but for inscrutable reasons not back-patched. In all three versions, ensure that the sign of tm_gmtoff is correctly reported even when the GMT offset is less than 1 hour. Add regression tests, which evidently we desperately need here. Thomas Munro and Tom Lane, per report from David Fetter
1 parent f4ceed6 commit 55c3a04

File tree

3 files changed

+75
-4
lines changed

3 files changed

+75
-4
lines changed

src/backend/utils/adt/formatting.c

+7-4
Original file line numberDiff line numberDiff line change
@@ -2506,12 +2506,15 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25062506
break;
25072507
case DCH_OF:
25082508
INVALID_FOR_INTERVAL;
2509-
sprintf(s, "%+0*d", S_FM(n->suffix) ? 0 : (tm->tm_gmtoff >= 0) ? 3 : 4,
2510-
(int) tm->tm_gmtoff / SECS_PER_HOUR);
2509+
sprintf(s, "%c%0*d",
2510+
(tm->tm_gmtoff >= 0) ? '+' : '-',
2511+
S_FM(n->suffix) ? 0 : 2,
2512+
abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
25112513
s += strlen(s);
2512-
if ((int) tm->tm_gmtoff % SECS_PER_HOUR != 0)
2514+
if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
25132515
{
2514-
sprintf(s, ":%02d", abs((int) tm->tm_gmtoff % SECS_PER_HOUR) / SECS_PER_MINUTE);
2516+
sprintf(s, ":%02d",
2517+
(abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
25152518
s += strlen(s);
25162519
}
25172520
break;

src/test/regress/expected/timestamptz.out

+51
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,57 @@ SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
16991699
| 2001 1 1 1 1 1 1
17001700
(66 rows)
17011701

1702+
-- Check OF with various zone offsets, particularly fractional hours
1703+
SET timezone = '00:00';
1704+
SELECT to_char(now(), 'OF');
1705+
to_char
1706+
---------
1707+
+00
1708+
(1 row)
1709+
1710+
SET timezone = '+02:00';
1711+
SELECT to_char(now(), 'OF');
1712+
to_char
1713+
---------
1714+
-02
1715+
(1 row)
1716+
1717+
SET timezone = '-13:00';
1718+
SELECT to_char(now(), 'OF');
1719+
to_char
1720+
---------
1721+
+13
1722+
(1 row)
1723+
1724+
SET timezone = '-00:30';
1725+
SELECT to_char(now(), 'OF');
1726+
to_char
1727+
---------
1728+
+00:30
1729+
(1 row)
1730+
1731+
SET timezone = '00:30';
1732+
SELECT to_char(now(), 'OF');
1733+
to_char
1734+
---------
1735+
-00:30
1736+
(1 row)
1737+
1738+
SET timezone = '-04:30';
1739+
SELECT to_char(now(), 'OF');
1740+
to_char
1741+
---------
1742+
+04:30
1743+
(1 row)
1744+
1745+
SET timezone = '04:30';
1746+
SELECT to_char(now(), 'OF');
1747+
to_char
1748+
---------
1749+
-04:30
1750+
(1 row)
1751+
1752+
RESET timezone;
17021753
CREATE TABLE TIMESTAMPTZ_TST (a int , b timestamptz);
17031754
-- Test year field value with len > 4
17041755
INSERT INTO TIMESTAMPTZ_TST VALUES(1, 'Sat Mar 12 23:58:48 1000 IST');

src/test/regress/sql/timestamptz.sql

+17
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,23 @@ SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID')
248248
SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
249249
FROM TIMESTAMPTZ_TBL;
250250

251+
-- Check OF with various zone offsets, particularly fractional hours
252+
SET timezone = '00:00';
253+
SELECT to_char(now(), 'OF');
254+
SET timezone = '+02:00';
255+
SELECT to_char(now(), 'OF');
256+
SET timezone = '-13:00';
257+
SELECT to_char(now(), 'OF');
258+
SET timezone = '-00:30';
259+
SELECT to_char(now(), 'OF');
260+
SET timezone = '00:30';
261+
SELECT to_char(now(), 'OF');
262+
SET timezone = '-04:30';
263+
SELECT to_char(now(), 'OF');
264+
SET timezone = '04:30';
265+
SELECT to_char(now(), 'OF');
266+
RESET timezone;
267+
251268
CREATE TABLE TIMESTAMPTZ_TST (a int , b timestamptz);
252269

253270
-- Test year field value with len > 4

0 commit comments

Comments
 (0)