--
-- DATE
--
CREATE TABLE DATE_TBL (f1 date);
INSERT INTO DATE_TBL VALUES ('1957-04-09');
INSERT INTO DATE_TBL VALUES ('1957-06-13');
INSERT INTO DATE_TBL VALUES ('1996-02-28');
INSERT INTO DATE_TBL VALUES ('1996-02-29');
INSERT INTO DATE_TBL VALUES ('1996-03-01');
INSERT INTO DATE_TBL VALUES ('1996-03-02');
INSERT INTO DATE_TBL VALUES ('1997-02-28');
INSERT INTO DATE_TBL VALUES ('1997-02-29');
ERROR:  date/time field value out of range: "1997-02-29"
INSERT INTO DATE_TBL VALUES ('1997-03-01');
INSERT INTO DATE_TBL VALUES ('1997-03-02');
INSERT INTO DATE_TBL VALUES ('2000-04-01');
INSERT INTO DATE_TBL VALUES ('2000-04-02');
INSERT INTO DATE_TBL VALUES ('2000-04-03');
INSERT INTO DATE_TBL VALUES ('2038-04-08');
INSERT INTO DATE_TBL VALUES ('2039-04-09');
INSERT INTO DATE_TBL VALUES ('2040-04-10');
SELECT f1 AS "Fifteen" FROM DATE_TBL;
  Fifteen   
------------
 04-09-1957
 06-13-1957
 02-28-1996
 02-29-1996
 03-01-1996
 03-02-1996
 02-28-1997
 03-01-1997
 03-02-1997
 04-01-2000
 04-02-2000
 04-03-2000
 04-08-2038
 04-09-2039
 04-10-2040
(15 rows)

SELECT f1 AS "Nine" FROM DATE_TBL WHERE f1 < '2000-01-01';
    Nine    
------------
 04-09-1957
 06-13-1957
 02-28-1996
 02-29-1996
 03-01-1996
 03-02-1996
 02-28-1997
 03-01-1997
 03-02-1997
(9 rows)

SELECT f1 AS "Three" FROM DATE_TBL
  WHERE f1 BETWEEN '2000-01-01' AND '2001-01-01';
   Three    
------------
 04-01-2000
 04-02-2000
 04-03-2000
(3 rows)

--
-- Check all the documented input formats
--
SET datestyle TO iso;  -- display results in ISO
SET datestyle TO ymd;
SELECT date 'January 8, 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999-01-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999-01-18';
    date    
------------
 1999-01-18
(1 row)

SELECT date '1/8/1999';
ERROR:  date/time field value out of range: "1/8/1999"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1/18/1999';
ERROR:  date/time field value out of range: "1/18/1999"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '18/1/1999';
ERROR:  date/time field value out of range: "18/1/1999"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '01/02/03';
    date    
------------
 2001-02-03
(1 row)

SELECT date '19990108';
    date    
------------
 1999-01-08
(1 row)

SELECT date '990108';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999.008';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'J2451187';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'January 8, 99 BC';
ERROR:  date/time field value out of range: "January 8, 99 BC"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '99-Jan-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999-Jan-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08-Jan-99';
ERROR:  date/time field value out of range: "08-Jan-99"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '08-Jan-1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan-08-99';
ERROR:  date/time field value out of range: "Jan-08-99"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date 'Jan-08-1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99-08-Jan';
ERROR:  invalid input syntax for type date: "99-08-Jan"
SELECT date '1999-08-Jan';
ERROR:  invalid input syntax for type date: "1999-08-Jan"
SELECT date '99 Jan 08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999 Jan 08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08 Jan 99';
ERROR:  date/time field value out of range: "08 Jan 99"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '08 Jan 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan 08 99';
ERROR:  date/time field value out of range: "Jan 08 99"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date 'Jan 08 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99 08 Jan';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999 08 Jan';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99-01-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999-01-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08-01-99';
ERROR:  date/time field value out of range: "08-01-99"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '08-01-1999';
ERROR:  date/time field value out of range: "08-01-1999"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '01-08-99';
ERROR:  date/time field value out of range: "01-08-99"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '01-08-1999';
ERROR:  date/time field value out of range: "01-08-1999"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '99-08-01';
    date    
------------
 1999-08-01
(1 row)

SELECT date '1999-08-01';
    date    
------------
 1999-08-01
(1 row)

SELECT date '99 01 08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999 01 08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08 01 99';
ERROR:  date/time field value out of range: "08 01 99"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '08 01 1999';
ERROR:  date/time field value out of range: "08 01 1999"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '01 08 99';
ERROR:  date/time field value out of range: "01 08 99"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '01 08 1999';
ERROR:  date/time field value out of range: "01 08 1999"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '99 08 01';
    date    
------------
 1999-08-01
(1 row)

SELECT date '1999 08 01';
    date    
------------
 1999-08-01
(1 row)

SET datestyle TO dmy;
SELECT date 'January 8, 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999-01-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999-01-18';
    date    
------------
 1999-01-18
(1 row)

SELECT date '1/8/1999';
    date    
------------
 1999-08-01
(1 row)

SELECT date '1/18/1999';
ERROR:  date/time field value out of range: "1/18/1999"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '18/1/1999';
    date    
------------
 1999-01-18
(1 row)

SELECT date '01/02/03';
    date    
------------
 2003-02-01
(1 row)

SELECT date '19990108';
    date    
------------
 1999-01-08
(1 row)

SELECT date '990108';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999.008';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'J2451187';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'January 8, 99 BC';
     date      
---------------
 0099-01-08 BC
(1 row)

SELECT date '99-Jan-08';
ERROR:  date/time field value out of range: "99-Jan-08"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999-Jan-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08-Jan-99';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08-Jan-1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan-08-99';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan-08-1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99-08-Jan';
ERROR:  invalid input syntax for type date: "99-08-Jan"
SELECT date '1999-08-Jan';
ERROR:  invalid input syntax for type date: "1999-08-Jan"
SELECT date '99 Jan 08';
ERROR:  date/time field value out of range: "99 Jan 08"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999 Jan 08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08 Jan 99';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08 Jan 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan 08 99';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan 08 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99 08 Jan';
ERROR:  invalid input syntax for type date: "99 08 Jan"
SELECT date '1999 08 Jan';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99-01-08';
ERROR:  date/time field value out of range: "99-01-08"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999-01-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08-01-99';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08-01-1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '01-08-99';
    date    
------------
 1999-08-01
(1 row)

SELECT date '01-08-1999';
    date    
------------
 1999-08-01
(1 row)

SELECT date '99-08-01';
ERROR:  date/time field value out of range: "99-08-01"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999-08-01';
    date    
------------
 1999-08-01
(1 row)

SELECT date '99 01 08';
ERROR:  date/time field value out of range: "99 01 08"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999 01 08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08 01 99';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08 01 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '01 08 99';
    date    
------------
 1999-08-01
(1 row)

SELECT date '01 08 1999';
    date    
------------
 1999-08-01
(1 row)

SELECT date '99 08 01';
ERROR:  date/time field value out of range: "99 08 01"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999 08 01';
    date    
------------
 1999-08-01
(1 row)

SET datestyle TO mdy;
SELECT date 'January 8, 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999-01-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999-01-18';
    date    
------------
 1999-01-18
(1 row)

SELECT date '1/8/1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1/18/1999';
    date    
------------
 1999-01-18
(1 row)

SELECT date '18/1/1999';
ERROR:  date/time field value out of range: "18/1/1999"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '01/02/03';
    date    
------------
 2003-01-02
(1 row)

SELECT date '19990108';
    date    
------------
 1999-01-08
(1 row)

SELECT date '990108';
    date    
------------
 1999-01-08
(1 row)

SELECT date '1999.008';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'J2451187';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'January 8, 99 BC';
     date      
---------------
 0099-01-08 BC
(1 row)

SELECT date '99-Jan-08';
ERROR:  date/time field value out of range: "99-Jan-08"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999-Jan-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08-Jan-99';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08-Jan-1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan-08-99';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan-08-1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99-08-Jan';
ERROR:  invalid input syntax for type date: "99-08-Jan"
SELECT date '1999-08-Jan';
ERROR:  invalid input syntax for type date: "1999-08-Jan"
SELECT date '99 Jan 08';
ERROR:  invalid input syntax for type date: "99 Jan 08"
SELECT date '1999 Jan 08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08 Jan 99';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08 Jan 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan 08 99';
    date    
------------
 1999-01-08
(1 row)

SELECT date 'Jan 08 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99 08 Jan';
ERROR:  invalid input syntax for type date: "99 08 Jan"
SELECT date '1999 08 Jan';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99-01-08';
ERROR:  date/time field value out of range: "99-01-08"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999-01-08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08-01-99';
    date    
------------
 1999-08-01
(1 row)

SELECT date '08-01-1999';
    date    
------------
 1999-08-01
(1 row)

SELECT date '01-08-99';
    date    
------------
 1999-01-08
(1 row)

SELECT date '01-08-1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99-08-01';
ERROR:  date/time field value out of range: "99-08-01"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999-08-01';
    date    
------------
 1999-08-01
(1 row)

SELECT date '99 01 08';
ERROR:  date/time field value out of range: "99 01 08"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999 01 08';
    date    
------------
 1999-01-08
(1 row)

SELECT date '08 01 99';
    date    
------------
 1999-08-01
(1 row)

SELECT date '08 01 1999';
    date    
------------
 1999-08-01
(1 row)

SELECT date '01 08 99';
    date    
------------
 1999-01-08
(1 row)

SELECT date '01 08 1999';
    date    
------------
 1999-01-08
(1 row)

SELECT date '99 08 01';
ERROR:  date/time field value out of range: "99 08 01"
HINT:  Perhaps you need a different "datestyle" setting.
SELECT date '1999 08 01';
    date    
------------
 1999-08-01
(1 row)

RESET datestyle;
--
-- Simple math
-- Leave most of it for the horology tests
--
SELECT f1 - date '2000-01-01' AS "Days From 2K" FROM DATE_TBL;
 Days From 2K 
--------------
       -15607
       -15542
        -1403
        -1402
        -1401
        -1400
        -1037
        -1036
        -1035
           91
           92
           93
        13977
        14343
        14710
(15 rows)

SELECT f1 - date 'epoch' AS "Days From Epoch" FROM DATE_TBL;
 Days From Epoch 
-----------------
           -4650
           -4585
            9554
            9555
            9556
            9557
            9920
            9921
            9922
           11048
           11049
           11050
           24934
           25300
           25667
(15 rows)

SELECT date 'yesterday' - date 'today' AS "One day";
 One day 
---------
      -1
(1 row)

SELECT date 'today' - date 'tomorrow' AS "One day";
 One day 
---------
      -1
(1 row)

SELECT date 'yesterday' - date 'tomorrow' AS "Two days";
 Two days 
----------
       -2
(1 row)

SELECT date 'tomorrow' - date 'today' AS "One day";
 One day 
---------
       1
(1 row)

SELECT date 'today' - date 'yesterday' AS "One day";
 One day 
---------
       1
(1 row)

SELECT date 'tomorrow' - date 'yesterday' AS "Two days";
 Two days 
----------
        2
(1 row)

--
-- test extract!
--
-- century
--
SELECT EXTRACT(CENTURY FROM DATE '0101-12-31 BC'); -- -2
 date_part 
-----------
        -2
(1 row)

SELECT EXTRACT(CENTURY FROM DATE '0100-12-31 BC'); -- -1
 date_part 
-----------
        -1
(1 row)

SELECT EXTRACT(CENTURY FROM DATE '0001-12-31 BC'); -- -1
 date_part 
-----------
        -1
(1 row)

SELECT EXTRACT(CENTURY FROM DATE '0001-01-01');    --  1
 date_part 
-----------
         1
(1 row)

SELECT EXTRACT(CENTURY FROM DATE '0001-01-01 AD'); --  1
 date_part 
-----------
         1
(1 row)

SELECT EXTRACT(CENTURY FROM DATE '1900-12-31');    -- 19
 date_part 
-----------
        19
(1 row)

SELECT EXTRACT(CENTURY FROM DATE '1901-01-01');    -- 20
 date_part 
-----------
        20
(1 row)

SELECT EXTRACT(CENTURY FROM DATE '2000-12-31');    -- 20
 date_part 
-----------
        20
(1 row)

SELECT EXTRACT(CENTURY FROM DATE '2001-01-01');    -- 21
 date_part 
-----------
        21
(1 row)

SELECT EXTRACT(CENTURY FROM CURRENT_DATE)>=21 AS True;     -- true
 true 
------
 t
(1 row)

--
-- millennium
--
SELECT EXTRACT(MILLENNIUM FROM DATE '0001-12-31 BC'); -- -1
 date_part 
-----------
        -1
(1 row)

SELECT EXTRACT(MILLENNIUM FROM DATE '0001-01-01 AD'); --  1
 date_part 
-----------
         1
(1 row)

SELECT EXTRACT(MILLENNIUM FROM DATE '1000-12-31');    --  1
 date_part 
-----------
         1
(1 row)

SELECT EXTRACT(MILLENNIUM FROM DATE '1001-01-01');    --  2
 date_part 
-----------
         2
(1 row)

SELECT EXTRACT(MILLENNIUM FROM DATE '2000-12-31');    --  2
 date_part 
-----------
         2
(1 row)

SELECT EXTRACT(MILLENNIUM FROM DATE '2001-01-01');    --  3
 date_part 
-----------
         3
(1 row)

-- next test to be fixed on the turn of the next millennium;-)
SELECT EXTRACT(MILLENNIUM FROM CURRENT_DATE);         --  3
 date_part 
-----------
         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)