pg.ddx.io  pgsql-general@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Adrian Klaver <adrian.klaver@aklaver.com>
To: Watzinger, Alexander <Alexander.Watzinger@oeaw.ac.at>
To: pgsql-general@lists.postgresql.org <pgsql-general@lists.postgresql.org>
Subject: Re: Support for dates before 4713 BC
Date: Sun, 21 Aug 2022 10:15:28 -0700
Message-ID: <5c679341-3d8b-a732-d349-76753d0422c6@aklaver.com> (raw)
In-Reply-To: <ca438ff8331c4e109aa1b75a130948ac@oeaw.ac.at>
References: <ca438ff8331c4e109aa1b75a130948ac@oeaw.ac.at>

On 8/20/22 07:05, Watzinger, Alexander wrote:
> Hi all,
> 
> I'm working on the open source project OpenAtlas (https://openatlas.eu 
> <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





view thread (20+ messages)  latest in thread

Message-ID: <5c679341-3d8b-a732-d349-76753d0422c6@aklaver.com>
Permalink:  ../5c679341-3d8b-a732-d349-76753d0422c6@aklaver.com/
Also on:    postgresql.org/message-id/5c679341-3d8b-a732-d349-76753d0422c6@aklaver.com

 · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-general@postgresql.org
  Cc: adrian.klaver@aklaver.com, Alexander.Watzinger@oeaw.ac.at, pgsql-general@lists.postgresql.org
  Subject: Re: Support for dates before 4713 BC
  In-Reply-To: <5c679341-3d8b-a732-d349-76753d0422c6@aklaver.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox