I\'m looking for standards for Date/Time addition. I haven\'t been able to find any. In particular I\'m hoping to find a spec that defines what should happen when you add a mont
Joda-Time in Java chooses the previous valid date when an invalid one is created. For example, 2011-01-31 + P1M = 2011-02-28
. I believe this is the most widely chosen default choice in date-time libraries, and thus a de facto standard.
ThreeTen/JSR-310 provides a strategy pattern for this, with four choices, see the code.
More amusing is the question of what the answer to 2011-01-31 + P1M-1D
is. If you add the month, then resolve the invalid date, then subtract the day, you get 2011-02-27. But I think most users expect 2011-02-28 because the period is being added in a single lump. See how ThreeTen handles this here.
I have considered trying to write a general purpose best practices in date/time calculations, or actual spec, but haven't really had the time!
First day of the month + 1 month should equal the first of the next month. Trying this on SQL Server
SELECT CAST ('01/01/2012' AS DateTime), DATEADD (m, 1, '01/01/2012')
UNION ALL SELECT CAST ('02/01/2012' AS DateTime), DATEADD (m, 1, '02/01/2012')
UNION ALL SELECT CAST ('03/01/2012' AS DateTime), DATEADD (m, 1, '03/01/2012')
UNION ALL SELECT CAST ('04/01/2012' AS DateTime), DATEADD (m, 1, '04/01/2012')
UNION ALL SELECT CAST ('05/01/2012' AS DateTime), DATEADD (m, 1, '05/01/2012')
This results in
----------------------- -----------------------
2012-01-01 2012-02-01
2012-02-01 2012-03-01
2012-03-01 2012-04-01
2012-04-01 2012-05-01
2012-05-01 2012-06-01
Last day of this month + 1 month should equal last day of next month. This should go for next month, current month, 10 months down, etc.
SELECT CAST ('01/31/2012' AS DateTime), DATEADD (m, 1, '01/31/2012')
UNION ALL SELECT CAST ('01/30/2012' AS DateTime), DATEADD (m, 1, '01/30/2012')
UNION ALL SELECT CAST ('01/29/2012' AS DateTime), DATEADD (m, 1, '01/29/2012')
UNION ALL SELECT CAST ('01/28/2012' AS DateTime), DATEADD (m, 1, '01/28/2012')
UNION ALL SELECT CAST ('01/27/2012' AS DateTime), DATEADD (m, 1, '01/27/2012')
UNION ALL SELECT CAST ('01/26/2012' AS DateTime), DATEADD (m, 1, '01/26/2012')
This results in
----------------------- -----------------------
2012-01-31 2012-02-29
2012-01-30 2012-02-29
2012-01-29 2012-02-29
2012-01-28 2012-02-28
2012-01-27 2012-02-27
2012-01-26 2012-02-26
See how 31, 30, 29 all become feb 29 (2012 is a leap year).
p.s. I took off the time parts (all zeroes) to help make it more readable