The difference between the dates in years

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sat Feb 10 21:43:12 UTC 2024


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





More information about the Digitalmars-d-learn mailing list