Search

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.

```On Sat, Feb 10, 2024 at 03:53:09PM +0000, 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.

IIRC you can just subtract two DateTime's to get a Duration that you can then convert into whatever units you want.  Only thing is, in this case conversion to months may not work because months don't have a fixed duration (they can vary from 28 days to 31 days) so there is no "correct" way of computing it, you need to program it yourself according to the exact calculation you want.

T

--
PNP = Plug 'N' Pray
```

On Saturday, 10 February 2024 at 16:03:32 UTC, H. S. Teoh wrote:

>

On Sat, Feb 10, 2024 at 03:53:09PM +0000, 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.

IIRC you can just subtract two DateTime's to get a Duration that you can then convert into whatever units you want. Only thing is, in this case conversion to months may not work because months don't have a fixed duration (they can vary from 28 days to 31 days) so there is no "correct" way of computing it, you need to program it yourself according to the exact calculation you want.

T

I did it this way, but there will be an inaccuracy, since somewhere there may be 366 days, and somewhere 365

``````auto d = cast(Date)Clock.currTime() - Date.fromISOExtString("2001-02-01");
writeln(d.total!"days"().to!int / 365);
``````

On Saturday, 10 February 2024 at 18:12:07 UTC, Alexander Zhirov wrote:

>

On Saturday, 10 February 2024 at 16:03:32 UTC, H. S. Teoh wrote:

>

On Sat, Feb 10, 2024 at 03:53:09PM +0000, 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.

IIRC you can just subtract two DateTime's to get a Duration that you can then convert into whatever units you want. Only thing is, in this case conversion to months may not work because months don't have a fixed duration (they can vary from 28 days to 31 days) so there is no "correct" way of computing it, you need to program it yourself according to the exact calculation you want.

T

I did it this way, but there will be an inaccuracy, since somewhere there may be 366 days, and somewhere 365

``````auto d = cast(Date)Clock.currTime() - Date.fromISOExtString("2001-02-01");
writeln(d.total!"days"().to!int / 365);
``````
``````int getDiffYears(string date) {
auto currentDate = cast(Date)Clock.currTime();
auto startDate = Date.fromISOExtString(date);
auto currentDay = currentDate.dayOfYear;
auto startDay = startDate.dayOfYear;
auto currentMonth = currentDate.month;
auto startMonth = startDate.month;
auto diffDays = currentDate - startDate;
auto diffYears = diffDays.total!"days"().to!int / 365;

return currentMonth >= startMonth && currentDay >= startDay ? diffYears : diffYears - 1;
}
``````
```On Saturday, 10 February 2024 at 19:16:35 UTC, Alexander Zhirov wrote:
> ...

Maybe this will help: I think if you will divide it can't be 365, but 365.242199.

About your code: I having tested fully, but I found a few problems and I wrote (Again without further tests) as below:

import std;

int getDiffYears(string date) {
auto currentDate = cast(Date)Clock.currTime();
auto startDate = Date.fromISOExtString(date);
auto currentDay = currentDate.dayOfYear;
auto startDay = startDate.dayOfYear;
auto currentMonth = currentDate.month;
auto startMonth = startDate.month;
auto diffDays = currentDate - startDate;
auto diffYears = diffDays.total!"days"().to!int / 365;
return currentMonth >= startMonth && currentDay >= startDay ? diffYears : diffYears - 1;
}

int getDiffYears2(string date) {
auto now  = cast(Date)Clock.currTime();
auto from = Date.fromISOExtString(date);
auto dy = now.year-from.year;
auto dm = (from.month-now.month);
auto dd = (dm == 0 && from.day>now.day);
return dy - 1 * (dm > 0 || dd);
}

void main(){
writeln("2001-02-09 is ", getDiffYears("2001-02-09"));
writeln("2001-02-10 is ", getDiffYears("2001-02-10"));
writeln("2001-02-11 is ", getDiffYears("2001-02-11"));
writeln("2001-03-01 is ", getDiffYears("2001-03-01"));
writeln("");
writeln("2001-02-09 is ", getDiffYears2("2001-02-09"));
writeln("2001-02-10 is ", getDiffYears2("2001-02-10"));
writeln("2001-02-11 is ", getDiffYears2("2001-02-11"));
writeln("2001-03-01 is ", getDiffYears2("2001-03-01"));
}

Output:

2001-02-09 is 23
2001-02-10 is 23
2001-02-11 is 22
2001-03-01 is 21

2001-02-09 is 23
2001-02-10 is 23
2001-02-11 is 22
2001-03-01 is 22

Matheus.
```
```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

```

On Saturday, 10 February 2024 at 15:53:09 UTC, Alexander Zhirov 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.

I'm assuming you mean you want the number of full years between the dates. If so, I use something like this:

``````import std;

void main() {
writeln(fullYears(Date(1999, 3, 1), Date(1999, 2, 1)));
writeln(fullYears(Date(2000, 3, 1), Date(1999, 2, 1)));
writeln(fullYears(Date(2000, 3, 1), Date(1999, 4, 1)));
writeln(fullYears(Date(2006, 4, 1), Date(1999, 4, 1)));
}

bool earlierInYear(Date date1, Date date2) {
return date1 < Date(date1.year, date2.month, date2.day);
}

long fullYears(Date date1, Date date2) {
assert(date1 >= date2, "The first date has to be later");
if (date1.earlierInYear(date2)) {
return max(date1.year - date2.year, 0);
} else {
return date1.year - date2.year;
}
}
``````

On Saturday, 10 February 2024 at 21:56:30 UTC, Lance Bachmeier wrote:

>

On Saturday, 10 February 2024 at 15:53:09 UTC, Alexander Zhirov 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.

I'm assuming you mean you want the number of full years between the dates. If so, I use something like this:

``````import std;

void main() {
writeln(fullYears(Date(1999, 3, 1), Date(1999, 2, 1)));
writeln(fullYears(Date(2000, 3, 1), Date(1999, 2, 1)));
writeln(fullYears(Date(2000, 3, 1), Date(1999, 4, 1)));
writeln(fullYears(Date(2006, 4, 1), Date(1999, 4, 1)));
}

bool earlierInYear(Date date1, Date date2) {
return date1 < Date(date1.year, date2.month, date2.day);
}

long fullYears(Date date1, Date date2) {
assert(date1 >= date2, "The first date has to be later");
if (date1.earlierInYear(date2)) {
return max(date1.year - date2.year, 0);
} else {
return date1.year - date2.year;
}
}
``````

should be

``````long fullYears(Date date1, Date date2) {
assert(date1 >= date2, "The first date has to be later");
if (date1.earlierInYear(date2)) {
return max(date1.year - date2.year - 1, 0);
} else {
return date1.year - date2.year;
}
}
``````
```Back when I was doing lots of software developer interviews, one of my frequent questions involved date math.  This wasn't because it's difficult from a coding standpoint, but that it's NOT a coding problem. The key part of the question is realization that it's a requirements question.  The thing that makes dates complicated is defining what the question actually is.

The topic _seems_ like it should be simple, but the deeper you dig the more you realize it's anything but simple.

On 2/10/2024 7:53 AM, 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.
```
```On Saturday, February 10, 2024 3:11:48 PM MST Brad Roberts via Digitalmars-d- learn wrote:
> Back when I was doing lots of software developer interviews, one of my frequent questions involved date math.  This wasn't because it's difficult from a coding standpoint, but that it's NOT a coding problem. The key part of the question is realization that it's a requirements question.  The thing that makes dates complicated is defining what the question actually is.
>
> The topic _seems_ like it should be simple, but the deeper you dig the more you realize it's anything but simple.

Indeed. And because it seems simple at first, it's very common for code to be written which does the wrong thing with regards to dates and times - often which seems like it does the right thing, because it works a lot of the time, when in fact, there are edge cases where it definitely does the wrong thing (e.g. with regards to leap years or DST). And math around months is a prime area where it's difficult to get right in part because different people have different requirements depending on the actual problem that they're trying to solve.

- Jonathan M Davis

```
« First   ‹ Prev
1 2