diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2016-03-17 15:50:33 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2016-03-17 15:50:33 -0400 |
commit | 17a250b189a94a470e37ce14d0ebf72390c86d4d (patch) | |
tree | dc66dc06211aeb8ae6d9685b5068c9cdea6a00c3 | |
parent | 23cb32660c841d21a376642e40d8cfbea6c5f010 (diff) | |
download | postgresql-17a250b189a94a470e37ce14d0ebf72390c86d4d.tar.gz postgresql-17a250b189a94a470e37ce14d0ebf72390c86d4d.zip |
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 2d87eedc1d4468d3 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 9b43d73b3f9bef27, 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
-rw-r--r-- | src/backend/utils/adt/formatting.c | 10 | ||||
-rw-r--r-- | src/test/regress/expected/timestamptz.out | 51 | ||||
-rw-r--r-- | src/test/regress/sql/timestamptz.sql | 17 |
3 files changed, 75 insertions, 3 deletions
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index b0c2c85b1c7..de2e37b07d7 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -2503,11 +2503,15 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; case DCH_OF: INVALID_FOR_INTERVAL; - sprintf(s, "%+0*ld", S_FM(n->suffix) ? 0 : 3, tm->tm_gmtoff / SECS_PER_HOUR); + sprintf(s, "%c%0*d", + (tm->tm_gmtoff >= 0) ? '+' : '-', + S_FM(n->suffix) ? 0 : 2, + abs((int) tm->tm_gmtoff) / SECS_PER_HOUR); s += strlen(s); - if (tm->tm_gmtoff % SECS_PER_HOUR != 0) + if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0) { - sprintf(s, ":%02ld", (tm->tm_gmtoff % SECS_PER_HOUR) / SECS_PER_MINUTE); + sprintf(s, ":%02d", + (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE); s += strlen(s); } break; diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out index e5a21305c00..50661bb5929 100644 --- a/src/test/regress/expected/timestamptz.out +++ b/src/test/regress/expected/timestamptz.out @@ -1675,6 +1675,57 @@ SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID') | 2001 1 1 1 1 1 1 (66 rows) +-- Check OF with various zone offsets, particularly fractional hours +SET timezone = '00:00'; +SELECT to_char(now(), 'OF'); + to_char +--------- + +00 +(1 row) + +SET timezone = '+02:00'; +SELECT to_char(now(), 'OF'); + to_char +--------- + -02 +(1 row) + +SET timezone = '-13:00'; +SELECT to_char(now(), 'OF'); + to_char +--------- + +13 +(1 row) + +SET timezone = '-00:30'; +SELECT to_char(now(), 'OF'); + to_char +--------- + +00:30 +(1 row) + +SET timezone = '00:30'; +SELECT to_char(now(), 'OF'); + to_char +--------- + -00:30 +(1 row) + +SET timezone = '-04:30'; +SELECT to_char(now(), 'OF'); + to_char +--------- + +04:30 +(1 row) + +SET timezone = '04:30'; +SELECT to_char(now(), 'OF'); + to_char +--------- + -04:30 +(1 row) + +RESET timezone; CREATE TABLE TIMESTAMPTZ_TST (a int , b timestamptz); -- Test year field value with len > 4 INSERT INTO TIMESTAMPTZ_TST VALUES(1, 'Sat Mar 12 23:58:48 1000 IST'); diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql index f4b455e7032..5e52f5f0c15 100644 --- a/src/test/regress/sql/timestamptz.sql +++ b/src/test/regress/sql/timestamptz.sql @@ -241,6 +241,23 @@ SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID') SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID') FROM TIMESTAMPTZ_TBL; +-- Check OF with various zone offsets, particularly fractional hours +SET timezone = '00:00'; +SELECT to_char(now(), 'OF'); +SET timezone = '+02:00'; +SELECT to_char(now(), 'OF'); +SET timezone = '-13:00'; +SELECT to_char(now(), 'OF'); +SET timezone = '-00:30'; +SELECT to_char(now(), 'OF'); +SET timezone = '00:30'; +SELECT to_char(now(), 'OF'); +SET timezone = '-04:30'; +SELECT to_char(now(), 'OF'); +SET timezone = '04:30'; +SELECT to_char(now(), 'OF'); +RESET timezone; + CREATE TABLE TIMESTAMPTZ_TST (a int , b timestamptz); -- Test year field value with len > 4 |