OSDN Git Service

Fix wrong week returnded by date_trunc('week') for early dates in
authorBruce Momjian <bruce@momjian.us>
Fri, 1 Apr 2005 14:25:23 +0000 (14:25 +0000)
committerBruce Momjian <bruce@momjian.us>
Fri, 1 Apr 2005 14:25:23 +0000 (14:25 +0000)
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
src/backend/utils/adt/timestamp.c

index 4fee01c..f879664 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.243 2005/03/30 04:52:49 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.244 2005/04/01 14:25:22 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -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 <type>timestamp</type> values only)
        </para>
+       <para>
+        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, <literal>2005-01-01</>
+        is part of the 53rd week of year 2004, and <literal>2006-01-01</> is part of 
+        the 52nd week of year 2005.
+       </para>
 
 <screen>
 SELECT EXTRACT(WEEK FROM TIMESTAMP '2001-02-16 20:38:40');
index e788c7b..1f82b2f 100644 (file)
@@ -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);