mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-18 18:44:06 +08:00
The following patches eliminate the overflows in the j2date() and date2j()
functions which limited the maximum date for a timestamp to AD 1465001. The new limit is AD 5874897. The files affected are: doc/src/sgml/datatype.sgml: Documentation change due to patch. Included is a notice about the reduced range when using an eight-byte integer for timestamps. src/backend/utils/adt/datetime.c: Replacement functions for j2date() and date2j() functions. src/include/utils/datetime.h: Corrected a bug with the limit on the earliest possible date, Nov 23,-4713 has a Julian day count of -1. The earliest possible date should be Nov 24, -4713 with a day count of 0. src/test/regress/expected/horology-no-DST-before-1970.out: src/test/regress/expected/horology-solaris-1947.out: src/test/regress/expected/horology.out: Copies of expected output for regression testing. Note: Only horology.out has been physically tested. I do not have access to a Solaris box and I don't know how to provoke the "pre-1970" test. src/test/regress/sql/horology.sql: Added some test cases to check extended range. John Cochran
This commit is contained in:
parent
4efbbd7318
commit
a286f73210
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.113 2003/01/31 01:08:07 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.114 2003/02/19 03:48:10 momjian Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="datatype">
|
<chapter id="datatype">
|
||||||
@ -1243,7 +1243,7 @@ SELECT b, char_length(b) FROM test2;
|
|||||||
<entry>both date and time</entry>
|
<entry>both date and time</entry>
|
||||||
<entry>8 bytes</entry>
|
<entry>8 bytes</entry>
|
||||||
<entry>4713 BC</entry>
|
<entry>4713 BC</entry>
|
||||||
<entry>AD 1465001</entry>
|
<entry>AD 5874897</entry>
|
||||||
<entry>1 microsecond / 14 digits</entry>
|
<entry>1 microsecond / 14 digits</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
@ -1251,7 +1251,7 @@ SELECT b, char_length(b) FROM test2;
|
|||||||
<entry>both date and time</entry>
|
<entry>both date and time</entry>
|
||||||
<entry>8 bytes</entry>
|
<entry>8 bytes</entry>
|
||||||
<entry>4713 BC</entry>
|
<entry>4713 BC</entry>
|
||||||
<entry>AD 1465001</entry>
|
<entry>AD 5874897</entry>
|
||||||
<entry>1 microsecond / 14 digits</entry>
|
<entry>1 microsecond / 14 digits</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
@ -1309,7 +1309,8 @@ SELECT b, char_length(b) FROM test2;
|
|||||||
a few years of 2000-01-01, but the precision degrades for dates further
|
a few years of 2000-01-01, but the precision degrades for dates further
|
||||||
away. When timestamps are stored as eight-byte integers (a compile-time
|
away. When timestamps are stored as eight-byte integers (a compile-time
|
||||||
option), microsecond precision is available over the full range of
|
option), microsecond precision is available over the full range of
|
||||||
values.
|
values. However eight-byte integer timestamps have a reduced range of
|
||||||
|
dates from 4713 BC up to 294276 AD.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.99 2003/01/29 01:08:42 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.100 2003/02/19 03:48:10 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -587,66 +587,77 @@ static datetkn *deltacache[MAXDATEFIELDS] = {NULL};
|
|||||||
* since it is numerically accurate and computationally simple.
|
* since it is numerically accurate and computationally simple.
|
||||||
* The algorithms here will accurately convert between Julian day
|
* The algorithms here will accurately convert between Julian day
|
||||||
* and calendar date for all non-negative Julian days
|
* and calendar date for all non-negative Julian days
|
||||||
* (i.e. from Nov 23, -4713 on).
|
* (i.e. from Nov 24, -4713 on).
|
||||||
*
|
|
||||||
* Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
|
|
||||||
* University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
|
|
||||||
*
|
|
||||||
* Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
|
|
||||||
* now at Aerospace Corp. (hi, Henry!)
|
|
||||||
*
|
*
|
||||||
* These routines will be used by other date/time packages
|
* These routines will be used by other date/time packages
|
||||||
* - thomas 97/02/25
|
* - thomas 97/02/25
|
||||||
|
*
|
||||||
|
* Rewritten to eliminate overflow problems. This now allows the
|
||||||
|
* routines to work correctly for all Julian day counts from
|
||||||
|
* 0 to 2147483647 (Nov 24, -4713 to Jun 3, 5874898) assuming
|
||||||
|
* a 32-bit integer. Longer types should also work to the limits
|
||||||
|
* of their precision.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
date2j(int y, int m, int d)
|
date2j(int y, int m, int d)
|
||||||
{
|
{
|
||||||
int m12 = (m - 14) / 12;
|
int julian;
|
||||||
|
int century;
|
||||||
|
|
||||||
return ((1461 * (y + 4800 + m12)) / 4
|
if (m > 2) {
|
||||||
+ (367 * (m - 2 - 12 * (m12))) / 12
|
m += 1;
|
||||||
- (3 * ((y + 4900 + m12) / 100)) / 4
|
y += 4800;
|
||||||
+ d - 32075);
|
} else {
|
||||||
|
m += 13;
|
||||||
|
y += 4799;
|
||||||
|
}
|
||||||
|
|
||||||
|
century = y/100;
|
||||||
|
julian = y*365 - 32167;
|
||||||
|
julian += y/4 - century + century/4;
|
||||||
|
julian += 7834*m/256 + d;
|
||||||
|
|
||||||
|
return julian;
|
||||||
} /* date2j() */
|
} /* date2j() */
|
||||||
|
|
||||||
void
|
void
|
||||||
j2date(int jd, int *year, int *month, int *day)
|
j2date(int jd, int *year, int *month, int *day)
|
||||||
{
|
{
|
||||||
int j,
|
unsigned int julian;
|
||||||
y,
|
unsigned int quad;
|
||||||
m,
|
unsigned int extra;
|
||||||
d;
|
int y;
|
||||||
|
|
||||||
int i,
|
julian = jd;
|
||||||
l,
|
julian += 32044;
|
||||||
n;
|
quad = julian/146097;
|
||||||
|
extra = (julian - quad*146097)*4 + 3;
|
||||||
|
julian += 60 + quad*3 + extra/146097;
|
||||||
|
quad = julian/1461;
|
||||||
|
julian -= quad*1461;
|
||||||
|
y = julian * 4 / 1461;
|
||||||
|
julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
|
||||||
|
+ 123;
|
||||||
|
y += quad*4;
|
||||||
|
*year = y - 4800;
|
||||||
|
quad = julian * 2141 / 65536;
|
||||||
|
*day = julian - 7834*quad/256;
|
||||||
|
*month = (quad + 10) % 12 + 1;
|
||||||
|
|
||||||
l = jd + 68569;
|
|
||||||
n = (4 * l) / 146097;
|
|
||||||
l -= (146097 * n + 3) / 4;
|
|
||||||
i = (4000 * (l + 1)) / 1461001;
|
|
||||||
l += 31 - (1461 * i) / 4;
|
|
||||||
j = (80 * l) / 2447;
|
|
||||||
d = l - (2447 * j) / 80;
|
|
||||||
l = j / 11;
|
|
||||||
m = (j + 2) - (12 * l);
|
|
||||||
y = 100 * (n - 49) + i + l;
|
|
||||||
|
|
||||||
*year = y;
|
|
||||||
*month = m;
|
|
||||||
*day = d;
|
|
||||||
return;
|
return;
|
||||||
} /* j2date() */
|
} /* j2date() */
|
||||||
|
|
||||||
int
|
int
|
||||||
j2day(int date)
|
j2day(int date)
|
||||||
{
|
{
|
||||||
int day;
|
unsigned int day;
|
||||||
|
|
||||||
day = (date + 1) % 7;
|
day = date;
|
||||||
|
day += 1;
|
||||||
|
day %= 7;
|
||||||
|
|
||||||
return day;
|
return (int) day;
|
||||||
} /* j2day() */
|
} /* j2day() */
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: datetime.h,v 1.34 2003/01/16 00:26:49 tgl Exp $
|
* $Id: datetime.h,v 1.35 2003/02/19 03:48:10 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -239,7 +239,7 @@ extern int day_tab[2][13];
|
|||||||
|
|
||||||
#define JULIAN_MINYEAR (-4713)
|
#define JULIAN_MINYEAR (-4713)
|
||||||
#define JULIAN_MINMONTH (11)
|
#define JULIAN_MINMONTH (11)
|
||||||
#define JULIAN_MINDAY (23)
|
#define JULIAN_MINDAY (24)
|
||||||
|
|
||||||
#define IS_VALID_JULIAN(y,m,d) (((y) > JULIAN_MINYEAR) \
|
#define IS_VALID_JULIAN(y,m,d) (((y) > JULIAN_MINYEAR) \
|
||||||
|| (((y) == JULIAN_MINYEAR) && (((m) > JULIAN_MINMONTH) \
|
|| (((y) == JULIAN_MINYEAR) && (((m) > JULIAN_MINMONTH) \
|
||||||
|
@ -328,6 +328,30 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
|
|||||||
Fri Dec 31 23:59:59 1999
|
Fri Dec 31 23:59:59 1999
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
|
||||||
|
Nov 27, 2733194
|
||||||
|
-----------------------------
|
||||||
|
Sun Nov 27 00:00:00 2733194
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
|
||||||
|
Nov 30, 5471101
|
||||||
|
-----------------------------
|
||||||
|
Sat Nov 30 00:00:00 5471101
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
|
||||||
|
Dec 31, 5874897
|
||||||
|
-----------------------------
|
||||||
|
Tue Dec 31 00:00:00 5874897
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
|
||||||
|
2147483493 Days
|
||||||
|
-------------------
|
||||||
|
@ 2147483493 days
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- Shorthand values
|
-- Shorthand values
|
||||||
-- Not directly usable for regression testing since these are not constants.
|
-- Not directly usable for regression testing since these are not constants.
|
||||||
-- So, just try to test parser and hope for the best - thomas 97/04/26
|
-- So, just try to test parser and hope for the best - thomas 97/04/26
|
||||||
|
@ -328,6 +328,30 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
|
|||||||
Fri Dec 31 23:59:59 1999
|
Fri Dec 31 23:59:59 1999
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
|
||||||
|
Nov 27, 2733194
|
||||||
|
-----------------------------
|
||||||
|
Sun Nov 27 00:00:00 2733194
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
|
||||||
|
Nov 30, 5471101
|
||||||
|
-----------------------------
|
||||||
|
Sat Nov 30 00:00:00 5471101
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
|
||||||
|
Dec 31, 5874897
|
||||||
|
-----------------------------
|
||||||
|
Tue Dec 31 00:00:00 5874897
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
|
||||||
|
2147483493 Days
|
||||||
|
-------------------
|
||||||
|
@ 2147483493 days
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- Shorthand values
|
-- Shorthand values
|
||||||
-- Not directly usable for regression testing since these are not constants.
|
-- Not directly usable for regression testing since these are not constants.
|
||||||
-- So, just try to test parser and hope for the best - thomas 97/04/26
|
-- So, just try to test parser and hope for the best - thomas 97/04/26
|
||||||
|
@ -328,6 +328,30 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
|
|||||||
Fri Dec 31 23:59:59 1999
|
Fri Dec 31 23:59:59 1999
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
|
||||||
|
Nov 27, 2733194
|
||||||
|
-----------------------------
|
||||||
|
Sun Nov 27 00:00:00 2733194
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
|
||||||
|
Nov 30, 5471101
|
||||||
|
-----------------------------
|
||||||
|
Sat Nov 30 00:00:00 5471101
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
|
||||||
|
Dec 31, 5874897
|
||||||
|
-----------------------------
|
||||||
|
Tue Dec 31 00:00:00 5874897
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
|
||||||
|
2147483493 Days
|
||||||
|
-------------------
|
||||||
|
@ 2147483493 days
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- Shorthand values
|
-- Shorthand values
|
||||||
-- Not directly usable for regression testing since these are not constants.
|
-- Not directly usable for regression testing since these are not constants.
|
||||||
-- So, just try to test parser and hope for the best - thomas 97/04/26
|
-- So, just try to test parser and hope for the best - thomas 97/04/26
|
||||||
|
@ -76,6 +76,10 @@ SELECT timestamp without time zone '1996-03-01' - interval '1 second' AS "Feb 29
|
|||||||
SELECT timestamp without time zone '1999-03-01' - interval '1 second' AS "Feb 28";
|
SELECT timestamp without time zone '1999-03-01' - interval '1 second' AS "Feb 28";
|
||||||
SELECT timestamp without time zone '2000-03-01' - interval '1 second' AS "Feb 29";
|
SELECT timestamp without time zone '2000-03-01' - interval '1 second' AS "Feb 29";
|
||||||
SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second' AS "Dec 31";
|
SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second' AS "Dec 31";
|
||||||
|
SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '1000000000 days' AS "Nov 27, 2733194";
|
||||||
|
SELECT timestamp without time zone 'Nov 24, 4714 BC' + interval '2000000000 days' AS "Nov 30, 5471101";
|
||||||
|
SELECT timestamp without time zone 'Nov 25, 4714 BC' + interval '2147483492 days' AS "Dec 31, 5874897";
|
||||||
|
SELECT timestamp without time zone '12/31/5874897' - timestamp without time zone 'Nov 24, 4714 BC' AS "2147483493 Days";
|
||||||
|
|
||||||
-- Shorthand values
|
-- Shorthand values
|
||||||
-- Not directly usable for regression testing since these are not constants.
|
-- Not directly usable for regression testing since these are not constants.
|
||||||
|
Loading…
Reference in New Issue
Block a user