*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.109 2004/06/03 17:57:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.110 2004/08/20 03:45:13 momjian Exp $
*
*-------------------------------------------------------------------------
*/
fsec = 0;
break;
case DTK_MILLENNIUM:
- tm->tm_year = (tm->tm_year / 1000) * 1000;
+ /* see comments in timestamptz_trunc */
+ if (tm->tm_year > 0)
+ tm->tm_year = ((tm->tm_year+999) / 1000) * 1000 - 999;
+ else
+ tm->tm_year = - ((999 - (tm->tm_year-1))/1000) * 1000 + 1;
case DTK_CENTURY:
- tm->tm_year = (tm->tm_year / 100) * 100;
+ /* see comments in timestamptz_trunc */
+ if (tm->tm_year > 0)
+ tm->tm_year = ((tm->tm_year+99) / 100) * 100 - 99;
+ else
+ tm->tm_year = - ((99 - (tm->tm_year-1))/100) * 100 + 1;
case DTK_DECADE:
- tm->tm_year = (tm->tm_year / 10) * 10;
+ /* see comments in timestamptz_trunc */
+ if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
+ {
+ if (tm->tm_year > 0)
+ tm->tm_year = (tm->tm_year / 10) * 10;
+ else
+ tm->tm_year = - ((8-(tm->tm_year-1)) / 10) * 10;
+ }
case DTK_YEAR:
tm->tm_mon = 1;
case DTK_QUARTER:
tm->tm_sec = 0;
fsec = 0;
break;
+ /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
case DTK_MILLENNIUM:
- tm->tm_year = (tm->tm_year / 1000) * 1000;
+ /* truncating to the millennium? what is this supposed to mean?
+ * let us put the first year of the millennium...
+ * i.e. -1000, 1, 1001, 2001...
+ */
+ if (tm->tm_year > 0)
+ tm->tm_year = ((tm->tm_year+999) / 1000) * 1000 - 999;
+ else
+ tm->tm_year = - ((999 - (tm->tm_year-1))/1000) * 1000 + 1;
case DTK_CENTURY:
- tm->tm_year = (tm->tm_year / 100) * 100;
+ /* truncating to the century? as above: -100, 1, 101... */
+ if (tm->tm_year > 0)
+ tm->tm_year = ((tm->tm_year+99) / 100) * 100 - 99 ;
+ else
+ tm->tm_year = - ((99 - (tm->tm_year-1))/100) * 100 + 1;
case DTK_DECADE:
- tm->tm_year = (tm->tm_year / 10) * 10;
+ /* truncating to the decade? first year of the decade.
+ * must not be applied if year was truncated before!
+ */
+ if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
+ {
+ if (tm->tm_year > 0)
+ tm->tm_year = (tm->tm_year / 10) * 10;
+ else
+ tm->tm_year = - ((8-(tm->tm_year-1)) / 10) * 10;
+ }
case DTK_YEAR:
tm->tm_mon = 1;
case DTK_QUARTER:
switch (val)
{
case DTK_MILLENNIUM:
+ /* caution: C division may have negative remainder */
tm->tm_year = (tm->tm_year / 1000) * 1000;
case DTK_CENTURY:
+ /* caution: C division may have negative remainder */
tm->tm_year = (tm->tm_year / 100) * 100;
case DTK_DECADE:
+ /* caution: C division may have negative remainder */
tm->tm_year = (tm->tm_year / 10) * 10;
case DTK_YEAR:
tm->tm_mon = 0;
break;
case DTK_DECADE:
- result = (tm->tm_year / 10);
+ /* what is a decade wrt dates?
+ * let us assume that decade 199 is 1990 thru 1999...
+ * decade 0 starts on year 1 BC, and -1 is 11 BC thru 2 BC...
+ */
+ if (tm->tm_year>=0)
+ result = (tm->tm_year / 10);
+ else
+ result = -((8-(tm->tm_year-1)) / 10);
break;
case DTK_CENTURY:
if (tm->tm_year > 0)
result = ((tm->tm_year+99) / 100);
else
- /* caution: C division may yave negative remainder */
+ /* caution: C division may have negative remainder */
result = - ((99 - (tm->tm_year-1))/100);
break;
break;
case DTK_DECADE:
- result = (tm->tm_year / 10);
+ /* see comments in timestamp_part */
+ if (tm->tm_year>0)
+ result = (tm->tm_year / 10);
+ else
+ result = - ((8-(tm->tm_year-1)) / 10);
break;
case DTK_CENTURY:
- result = (tm->tm_year / 100);
+ /* see comments in timestamp_part */
+ if (tm->tm_year > 0)
+ result = ((tm->tm_year+99) / 100);
+ else
+ result = - ((99 - (tm->tm_year-1))/100);
break;
case DTK_MILLENNIUM:
- result = (tm->tm_year / 1000);
+ /* see comments in timestamp_part */
+ if (tm->tm_year > 0)
+ result = ((tm->tm_year+999) / 1000);
+ else
+ result = - ((999 - (tm->tm_year-1))/1000);
break;
case DTK_JULIAN:
break;
case DTK_DECADE:
+ /* caution: C division may have negative remainder */
result = (tm->tm_year / 10);
break;
case DTK_CENTURY:
+ /* caution: C division may have negative remainder */
result = (tm->tm_year / 100);
break;
case DTK_MILLENNIUM:
+ /* caution: C division may have negative remainder */
result = (tm->tm_year / 1000);
break;
3
(1 row)
+--
+-- decade
+--
+SELECT EXTRACT(DECADE FROM DATE '1994-12-25'); -- 199
+ date_part
+-----------
+ 199
+(1 row)
+
+SELECT EXTRACT(DECADE FROM DATE '0010-01-01'); -- 1
+ date_part
+-----------
+ 1
+(1 row)
+
+SELECT EXTRACT(DECADE FROM DATE '0009-12-31'); -- 0
+ date_part
+-----------
+ 0
+(1 row)
+
+SELECT EXTRACT(DECADE FROM DATE '0001-01-01 BC'); -- 0
+ date_part
+-----------
+ 0
+(1 row)
+
+SELECT EXTRACT(DECADE FROM DATE '0002-12-31 BC'); -- -1
+ date_part
+-----------
+ -1
+(1 row)
+
+SELECT EXTRACT(DECADE FROM DATE '0011-01-01 BC'); -- -1
+ date_part
+-----------
+ -1
+(1 row)
+
+SELECT EXTRACT(DECADE FROM DATE '0012-12-31 BC'); -- -2
+ date_part
+-----------
+ -2
+(1 row)
+
+--
+-- some other types:
+--
+-- on a timestamp.
+SELECT EXTRACT(CENTURY FROM NOW())>=21 AS True; -- true
+ true
+------
+ t
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM TIMESTAMP '1970-03-20 04:30:00.00000'); -- 20
+ date_part
+-----------
+ 20
+(1 row)
+
+-- on an interval
+SELECT EXTRACT(CENTURY FROM INTERVAL '100 y'); -- 1
+ date_part
+-----------
+ 1
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM INTERVAL '99 y'); -- 0
+ date_part
+-----------
+ 0
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM INTERVAL '-99 y'); -- 0
+ date_part
+-----------
+ 0
+(1 row)
+
+SELECT EXTRACT(CENTURY FROM INTERVAL '-100 y'); -- -1
+ date_part
+-----------
+ -1
+(1 row)
+
+--
+-- test trunc function!
+--
+SELECT DATE_TRUNC('MILLENNIUM', TIMESTAMP '1970-03-20 04:30:00.00000'); -- 1001
+ date_trunc
+--------------------------
+ Thu Jan 01 00:00:00 1001
+(1 row)
+
+SELECT DATE_TRUNC('MILLENNIUM', DATE '1970-03-20'); -- 1001-01-01
+ date_trunc
+------------------------------
+ Thu Jan 01 00:00:00 1001 PST
+(1 row)
+
+SELECT DATE_TRUNC('CENTURY', TIMESTAMP '1970-03-20 04:30:00.00000'); -- 1901
+ date_trunc
+--------------------------
+ Tue Jan 01 00:00:00 1901
+(1 row)
+
+SELECT DATE_TRUNC('CENTURY', DATE '1970-03-20'); -- 1901
+ date_trunc
+------------------------------
+ Tue Jan 01 00:00:00 1901 PST
+(1 row)
+
+SELECT DATE_TRUNC('CENTURY', DATE '2004-08-10'); -- 2001-01-01
+ date_trunc
+------------------------------
+ Mon Jan 01 00:00:00 2001 PST
+(1 row)
+
+SELECT DATE_TRUNC('CENTURY', DATE '0002-02-04'); -- 0001-01-01
+ date_trunc
+------------------------------
+ Mon Jan 01 00:00:00 0001 PST
+(1 row)
+
+SELECT DATE_TRUNC('CENTURY', DATE '0055-08-10 BC'); -- 0100-01-01 BC
+ date_trunc
+---------------------------------
+ Tue Jan 01 00:00:00 0100 PST BC
+(1 row)
+
+SELECT DATE_TRUNC('DECADE', DATE '1993-12-25'); -- 1990-01-01
+ date_trunc
+------------------------------
+ Mon Jan 01 00:00:00 1990 PST
+(1 row)
+
+SELECT DATE_TRUNC('DECADE', DATE '0004-12-25'); -- 0001-01-01 BC
+ date_trunc
+---------------------------------
+ Sat Jan 01 00:00:00 0001 PST BC
+(1 row)
+
+SELECT DATE_TRUNC('DECADE', DATE '0002-12-31 BC'); -- 0011-01-01 BC
+ date_trunc
+---------------------------------
+ Mon Jan 01 00:00:00 0011 PST BC
+(1 row)
+
SELECT EXTRACT(MILLENNIUM FROM DATE '2001-01-01'); -- 3
-- next test to be fixed on the turn of the next millennium;-)
SELECT EXTRACT(MILLENNIUM FROM CURRENT_DATE); -- 3
+--
+-- decade
+--
+SELECT EXTRACT(DECADE FROM DATE '1994-12-25'); -- 199
+SELECT EXTRACT(DECADE FROM DATE '0010-01-01'); -- 1
+SELECT EXTRACT(DECADE FROM DATE '0009-12-31'); -- 0
+SELECT EXTRACT(DECADE FROM DATE '0001-01-01 BC'); -- 0
+SELECT EXTRACT(DECADE FROM DATE '0002-12-31 BC'); -- -1
+SELECT EXTRACT(DECADE FROM DATE '0011-01-01 BC'); -- -1
+SELECT EXTRACT(DECADE FROM DATE '0012-12-31 BC'); -- -2
+--
+-- some other types:
+--
+-- on a timestamp.
+SELECT EXTRACT(CENTURY FROM NOW())>=21 AS True; -- true
+SELECT EXTRACT(CENTURY FROM TIMESTAMP '1970-03-20 04:30:00.00000'); -- 20
+-- on an interval
+SELECT EXTRACT(CENTURY FROM INTERVAL '100 y'); -- 1
+SELECT EXTRACT(CENTURY FROM INTERVAL '99 y'); -- 0
+SELECT EXTRACT(CENTURY FROM INTERVAL '-99 y'); -- 0
+SELECT EXTRACT(CENTURY FROM INTERVAL '-100 y'); -- -1
+--
+-- test trunc function!
+--
+SELECT DATE_TRUNC('MILLENNIUM', TIMESTAMP '1970-03-20 04:30:00.00000'); -- 1001
+SELECT DATE_TRUNC('MILLENNIUM', DATE '1970-03-20'); -- 1001-01-01
+SELECT DATE_TRUNC('CENTURY', TIMESTAMP '1970-03-20 04:30:00.00000'); -- 1901
+SELECT DATE_TRUNC('CENTURY', DATE '1970-03-20'); -- 1901
+SELECT DATE_TRUNC('CENTURY', DATE '2004-08-10'); -- 2001-01-01
+SELECT DATE_TRUNC('CENTURY', DATE '0002-02-04'); -- 0001-01-01
+SELECT DATE_TRUNC('CENTURY', DATE '0055-08-10 BC'); -- 0100-01-01 BC
+SELECT DATE_TRUNC('DECADE', DATE '1993-12-25'); -- 1990-01-01
+SELECT DATE_TRUNC('DECADE', DATE '0004-12-25'); -- 0001-01-01 BC
+SELECT DATE_TRUNC('DECADE', DATE '0002-12-31 BC'); -- 0011-01-01 BC