Re: [BUGS] BUG #14632: Plus and minus operators inconsistency with leap years and year intervals. - Mailing list pgsql-bugs

From Pietro Pugni
Subject Re: [BUGS] BUG #14632: Plus and minus operators inconsistency with leap years and year intervals.
Date
Msg-id AA4AA8B1-AD27-458F-9941-6E5B5F56EACA@gmail.com
Whole thread Raw
In response to Re: [BUGS] BUG #14632: Plus and minus operators inconsistency withleap years and year intervals.  ("David G. Johnston" <david.g.johnston@gmail.com>)
Responses Re: [BUGS] BUG #14632: Plus and minus operators inconsistency withleap years and year intervals.
Re: [BUGS] BUG #14632: Plus and minus operators inconsistency withleap years and year intervals.
List pgsql-bugs

​In theory we could simply die trying but given few complaints this behavior doesn't seem to bother many people if not actually please them because at least they can get a correct result even if it is munged a bit.  Date interval math is fraught with problems.; you can bypass most of them by manipulating days instead.
Many people doesn’t observe data and thus don’t see errors. I was simply calculating birthdays from birth dates and found some weird results that turned out to be associated to leap years.


The “logical” bug can be seen also by adding and subtracting the same quantity:

SELECT '1912-02-29'::date - '10 years'::interval + '10 years'::interval

It returns '1912-02-28 00:00:00' instead of '1912-02-29 00:00:00'.

Expect 1912-02-28 is a correct response.  The only reason you think the 29th comes into play here is because you remember that the starting point was the 29th.  The system has no such memory.​

And this is logically wrong because it leads to wrong results. I’m aware that time intervals are difficult to manage but more exactness is needed here: '10 years' must have the same meaning when added to a date and subtracted from it, otherwise it leads to wrong results.


It’s an issue because there’s no other way to obtain the original date (reversing the add operation).

You are correct.  Given the presence of leap years what you describe is a mathematical impossibility - not a bug.

It should be advised in the official docs (I can’t find any reference for this topic).


Also:
SELECT age('1922-02-28'::date, '1912-02-29'::date) = '10 years'::interval
returns false, while:
SELECT ('1922-02-29'::date + '10 years'::interval) = '1922-02-28'::date
returns true.

The inconsistency (or bug) resides in the non unique meaning of the interval handling with respect of summing and subtracting the same quantity. 


​It resides in the fact we apply date shifting after applying the interval in order to come up with a valid date.  That such date shifting negates the commutative property is an unfortunate byproduct.  To my knowledge there is no promise nor requirement for date arithmetic to be commutative.  Or, more precisely, if you wish to use the commutative property here you must operate using days.

Again, it should be written in some part of the docs that intervals lead to different results if summed/subtracted to/from leap dates.



Again, the issue can be seen this way: adding the interval returned by 
​​
SELECT age('1922-02-28'::date, '1912-02-29'::date)
 to the original date. So:
​​
SELECT '1912-02-29'::date + '9 years 11 mons 28 days'::interval
returns:
(c) 1922-02-26 00:00:00
Here we loose 2 days even if we add the same interval used in (b)!

​Operate in days and you can do this just fine - but note you cannot just convert the interval to a number of days.

​SELECT '1922-02-28'::date - '1912-02-29'::date ; 3652
SELECT '1922-02-28'::date - 3652 ; 1912-02-29

This particular example leads me to suspect that some improvement in this area might be possible...

The bug basically consists of the vague meaning of “years” applied to leap years. It should be revised in order to be consistent and correct.

How?

Probably considering leap dates as singularities and threat them by subtracting 1 day. 
For example, a possible workaround to properly calculate the interval between 1922-02-28 and 1922-02-29 is the following:

SELECT age('1922-02-28'::date, '1912-02-29'::date - '1 day'::interval)
   age    
----------
 10 years

King regards,
 Pietro Pugni

pgsql-bugs by date:

Previous
From: Pietro Pugni
Date:
Subject: Re: [BUGS] BUG #14632: Plus and minus operators inconsistency with leap years and year intervals.
Next
From: "David G. Johnston"
Date:
Subject: Re: [BUGS] BUG #14632: Plus and minus operators inconsistency withleap years and year intervals.