Skip to content

Commit 7a52a8f

Browse files
committed
Clean up the code for to_timestamp's conversion of year plus ISO day number
to date, as per bug #4702 and subsequent discussion. In particular, make it work for years specified using AD/BC or CC fields, and fix the test for "no year specified" so that it doesn't trigger inappropriately for 1 BC (which it was doing even in code paths that had nothing to do with to_timestamp). I also did some minor code beautification in the non-ISO-day-number code path. This area has been busted all along, but because the code has been rewritten repeatedly, it would be considerable trouble to back-patch. It's such a corner case that it doesn't seem worth the effort.
1 parent 0f80200 commit 7a52a8f

File tree

2 files changed

+28
-33
lines changed

2 files changed

+28
-33
lines changed

src/backend/utils/adt/formatting.c

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* -----------------------------------------------------------------------
22
* formatting.c
33
*
4-
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.155 2009/03/12 00:53:25 tgl Exp $
4+
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.156 2009/03/15 20:31:19 tgl Exp $
55
*
66
*
77
* Portions Copyright (c) 1999-2009, PostgreSQL Global Development Group
@@ -709,13 +709,13 @@ typedef enum
709709
*/
710710
static const KeyWord DCH_keywords[] = {
711711
/* name, len, id, is_digit, date_mode */
712-
{"A.D.", 4, DCH_A_D, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* A */
712+
{"A.D.", 4, DCH_A_D, FALSE, FROM_CHAR_DATE_NONE}, /* A */
713713
{"A.M.", 4, DCH_A_M, FALSE, FROM_CHAR_DATE_NONE},
714-
{"AD", 2, DCH_AD, FALSE, FROM_CHAR_DATE_GREGORIAN},
714+
{"AD", 2, DCH_AD, FALSE, FROM_CHAR_DATE_NONE},
715715
{"AM", 2, DCH_AM, FALSE, FROM_CHAR_DATE_NONE},
716-
{"B.C.", 4, DCH_B_C, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* B */
717-
{"BC", 2, DCH_BC, FALSE, FROM_CHAR_DATE_GREGORIAN},
718-
{"CC", 2, DCH_CC, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* C */
716+
{"B.C.", 4, DCH_B_C, FALSE, FROM_CHAR_DATE_NONE}, /* B */
717+
{"BC", 2, DCH_BC, FALSE, FROM_CHAR_DATE_NONE},
718+
{"CC", 2, DCH_CC, TRUE, FROM_CHAR_DATE_NONE}, /* C */
719719
{"DAY", 3, DCH_DAY, FALSE, FROM_CHAR_DATE_NONE}, /* D */
720720
{"DDD", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
721721
{"DD", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
@@ -757,13 +757,13 @@ static const KeyWord DCH_keywords[] = {
757757
{"YYY", 3, DCH_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
758758
{"YY", 2, DCH_YY, TRUE, FROM_CHAR_DATE_GREGORIAN},
759759
{"Y", 1, DCH_Y, TRUE, FROM_CHAR_DATE_GREGORIAN},
760-
{"a.d.", 4, DCH_a_d, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* a */
760+
{"a.d.", 4, DCH_a_d, FALSE, FROM_CHAR_DATE_NONE}, /* a */
761761
{"a.m.", 4, DCH_a_m, FALSE, FROM_CHAR_DATE_NONE},
762-
{"ad", 2, DCH_ad, FALSE, FROM_CHAR_DATE_GREGORIAN},
762+
{"ad", 2, DCH_ad, FALSE, FROM_CHAR_DATE_NONE},
763763
{"am", 2, DCH_am, FALSE, FROM_CHAR_DATE_NONE},
764-
{"b.c.", 4, DCH_b_c, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* b */
765-
{"bc", 2, DCH_bc, FALSE, FROM_CHAR_DATE_GREGORIAN},
766-
{"cc", 2, DCH_CC, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* c */
764+
{"b.c.", 4, DCH_b_c, FALSE, FROM_CHAR_DATE_NONE}, /* b */
765+
{"bc", 2, DCH_bc, FALSE, FROM_CHAR_DATE_NONE},
766+
{"cc", 2, DCH_CC, TRUE, FROM_CHAR_DATE_NONE}, /* c */
767767
{"day", 3, DCH_day, FALSE, FROM_CHAR_DATE_NONE}, /* d */
768768
{"ddd", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
769769
{"dd", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
@@ -3281,41 +3281,41 @@ do_to_timestamp(text *date_txt, text *fmt,
32813281
* be interpreted as a Gregorian day-of-year, or an ISO week date
32823282
* day-of-year.
32833283
*/
3284+
3285+
if (!tm->tm_year && !tmfc.bc)
3286+
ereport(ERROR,
3287+
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3288+
errmsg("cannot calculate day of year without year information")));
3289+
32843290
if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
32853291
{
32863292
int j0; /* zeroth day of the ISO year, in Julian */
32873293

3288-
j0 = isoweek2j(tmfc.year, 1) - 1;
3294+
j0 = isoweek2j(tm->tm_year, 1) - 1;
32893295

32903296
j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
32913297
}
32923298
else
32933299
{
3294-
int *y,
3295-
i;
3296-
3297-
int ysum[2][13] = {
3298-
{31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0},
3299-
{31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 0}};
3300+
const int *y;
3301+
int i;
33003302

3301-
if (!tm->tm_year)
3302-
ereport(ERROR,
3303-
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3304-
errmsg("cannot calculate day of year without year information")));
3303+
static const int ysum[2][13] = {
3304+
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
3305+
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
33053306

33063307
y = ysum[isleap(tm->tm_year)];
33073308

3308-
for (i = 0; i <= 11; i++)
3309+
for (i = 1; i <= 12; i++)
33093310
{
3310-
if (tm->tm_yday < y[i])
3311+
if (tmfc.ddd < y[i])
33113312
break;
33123313
}
33133314
if (tm->tm_mon <= 1)
3314-
tm->tm_mon = i + 1;
3315+
tm->tm_mon = i;
33153316

33163317
if (tm->tm_mday <= 1)
3317-
tm->tm_mday = i == 0 ? tm->tm_yday :
3318-
tm->tm_yday - y[i - 1];
3318+
tm->tm_mday = tmfc.ddd - y[i - 1];
33193319
}
33203320
}
33213321

src/backend/utils/adt/timestamp.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.196 2009/01/01 17:23:50 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.197 2009/03/15 20:31:19 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -3668,11 +3668,6 @@ isoweek2j(int year, int week)
36683668
int day0,
36693669
day4;
36703670

3671-
if (!year)
3672-
ereport(ERROR,
3673-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3674-
errmsg("cannot calculate week number without year information")));
3675-
36763671
/* fourth day of current year */
36773672
day4 = date2j(year, 1, 4);
36783673

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy