Skip to content

Commit 9e9724e

Browse files
committed
Fix wrong week returnded by date_trunc('week') for early dates in
January --- would return wrong year for 2005-01-01 and 2006-01-01. per report from Robert Creager. Backpatch to 8.0.X.
1 parent a70574d commit 9e9724e

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

doc/src/sgml/func.sgml

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.243 2005/03/30 04:52:49 neilc Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.244 2005/04/01 14:25:22 momjian Exp $
33
PostgreSQL documentation
44
-->
55

@@ -5472,6 +5472,12 @@ SELECT EXTRACT(SECOND FROM TIME '17:12:28.5');
54725472
week starts on Monday.) In other words, the first Thursday of
54735473
a year is in week 1 of that year. (for <type>timestamp</type> values only)
54745474
</para>
5475+
<para>
5476+
Because of this, it is possible for early January dates to be part of the
5477+
52nd or 53rd week of the previous year. For example, <literal>2005-01-01</>
5478+
is part of the 53rd week of year 2004, and <literal>2006-01-01</> is part of
5479+
the 52nd week of year 2005.
5480+
</para>
54755481

54765482
<screen>
54775483
SELECT EXTRACT(WEEK FROM TIMESTAMP '2001-02-16 20:38:40');

src/backend/utils/adt/timestamp.c

+27-5
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.117 2004/12/31 22:01:22 pgsql Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.118 2005/04/01 14:25:23 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -2754,12 +2754,23 @@ timestamp_trunc(PG_FUNCTION_ARGS)
27542754
switch (val)
27552755
{
27562756
case DTK_WEEK:
2757-
isoweek2date(date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
2757+
{
2758+
int woy;
2759+
2760+
woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
2761+
/*
2762+
* If it is week 52/53 and the month is January,
2763+
* then the week must belong to the previous year.
2764+
*/
2765+
if (woy >= 52 && tm->tm_mon == 1)
2766+
--tm->tm_year;
2767+
isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
27582768
tm->tm_hour = 0;
27592769
tm->tm_min = 0;
27602770
tm->tm_sec = 0;
27612771
fsec = 0;
27622772
break;
2773+
}
27632774
case DTK_MILLENNIUM:
27642775
/* see comments in timestamptz_trunc */
27652776
if (tm->tm_year > 0)
@@ -2874,13 +2885,24 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
28742885
switch (val)
28752886
{
28762887
case DTK_WEEK:
2877-
isoweek2date(date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
2888+
{
2889+
int woy;
2890+
2891+
woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
2892+
/*
2893+
* If it is week 52/53 and the month is January,
2894+
* then the week must belong to the previous year.
2895+
*/
2896+
if (woy >= 52 && tm->tm_mon == 1)
2897+
--tm->tm_year;
2898+
isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
28782899
tm->tm_hour = 0;
28792900
tm->tm_min = 0;
28802901
tm->tm_sec = 0;
28812902
fsec = 0;
28822903
redotz = true;
28832904
break;
2905+
}
28842906
/* one may consider DTK_THOUSAND and DTK_HUNDRED... */
28852907
case DTK_MILLENNIUM:
28862908

@@ -3142,7 +3164,7 @@ date2isoweek(int year, int mon, int mday)
31423164
* Sometimes the last few days in a year will fall into the first week
31433165
* of the next year, so check for this.
31443166
*/
3145-
if (result >= 53)
3167+
if (result >= 52)
31463168
{
31473169
day4 = date2j(year + 1, 1, 4);
31483170

@@ -3198,7 +3220,7 @@ date2isoyear(int year, int mon, int mday)
31983220
* Sometimes the last few days in a year will fall into the first week
31993221
* of the next year, so check for this.
32003222
*/
3201-
if (result >= 53)
3223+
if (result >= 52)
32023224
{
32033225
day4 = date2j(year + 1, 1, 4);
32043226

0 commit comments

Comments
 (0)