Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+27-27
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

+1-6
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)