Jonathan M Davis
Posted in reply to Alexander Zhirov
| On Saturday, February 10, 2024 8:53:09 AM MST Alexander Zhirov via Digitalmars-d-learn wrote:
> Is it possible to calculate the difference between dates in years using regular means? Something like that
>
>
> ```
> writeln(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)));
> ```
>
> At the same time, keep in mind that the month and day matter, because the difference between the year, taking into account the month that has not come, will be less.
>
> My abilities are not yet enough to figure it out more elegantly.
Well, diffMonths could be used to build what you want, but std.datetime doesn't really provide a direct solution for it.
Subtracting one Date from another gives you a Duration, but that doesn't take the month or year into account, because the lengths of the months are variable.
diffMonths is the solution to get around that, since it does take the exact years and months involved to give you the number of months. However, it doesn't take the days of the month into account. It's just diffing the months themselves, and any day of the month counts as being part of that month.
However, after some mucking around, I think that I have a solution built on top of diffMonths, though of course, it's possible that I screwed up somewhere with my test dates. I named it yearsApart rather than diffYears, since unlike diffMonths, it does take the smaller units into account. But of course, you can name it whatever you want.
import std.datetime.date : Date;
int yearsApart(Date lhs, Date rhs)
{
auto months = lhs.diffMonths(rhs);
auto years = months / 12;
if(years == 0)
return 0;
auto remainder = months % 12;
if(remainder != 0)
return years;
if(months >= 0)
return lhs.day >= rhs.day ? years : years - 1;
return lhs.day <= rhs.day ? years : years + 1;
}
unittest
{
assert(yearsApart(Date(1999, 3, 1), Date(1999, 1, 1)) == 0);
assert(yearsApart(Date(1999, 1, 1), Date(1999, 3, 1)) == 0);
assert(yearsApart(Date(1999, 3, 1), Date(1998, 1, 1)) == 1);
assert(yearsApart(Date(1998, 3, 1), Date(1999, 1, 1)) == 0);
assert(yearsApart(Date(2000, 12, 1), Date(1995, 12, 1)) == 5);
assert(yearsApart(Date(1995, 12, 1), Date(2000, 12, 1)) == -5);
assert(yearsApart(Date(2000, 12, 2), Date(1995, 12, 1)) == 5);
assert(yearsApart(Date(1995, 12, 1), Date(2000, 12, 2)) == -5);
assert(yearsApart(Date(2000, 12, 1), Date(1995, 12, 2)) == 4);
assert(yearsApart(Date(1995, 12, 2), Date(2000, 12, 1)) == -4);
assert(yearsApart(Date(2000, 2, 29), Date(1999, 2, 28)) == 1);
assert(yearsApart(Date(1999, 2, 28), Date(2000, 2, 29)) == -1);
assert(yearsApart(Date(2000, 2, 29), Date(1999, 3, 1)) == 0);
assert(yearsApart(Date(1999, 3, 1), Date(2000, 2, 29)) == 0);
assert(yearsApart(Date(2000, 2, 29), Date(1998, 3, 1)) == 1);
assert(yearsApart(Date(1998, 3, 1), Date(2000, 2, 29)) == -1);
assert(yearsApart(Date(2001, 3, 1), Date(2000, 2, 29)) == 1);
assert(yearsApart(Date(2000, 2, 29), Date(2001, 3, 1)) == -1);
assert(yearsApart(Date(2005, 3, 1), Date(2000, 2, 29)) == 5);
assert(yearsApart(Date(2004, 3, 1), Date(2000, 2, 29)) == 4);
assert(yearsApart(Date(2003, 3, 1), Date(2000, 2, 29)) == 3);
assert(yearsApart(Date(2002, 3, 1), Date(2000, 2, 29)) == 2);
assert(yearsApart(Date(2001, 3, 1), Date(2000, 2, 29)) == 1);
assert(yearsApart(Date(2000, 3, 1), Date(2000, 2, 29)) == 0);
assert(yearsApart(Date(2000, 2, 29), Date(2001, 3, 1)) == -1);
assert(yearsApart(Date(2000, 2, 29), Date(2002, 3, 1)) == -2);
assert(yearsApart(Date(2000, 2, 29), Date(2003, 3, 1)) == -3);
assert(yearsApart(Date(2000, 2, 29), Date(2004, 3, 1)) == -4);
assert(yearsApart(Date(2000, 2, 29), Date(2005, 3, 1)) == -5);
assert(yearsApart(Date(2005, 2, 28), Date(2000, 2, 29)) == 4);
assert(yearsApart(Date(2004, 2, 29), Date(2000, 2, 29)) == 4);
assert(yearsApart(Date(2004, 2, 28), Date(2000, 2, 29)) == 3);
assert(yearsApart(Date(2003, 2, 28), Date(2000, 2, 29)) == 2);
assert(yearsApart(Date(2002, 2, 28), Date(2000, 2, 29)) == 1);
assert(yearsApart(Date(2001, 2, 28), Date(2000, 2, 29)) == 0);
assert(yearsApart(Date(2000, 2, 29), Date(2000, 2, 29)) == 0);
assert(yearsApart(Date(2000, 2, 28), Date(2000, 2, 29)) == 0);
assert(yearsApart(Date(2000, 2, 29), Date(2000, 2, 28)) == 0);
assert(yearsApart(Date(2000, 2, 29), Date(2000, 2, 29)) == 0);
assert(yearsApart(Date(2000, 2, 29), Date(2001, 2, 28)) == 0);
assert(yearsApart(Date(2000, 2, 29), Date(2002, 2, 28)) == -1);
assert(yearsApart(Date(2000, 2, 29), Date(2003, 2, 28)) == -2);
assert(yearsApart(Date(2000, 2, 29), Date(2004, 2, 28)) == -3);
assert(yearsApart(Date(2000, 2, 29), Date(2004, 2, 29)) == -4);
assert(yearsApart(Date(2000, 2, 29), Date(2005, 2, 28)) == -4);
}
- Jonathan M Davis
|