Given three non-negative integers y
, m
, and d
(of which at least one must be positive) and a valid date with a positive year (in any reasonable format that includes the year, month, and day, and no additional information), output the date that is y
years, m
months, and d
days after the original date.
The Gregorian calendar is to be used for all dates (even dates prior to the adoption of the Gregorian calendar).
The method for computing the next date is as follows:
- Add
y
to the year - Add
m
to the month - Normalize the date by applying rollovers (e.g.
2018-13-01
->2019-01-01
) - If the day is past the last day of the month, change it to the last day in the month (e.g.
2018-02-30
->2018-02-28
) - Add
d
to the day - Normalize the date by applying rollovers (e.g.
2019-01-32
->2019-02-01
)
Leap years (years divisible by 4, but not divisible by 100 unless also divisible by 400) must be handled appropriately. All inputs and outputs will be within the representable integer range of your language.
Test Cases
Test cases are provided in the format input => output
, where input
is a JSON object.
{"date":"2018-01-01","add":{"d":1}} => 2018-01-02
{"date":"2018-01-01","add":{"M":1}} => 2018-02-01
{"date":"2018-01-01","add":{"Y":1}} => 2019-01-01
{"date":"2018-01-30","add":{"M":1}} => 2018-02-28
{"date":"2018-01-30","add":{"M":2}} => 2018-03-30
{"date":"2000-02-29","add":{"Y":1}} => 2001-02-28
{"date":"2000-02-29","add":{"Y":4}} => 2004-02-29
{"date":"2000-01-30","add":{"d":2}} => 2000-02-01
{"date":"2018-01-01","add":{"Y":2,"M":3,"d":4}} => 2020-04-05
{"date":"2018-01-01","add":{"Y":5,"M":15,"d":40}} => 2024-05-11
You may use this JSFiddle for testing.
This is code-golf, so the shortest solution (in each language) wins.
y
,m
andd
(e.g. couldd
be 2147483000?) \$\endgroup\$All inputs and outputs will be within the representable integer range of your language.
\$\endgroup\$