Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oPoY4-0003S7-F9 for pgsql-general@arkaria.postgresql.org; Sun, 21 Aug 2022 17:15:45 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1oPoY2-0001mb-O4 for pgsql-general@arkaria.postgresql.org; Sun, 21 Aug 2022 17:15:42 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oPoY0-0001mE-TA for pgsql-general@lists.postgresql.org; Sun, 21 Aug 2022 17:15:42 +0000 Received: from wout1-smtp.messagingengine.com ([64.147.123.24]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oPoXu-0005d0-Dl for pgsql-general@lists.postgresql.org; Sun, 21 Aug 2022 17:15:39 +0000 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.west.internal (Postfix) with ESMTP id EA8A0320076F; Sun, 21 Aug 2022 13:15:30 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Sun, 21 Aug 2022 13:15:31 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aklaver.com; h= cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; t=1661102130; x= 1661188530; bh=04wE6wFUhEHyzq6yqVw/E07EEhi9K6AVhRTzxXXTQu4=; b=q c1DVvW+s1Bk6WlpmlcGzk28Q7C6kqta3jB9OiUwEGOaOg09EvVcvQse4t5EE7ScL V+h04qVzK/fht0ZeKF+Zx/Mcr/mIVN0X7HHHb/+DFiJcEp9O/v4zCq2fj2TyiB64 okHVwL1k3PMfRsf08hjeq+lcpLOCOqJRmOrjPBdQB9jyNm7m2FzZD93Adlt8EtW9 DNKlaAoALvwUkZ25QFAIdAIyFRkUGnVfIK2wXGzH1KaUAv0h4imb89uC8OI1f176 H9MtEREkpSMYlzfil4joPE1mG4G7Zdh2+4MkhPa+mb27+wzz3KopjZAU/n1YzTj0 KTqDEAJyXcYBTV6kvcibQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:date:feedback-id:feedback-id:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to:x-me-proxy:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1661102130; x=1661188530; bh=0 4wE6wFUhEHyzq6yqVw/E07EEhi9K6AVhRTzxXXTQu4=; b=AeZvLpgDRDhUb4tbv 11wgz9FQUnCU7Tx13MExP03eHtqIHm52GBaxjQAWQE0EKmh6kIodvUY8gwWKR7cY rW+Y9HbPTnCphNO9h8wvwrg8y3p2LjcFFHq1N4ngyTGFU8gjAUuIRfWZvmLYSWl/ I2v2bDfBN13sOjL2NeI2Yv9JHu9E5n264454OzItjTPpQPI5/c1vFu4EByYMmOrE d1tbRdkf5qrvEAB7f9fzgzn25Y2amP9MzFIh78SrK0VKvtstF70h2qhoY3H0H355 uTLlEchaP0zWdfVF0dHmC6hZ1qM6fRXFtRAJqJfqgFZ0cOr/IAgC1b1iUf0QxRfr FIM6A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrvdeihedgudduudcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefkffggfgfuvfhfhfgjtgfgsehtjeertddtfeejnecuhfhrohhmpeetughr ihgrnhcumfhlrghvvghruceorggurhhirghnrdhklhgrvhgvrhesrghklhgrvhgvrhdrtg homheqnecuggftrfgrthhtvghrnhepvdelhfehhfdvvddvkeeitedvvdeuleetvdefhfei feekgeeuieetgffhjeduueejnecuffhomhgrihhnpehophgvnhgrthhlrghsrdgvuhdpoh gvrgifrdgrtgdrrghtnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghi lhhfrhhomheprggurhhirghnrdhklhgrvhgvrhesrghklhgrvhgvrhdrtghomh X-ME-Proxy: Feedback-ID: i76984098:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 21 Aug 2022 13:15:29 -0400 (EDT) Message-ID: <5c679341-3d8b-a732-d349-76753d0422c6@aklaver.com> Date: Sun, 21 Aug 2022 10:15:28 -0700 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.12.0 Subject: Re: Support for dates before 4713 BC Content-Language: en-US To: "Watzinger, Alexander" , "pgsql-general@lists.postgresql.org" References: From: Adrian Klaver In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 8/20/22 07:05, Watzinger, Alexander wrote: > Hi all, > > I'm working on the open source project OpenAtlas (https://openatlas.eu > ) which is used to enter historical and > archeological data. > Although we really appreciate the wonderful PostgreSQL software, the > limitation of not being able to use dates before 4713 BC is problematic > in regard to archeological data. > The only reason for this limitation I found was that the Julian Calendar > wasn't created with this in mind. The only suggestion I found was to > write an own implementation just using integers for years. But building > a parallel date system in this case would be way to cumbersomeand error > prone, we really like using the database for date operations. > > > So my questions are: > Any chance to add support for dates before 4713 BC? We really would > appreciate that. > > The 4713 BC limit feels very arbitrary, what is the reason for this > exact limit? From include/datatype/timestamp.h: /* * Julian date support. * * date2j() and j2date() nominally handle the Julian date range 0..INT_MAX, * or 4714-11-24 BC to 5874898-06-03 AD. In practice, date2j() will work and * give correct negative Julian dates for dates before 4714-11-24 BC as well. * We rely on it to do so back to 4714-11-01 BC. Allowing at least one day's * slop is necessary so that timestamp rotation doesn't produce dates that * would be rejected on input. For example, '4714-11-24 00:00 GMT BC' is a * legal timestamptz value, but in zones east of Greenwich it would print as * sometime in the afternoon of 4714-11-23 BC; if we couldn't process such a * date we'd have a dump/reload failure. So the idea is for IS_VALID_JULIAN * to accept a slightly wider range of dates than we really support, and * then we apply the exact checks in IS_VALID_DATE or IS_VALID_TIMESTAMP, * after timezone rotation if any. To save a few cycles, we can make * IS_VALID_JULIAN check only to the month boundary, since its exact cutoffs * are not very critical in this scheme. * * It is correct that JULIAN_MINYEAR is -4713, not -4714; it is defined to * allow easy comparison to tm_year values, in which we follow the convention * that tm_year <= 0 represents abs(tm_year)+1 BC. */ #define JULIAN_MINYEAR (-4713) #define JULIAN_MINMONTH (11) #define JULIAN_MINDAY (24) #define JULIAN_MAXYEAR (5874898) #define JULIAN_MAXMONTH (6) #define JULIAN_MAXDAY (3) #define IS_VALID_JULIAN(y,m,d) \ (((y) > JULIAN_MINYEAR || \ ((y) == JULIAN_MINYEAR && ((m) >= JULIAN_MINMONTH))) && \ ((y) < JULIAN_MAXYEAR || \ ((y) == JULIAN_MAXYEAR && ((m) < JULIAN_MAXMONTH)))) /* Julian-date equivalents of Day 0 in Unix and Postgres reckoning */ #define UNIX_EPOCH_JDATE 2440588 /* == date2j(1970, 1, 1) */ #define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */ /* * Range limits for dates and timestamps. * * We have traditionally allowed Julian day zero as a valid datetime value, * so that is the lower bound for both dates and timestamps. * * The upper limit for dates is 5874897-12-31, which is a bit less than what * the Julian-date code can allow. For timestamps, the upper limit is * 294276-12-31. The int64 overflow limit would be a few days later; again, * leaving some slop avoids worries about corner-case overflow, and provides * a simpler user-visible definition. */ /* First allowed date, and first disallowed date, in Julian-date form */ #define DATETIME_MIN_JULIAN (0) #define DATE_END_JULIAN (2147483494) /* == date2j(JULIAN_MAXYEAR, 1, 1) */ #define TIMESTAMP_END_JULIAN (109203528) /* == date2j(294277, 1, 1) */ /* Timestamp limits */ #define MIN_TIMESTAMP INT64CONST(-211813488000000000) /* == (DATETIME_MIN_JULIAN - POSTGRES_EPOCH_JDATE) * USECS_PER_DAY */ #define END_TIMESTAMP INT64CONST(9223371331200000000) /* == (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE) * USECS_PER_DAY */ /* Range-check a date (given in Postgres, not Julian, numbering) */ #define IS_VALID_DATE(d) \ ((DATETIME_MIN_JULIAN - POSTGRES_EPOCH_JDATE) <= (d) && \ (d) < (DATE_END_JULIAN - POSTGRES_EPOCH_JDATE)) /* Range-check a timestamp */ #define IS_VALID_TIMESTAMP(t) (MIN_TIMESTAMP <= (t) && (t) < END_TIMESTAMP) #endif /* DATATYPE_TIMESTAMP_H */ > > > Feedback and pointers are very welcome, > > Alex > > > -- > Alexander Watzinger > > Austrian Academy of Sciences > Austrian Centre for Digital Humanities and Cultural Heritage > alexander.watzinger@oeaw.ac.at | www.oeaw.ac.at/acdh > -- Adrian Klaver adrian.klaver@aklaver.com