How to calculate a date some years a go?

I am using Timex library to do date stuff in my project. One of my tests requires to calculate a date exactly 18 years a go from today. What if today is 29 February 2016?

2016 is a leap year but 1998 is not. So there is no 29 February 2016.

My first approach was to use Timex.subtract/2 for this. I am not sure how exactly it is used so I searched in tests and found this line that calculates dates from days. Unfortunately there is no duration from_years

I thought a way to solve this problem.

Subtract 18 from the year. Test if the year is leap?. If it’s not and today.day == 29 and today.month == 02 then create a new date with day = 01 and month = 03. So from 29-February-2016 we derive 01-March-1998.

But still I am curious how this can be achieved using Elixir’s libraries instead of my simplistic idea. Be it Timex or built in.

you could argure that since leap day is the last day of February, it should ‘jump back’ to 28 February if you end up in a non-leap year. For many applications (such as e. g. monthly recurring timers) this makes more sense.

But other than that, your simple approach is great.

… until you look too far back, and come across calendar ambiguities such as for instance the greatly varying moments at which the different European countries decided to switch from the Julian to the Gregorian calendar.

Date and Time handling is a very messy problem.

2 Likes

Timex does this fine.

iex> feb = ~D[2016-02-29]
~D[2016-02-29]
iex> Timex.shift(feb, years: -18)
~D[1998-02-28]
3 Likes

I’m an idiot who didn’t read the question properly. Sorry.

What makes a date exactly 18 years ago?
Is 1 March 1998 exactly 18 years before 29 February 2016 or is it 5 March 1998 (18 * 365 days)?

1 Like

Not exactly relevant but I’ll post it anyway. Whenever someone asks how to calculate a date it always makes me chuckle because of this:

5 Likes

No you are not. It was me who probably made wrong assumptions for how dates work.

1 Like