From 9e9724e8bd5ffe8e32401bc15e8acfdef99bf9ed Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Fri, 1 Apr 2005 14:25:23 +0000 Subject: [PATCH] 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. --- doc/src/sgml/func.sgml | 8 +++++++- src/backend/utils/adt/timestamp.c | 32 ++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 4fee01c6d8..f879664a9e 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,5 +1,5 @@ @@ -5472,6 +5472,12 @@ SELECT EXTRACT(SECOND FROM TIME '17:12:28.5'); week starts on Monday.) In other words, the first Thursday of a year is in week 1 of that year. (for timestamp values only) + + Because of this, it is possible for early January dates to be part of the + 52nd or 53rd week of the previous year. For example, 2005-01-01 + is part of the 53rd week of year 2004, and 2006-01-01 is part of + the 52nd week of year 2005. + SELECT EXTRACT(WEEK FROM TIMESTAMP '2001-02-16 20:38:40'); diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index e788c7b162..1f82b2fec9 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.117 2004/12/31 22:01:22 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.118 2005/04/01 14:25:23 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -2754,12 +2754,23 @@ timestamp_trunc(PG_FUNCTION_ARGS) switch (val) { case DTK_WEEK: - isoweek2date(date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); + { + int woy; + + woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday); + /* + * If it is week 52/53 and the month is January, + * then the week must belong to the previous year. + */ + if (woy >= 52 && tm->tm_mon == 1) + --tm->tm_year; + isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; fsec = 0; break; + } case DTK_MILLENNIUM: /* see comments in timestamptz_trunc */ if (tm->tm_year > 0) @@ -2874,13 +2885,24 @@ timestamptz_trunc(PG_FUNCTION_ARGS) switch (val) { case DTK_WEEK: - isoweek2date(date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); + { + int woy; + + woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday); + /* + * If it is week 52/53 and the month is January, + * then the week must belong to the previous year. + */ + if (woy >= 52 && tm->tm_mon == 1) + --tm->tm_year; + isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; fsec = 0; redotz = true; break; + } /* one may consider DTK_THOUSAND and DTK_HUNDRED... */ case DTK_MILLENNIUM: @@ -3142,7 +3164,7 @@ date2isoweek(int year, int mon, int mday) * Sometimes the last few days in a year will fall into the first week * of the next year, so check for this. */ - if (result >= 53) + if (result >= 52) { day4 = date2j(year + 1, 1, 4); @@ -3198,7 +3220,7 @@ date2isoyear(int year, int mon, int mday) * Sometimes the last few days in a year will fall into the first week * of the next year, so check for this. */ - if (result >= 53) + if (result >= 52) { day4 = date2j(year + 1, 1, 4);