digitalmars.D.learn - Convert duration to years?

• Nestor (22/22) Jan 14 2017 Hi,
• Dave Chapman (13/36) Jan 14 2017 Does this do what you want?
• Nestor (32/44) Jan 14 2017 It seems to work, but not very accurately, see variation:
• ag0aep6g (26/45) Jan 15 2017 That's the better approach, I think. Years have variable lengths.
• rikki cattermole (15/37) Jan 14 2017 So I had a go at this and found I struggled looking at "magic" functions...
• Nestor (4/18) Jan 15 2017 Well... correct me if I am wrong, but isn't t1.add!"years"(1)
• Nestor (13/13) Jan 15 2017 I cleaned up the function a little, but it still feels like a
• rikki cattermole (2/14) Jan 15 2017 The problem with this is that it won't take into account leap years.
• biozic (5/18) Jan 15 2017 It doesn't feel like a hack to me, because it's simple and
• Nestor (12/32) Jan 15 2017 I know. I thought about it as well, but it's not something you
• Nestor (6/13) Jan 15 2017 On second thought, if a baby was born in march 1 of 1999
• biozic (9/24) Jan 15 2017 No. A baby born on March 1st 1999 is just "one year old" on March
• Nestor (5/12) Jan 15 2017 Perhaps I didn't make myself clear. I was not refering here to
• Jonathan M Davis via Digitalmars-d-learn (40/62) Jan 15 2017 Well, there's diffMonths:
• Nestor (1/1) Jan 15 2017 Thank you all.
Nestor <nestorperez2016 yopmail.com> writes:
```Hi,

I would simply like to get someone's age, but I am a little lost
with time and date functions. I can already get the duration, but
after reading the documentation it's unclear to me how to convert
that into years. See following code:

import std.stdio;

void getAge(int yyyy, int mm, int dd) {
import std.datetime;
SysTime t1 = SysTime(Date(yyyy, mm, dd));
SysTime t2 = Clock.currTime();
writeln(t2 - t1);
}

int main() {
try
getAge(1980, 1, 1);
catch(Exception e) {
writefln("%s.\n(%s, line %s)", e.msg, e.file, e.line);
}
}

Notice getAge should return ubyte instead of void, only I haven't
been able to find how to do it. Any suggestion would be welcome.

```
Jan 14 2017
Dave Chapman <donte5379 comcast.net> writes:
```On Sunday, 15 January 2017 at 03:43:32 UTC, Nestor wrote:
Hi,

I would simply like to get someone's age, but I am a little
lost with time and date functions. I can already get the
duration, but after reading the documentation it's unclear to
me how to convert that into years. See following code:

import std.stdio;

void getAge(int yyyy, int mm, int dd) {
import std.datetime;
SysTime t1 = SysTime(Date(yyyy, mm, dd));
SysTime t2 = Clock.currTime();
writeln(t2 - t1);
}

int main() {
try
getAge(1980, 1, 1);
catch(Exception e) {
writefln("%s.\n(%s, line %s)", e.msg, e.file, e.line);
}
}

Notice getAge should return ubyte instead of void, only I
haven't been able to find how to do it. Any suggestion would be
welcome.

Does this do what you want?
import std.stdio;

uint getAge(int yyyy, int mm, int dd) {
import std.datetime;
SysTime t1 = SysTime(Date(yyyy, mm, dd));
SysTime t2 = Clock.currTime();
return( (t2.year - t1.year));
}

void main() {
auto age = getAge(1980, 1, 1);
writefln("age is %s", age);
}
```
Jan 14 2017
Nestor <nestorperez2016 yopmail.com> writes:
```On Sunday, 15 January 2017 at 06:23:56 UTC, Dave Chapman wrote:
Does this do what you want?
import std.stdio;

uint getAge(int yyyy, int mm, int dd) {
import std.datetime;
SysTime t1 = SysTime(Date(yyyy, mm, dd));
SysTime t2 = Clock.currTime();
return( (t2.year - t1.year));
}

void main() {
auto age = getAge(1980, 1, 1);
writefln("age is %s", age);
}

It seems to work, but not very accurately, see variation:

import std.stdio;

uint getAge() {
import std.datetime;
SysTime t1 = SysTime(Date(2000, 12, 31));
SysTime t2 = SysTime(Date(2001, 1, 1));
return((t2.year - t1.year));
}

void main() {
auto age = getAge();
writefln("age is %s", age);
}

I eventually came up with this, but it seems an ugly hack:

import std.stdio;

uint getAge(int yyyy, ubyte mm, ubyte dd) {
ubyte correction;
import std.datetime;
SysTime t = Clock.currTime();
if (t.month < mm) correction = 1;
else if (t.month == mm) correction = (t.day < dd) ? 1 : 0;
else correction = 0;
return (t.year - yyyy - correction);
}

void main() {
try
writefln("Edad: %s años.", getAge(1958, 1, 21));
catch(Exception e) {
writefln("%s.\n(%s, line %s)", e.msg, e.file, e.line);
}
}

Isn't there a built-in function to do this?
```
Jan 14 2017
ag0aep6g <anonymous example.com> writes:
```On 01/15/2017 07:58 AM, Nestor wrote:
I eventually came up with this, but it seems an ugly hack:

import std.stdio;

uint getAge(int yyyy, ubyte mm, ubyte dd) {
ubyte correction;
import std.datetime;
SysTime t = Clock.currTime();
if (t.month < mm) correction = 1;
else if (t.month == mm) correction = (t.day < dd) ? 1 : 0;
else correction = 0;
return (t.year - yyyy - correction);
}

void main() {
try
writefln("Edad: %s años.", getAge(1958, 1, 21));
catch(Exception e) {
writefln("%s.\n(%s, line %s)", e.msg, e.file, e.line);
}
}

That's the better approach, I think. Years have variable lengths.
Determining "age" in years works by comparing dates, not durations.

I would write it like this, but as far as I see yours does the same thing:

----
int getAge(int yyyy, int mm, int dd)
{
import std.datetime;

immutable SysTime now = Clock.currTime();
immutable int years = now.year - yyyy;

return mm > now.month || mm == now.month && dd > now.day
? years - 1 // birthday hasn't come yet this year
: years; // birthday has already been this year
}

void main()
{
import std.stdio;

/* Day of writing: 2017-01-15 */
writeln(getAge(1980, 1, 1)); /* 37 */
writeln(getAge(1980, 1, 15)); /* 37 (birthday is today) */
writeln(getAge(1980, 1, 30)); /* 36 */
writeln(getAge(1980, 6, 1)); /* 36 */
}
----

Isn't there a built-in function to do this?

If there is, finding it in std.datetime would take me longer than
writing it myself.
```
Jan 15 2017
rikki cattermole <rikki cattermole.co.nz> writes:
```On 15/01/2017 4:43 PM, Nestor wrote:
Hi,

I would simply like to get someone's age, but I am a little lost with
time and date functions. I can already get the duration, but after
reading the documentation it's unclear to me how to convert that into
years. See following code:

import std.stdio;

void getAge(int yyyy, int mm, int dd) {
import std.datetime;
SysTime t1 = SysTime(Date(yyyy, mm, dd));
SysTime t2 = Clock.currTime();
writeln(t2 - t1);
}

int main() {
try
getAge(1980, 1, 1);
catch(Exception e) {
writefln("%s.\n(%s, line %s)", e.msg, e.file, e.line);
}
}

Notice getAge should return ubyte instead of void, only I haven't been
able to find how to do it. Any suggestion would be welcome.

So I had a go at this and found I struggled looking at "magic" functions
and methods.
Turns out there is a much simpler answer.

int getAge(int yyyy, int mm, int dd) {
import std.datetime;
auto t1 = cast(DateTime)SysTime(Date(yyyy, mm, dd));
auto t2 = cast(DateTime)Clock.currTime();

int numYears;
while(t2 > t1) {
numYears++;
}

return numYears;
}
```
Jan 14 2017
Nestor <nestorperez2016 yopmail.com> writes:
```On Sunday, 15 January 2017 at 07:25:26 UTC, rikki cattermole
wrote:
So I had a go at this and found I struggled looking at "magic"
functions and methods.
Turns out there is a much simpler answer.

int getAge(int yyyy, int mm, int dd) {
import std.datetime;
auto t1 = cast(DateTime)SysTime(Date(yyyy, mm, dd));
auto t2 = cast(DateTime)Clock.currTime();

int numYears;
while(t2 > t1) {
numYears++;
}

return numYears;
}

Well... correct me if I am wrong, but isn't t1.add!"years"(1)
simply adding one year to t1?
```
Jan 15 2017
Nestor <nestorperez2016 yopmail.com> writes:
```I cleaned up the function a little, but it still feels like a
hack:

uint getAge(uint yyyy, uint mm, uint dd) {
import std.datetime;
SysTime t = Clock.currTime;
ubyte correction = 0;
if(
(t.month < mm) ||
( (t.month == mm) && (t.day < dd) )
) correction += 1;
return (t.year - yyyy - correction);
}

Isn't there anything better?
```
Jan 15 2017
rikki cattermole <rikki cattermole.co.nz> writes:
```On 15/01/2017 9:40 PM, Nestor wrote:
I cleaned up the function a little, but it still feels like a hack:

uint getAge(uint yyyy, uint mm, uint dd) {
import std.datetime;
SysTime t = Clock.currTime;
ubyte correction = 0;
if(
(t.month < mm) ||
( (t.month == mm) && (t.day < dd) )
) correction += 1;
return (t.year - yyyy - correction);
}

Isn't there anything better?

The problem with this is that it won't take into account leap years.
```
Jan 15 2017
biozic <dransic gmail.com> writes:
```On Sunday, 15 January 2017 at 08:40:37 UTC, Nestor wrote:
I cleaned up the function a little, but it still feels like a
hack:

uint getAge(uint yyyy, uint mm, uint dd) {
import std.datetime;
SysTime t = Clock.currTime;
ubyte correction = 0;
if(
(t.month < mm) ||
( (t.month == mm) && (t.day < dd) )
) correction += 1;
return (t.year - yyyy - correction);
}

Isn't there anything better?

It doesn't feel like a hack to me, because it's simple and
correct code that comply with the common definition of a person's
age. The only inaccuracy I can think of is about people born on
February 29th...
```
Jan 15 2017
Nestor <nestorperez2016 yopmail.com> writes:
```On Sunday, 15 January 2017 at 11:01:28 UTC, biozic wrote:
On Sunday, 15 January 2017 at 08:40:37 UTC, Nestor wrote:
I cleaned up the function a little, but it still feels like a
hack:

uint getAge(uint yyyy, uint mm, uint dd) {
import std.datetime;
SysTime t = Clock.currTime;
ubyte correction = 0;
if(
(t.month < mm) ||
( (t.month == mm) && (t.day < dd) )
) correction += 1;
return (t.year - yyyy - correction);
}

Isn't there anything better?

It doesn't feel like a hack to me, because it's simple and
correct code that comply with the common definition of a
person's age. The only inaccuracy I can think of is about
people born on February 29th...

I know. I thought about it as well, but it's not something you
can deal with cleanly.

For example, take a baby born in february 29 of year 2000 (leap
year). In february 28 of 2001 that baby was one day short to one
year.

Family can make a concession and celebrate birthdays in february
28 of non-leap years, but march 1 is the actual day when the year
of life completes. Which one to choose?

Another way to deal with this is modifying the function to take a
parameter which allows to do a relaxed calculation in non-leap
years if one so desires.
```
Jan 15 2017
Nestor <nestorperez2016 yopmail.com> writes:
```On Sunday, 15 January 2017 at 14:04:39 UTC, Nestor wrote:
...
For example, take a baby born in february 29 of year 2000 (leap
year). In february 28 of 2001 that baby was one day short to
one year.

Family can make a concession and celebrate birthdays in
february 28 of non-leap years, but march 1 is the actual day
when the year of life completes. Which one to choose?

On second thought, if a baby was born in march 1 of 1999
(non-leap year), in march 1 of 2000 (leap year) the age would
have been one year plus one day (because of february 29). So
perhaps the best thing is to always perform a "relaxed"
calculation.
```
Jan 15 2017
biozic <dransic gmail.com> writes:
```On Sunday, 15 January 2017 at 14:20:04 UTC, Nestor wrote:
On Sunday, 15 January 2017 at 14:04:39 UTC, Nestor wrote:
...
For example, take a baby born in february 29 of year 2000
(leap year). In february 28 of 2001 that baby was one day
short to one year.

Family can make a concession and celebrate birthdays in
february 28 of non-leap years, but march 1 is the actual day
when the year of life completes. Which one to choose?

On second thought, if a baby was born in march 1 of 1999
(non-leap year), in march 1 of 2000 (leap year) the age would
have been one year plus one day (because of february 29).

No. A baby born on March 1st 1999 is just "one year old" on March
1st 2000, as it also is on March 2nd or any day after during the
same year.

So perhaps the best thing is to always perform a "relaxed"
calculation.

I guess the problem of people born on February 29th is really
application-dependent, and it also depends on the use of the
calculated age. A social web app: users probably would like to
see their age change on the 28th of non-leap years. A
regulation-aware software: just follow what the law says. Etc.
```
Jan 15 2017
Nestor <nestorperez2016 yopmail.com> writes:
```On Sunday, 15 January 2017 at 16:57:35 UTC, biozic wrote:
On Sunday, 15 January 2017 at 14:20:04 UTC, Nestor wrote:
On second thought, if a baby was born in march 1 of 1999
(non-leap year), in march 1 of 2000 (leap year) the age would
have been one year plus one day (because of february 29).

No. A baby born on March 1st 1999 is just "one year old" on
March 1st 2000, as it also is on March 2nd or any day after
during the same year.

Perhaps I didn't make myself clear. I was not refering here to
age in the conventional sense, but to the actual aging process.
In other words, in this particular case the amount of days
elapsed would have been 366 instead of 365.
```
Jan 15 2017
Jonathan M Davis via Digitalmars-d-learn writes:
```On Sunday, January 15, 2017 03:43:32 Nestor via Digitalmars-d-learn wrote:
Hi,

I would simply like to get someone's age, but I am a little lost
with time and date functions. I can already get the duration, but
after reading the documentation it's unclear to me how to convert
that into years. See following code:

import std.stdio;

void getAge(int yyyy, int mm, int dd) {
import std.datetime;
SysTime t1 = SysTime(Date(yyyy, mm, dd));
SysTime t2 = Clock.currTime();
writeln(t2 - t1);
}

int main() {
try
getAge(1980, 1, 1);
catch(Exception e) {
writefln("%s.\n(%s, line %s)", e.msg, e.file, e.line);
}
}

Notice getAge should return ubyte instead of void, only I haven't
been able to find how to do it. Any suggestion would be welcome.

Well, there's diffMonths:

http://dlang.org/phobos/std_datetime.html#.SysTime.diffMonths

However, I doubt that it really does quite what you want. Because of the
varying lengths of months and years, you're probably going to have to write
code that does what you want with some combination of function. You probably
want to do something like

void getAge(int yyyy, int mm, int dd)
{
auto birthdate = Date(yyyy, mm, dd);
auto currDate = cast(Date)Clock.currTime;
// This make Feb 29th become March 1st
auto birthdayThisYear = Date(currDate.year, mm, 1) + days(dd - 1);
auto years = currDate.year - birthdate.year;
if(currDate < birthdayThisYear)
--years;
writeln(years);
}

I _think_ that that does it, but I'd want to do something like

void printAge(int yyyy, int mm, int dd)
{
writeln(getAge(cast(Date)Clock.currTime(), yyyy, mm, dd);
}

int getAge(Date currDate, int yyyy, int mm, int dd)
{
auto birthdate = Date(yyyy, mm, dd);
auto currDate = cast(Date)Clock.currTime;
// This make Feb 29th become March 1st
auto birthdayThisYear = Date(currDate.year, mm, 1) + days(dd - 1);
auto years = currDate.year - birthdate.year;
if(currDate < birthdayThisYear)
--years;
return years;
}

and then add unit tests for getAge to verify that it did the correct thing
for various dates. It's quite possible that there's something subtley wrong
with it. Also, depending on what exactly you're trying to do, it's possible
that I didn't quite understand what you're trying to do and that it needs
some additional tweaks in order to do what you want.

- Jonathan M Davis
```
Jan 15 2017
Nestor <nestorperez2016 yopmail.com> writes:
```Thank you all.
```
Jan 15 2017