Calculate the age of someone based on front matter

What I’m trying to do

I have notes on people and in the front matter I have a birthday property with a date formatted YYYY-MM-DD

Carla’s birthday is 1993-03-17 which makes her 30. I would like a section under the front matter with a simple dataview query using momentjs (or anything else) to calculate her age based on the front matter.

Carla’s Note

---
birthday: 1993-03-17
---
Age:: 30

Sorry for the code dump but but after many attempts at what I feel should work and searching StackOverflow, Reddit, and this form. I don’t know what I am doing wrong.

I would prefer the inline Dataview so that it can come after the Age::

Things I have tried

This is driving me insane, this should be a simple currentDate - birthday. But no matter what I did, I could not get anything close to the correct answer, or it just throw NaN, -NaN, <$>

`$= moment().diff(moment(dv.current().birthday, "YYYY-MM-DD"), 'years')`

Produces:
NaN

`$= Math.floor(moment(new Date()).diff(moment(dv.current().birthday,"YYYY-MM-DD"),'years',true))`

Produces:
NaN

`$= moment().subtract(dv.current().birthday, 'year').format('YY')`

Produces:
-NaN

`$= moment().endOf('day').diff(moment(dv.current().birthday, 'MMMM DD[,] YYYY'), 'years')`

Produces:
NaN

`$= moment().endOf('day').diff(1993, 'years')`

Produces:
53 (How, why, What?)

`$= moment(moment().endOf('day').format('YY')).subtract(dv.current().birthday, 'years')`

Produces:
<$>

`$= moment().subtract(moment(dv.current().birthday).format('YYYY'), 'years').format('YY')`

Produces:
00 (Why?)

```dataviewjs
const birthday = moment(dv.current().birthday).format('YYYY-MM-DD');
dv.paragraph("birthday: " + birthday);

const parsedBirthday = moment(birthday).format('YYYY');
dv.paragraph("parsedBirthday: " + parsedBirthday);

const ageInYears = moment().diff(parsedBirthday, 'years');
dv.paragraph("ageInYears: " + ageInYears);

const ageAsTwoDigitYear = moment().subtract(ageInYears, 'years').format('YY');
dv.paragraph("ageAsTwoDigitYear: " + ageAsTwoDigitYear);
```

Produces:

birthday: 2023-04-18

parsedBirthday: 2023

ageInYears: 0

ageAsTwoDigitYear: 23

Not even remotly close…

:crossed_fingers:

`=date(today) - this.birthday`

Does it work?

EDIT:

The following query works when placed in a note that has an ISO8061 format date in its title:

Age2:: `=date(this.file.day) - this.birthday`


https://blacksmithgu.github.io/obsidian-dataview/annotation/metadata-pages/#implicit-fields

1 Like

See I new this was going to be simple and that I was over thinking it… Thank you @anon63144152 this has been making my mad for a few weeks every time I come back to the problem. Just kept giving up. Thank you for multiple solutions.

1 Like

@anon63144152 How would one format this date. I am going back and forth weather I like it showing Years, months, weeks, days. It is kinda nice, but for those who want it formatted “YY” for example.

1 Like

Hello.

The following works in local tests:

age2:: `=date(this.file.day).year - this.birthday.year` years old

Hope it does what you need. :crossed_fingers:t4:

Some comments related to why your various examples failed, based on the following setup:

The this.birthday or dv.current().birthday are already a DateTime object, so doing stuff like diff(dv.current().birthday, 'YYYY-MM-DD') just confuses moment, it seems. This can be seen in the third line showing the birthday:. To actually get moment to accept is a date, one way to do that would be to do the dv.current().birthday.toISODate.

This is further examplified on the fourth line with the diff:, which is using your line with the addition of .toISODate() to help moment understand it as a date. The fifth line, subtract, uses another method which is to extract the year through the DateTime object, before subtracting it. So now both of these produce the expected 30 years result.

The last section with the diff 1993 baffled me a little until I realised it took that as milliseconds since 1970-01-01. So “1993” is close to 2 second after midnight on 1970-01-01. This can be shown by doing a `$= moment(1993).format(“YYYY-MM-DD HH:mm:ss Z”) `. So the difference of 53 years is from today back to 1970.

One of the alternate ways to enter a random date, is to use the [YYYY, MM, DD] format as showcased in the last line.


Hopefully, this illuminates a little on how important it is to understand how and what moment accepts as dates, and how to use in combination with Dataview’s DateTime object.

I think my post above regarding a YY value is not working correctly as it is just subtracting the years from each other and ignoring the months and days.

I looked at this reference but the suggested syntax gives a decimal value for the calculation:

`= (date(this.file.day) - this.birthday).years`

I don’t understand the post by @holroy to know if an accurate years-only calculation can be formulated against a date extracted from a file name. I have zero understanding of DVJS.

Sorry.

Date calculation is one area where it’s hard to tell what’s the wanted output. Do you want the exact age, or the approximate age? Does 360 days equal a year, or not?

One thing I’m a little stumped by is the Dataview handling of dates, is its handling of days and months. Like the difference from 2023-03-17 to 2023-02-16, how many days are that?

duration: `= dur(date(2023-03-17) - date(2023-02-16))`
duration.days: `= dur(date(2023-03-17) - date(2023-02-16)).days`
day of year, 2023-03-17: `= dateformat(date(2023-03-17), "o")`
day of year, 2023-02-16: `= dateformat(date(2023-02-16), "o")`
difference of day of year: `= number(dateformat(date(2023-03-17), "o")) - number(dateformat(date(2023-02-16), "o"))`

The duration.days line says it’s 31 days, but if you use the day of the year calculation it’s 29 days. Most people would argue the latter is the right one. But one can see how the first one does a difference of 1 month, and an additional day, which also makes sense. (The transformation into that being 31 days, though, … )

My point is that the same might apply to doing year calculations (on the DateTime objects), and similar issues might occur when using moment(). So date calculations, from my point of view, are tricky and slightly confusing.

1 Like

Thanks.

There’s an open bug report about dates being miscalculated:

All of this = :exploding_head:

Assumed it would be possible just to get the number of years right for the OP.

1 Like

Great discussion, very enlightening. Thanks for chiming in @holroy that info will be very useful in the future. Gosh dates always suck in programming.

2 Likes

Forgive the high level of ignorance that follows.

We can use this syntax to get years only:

`$=dv.array(moment('2023-04-21').diff(moment('1993-03-17'), 'years').toLocaleString('en-en') + " years")`

If we have a file name such as 2023-04-21, is it not possible to write this so that the array(moment is taken from the file name and the diff(moment is taken from the value for birthday?

`$=dv.array(moment('this.file.day').diff(moment('this.birthday'), 'years').toLocaleString('en-en') + " years")`

And if not the file name, can we just use something like (date(today) for the first array(moment?

`$=dv.array(moment('date.today').diff(moment('this.birthday'), 'years').toLocaleString('en-en') + " years")`

If DQL can extract dates from file names and YAML keys, why can’t DVJS?

No problem, I’m confused myself when navigating this landscape of dates in different contexts.

Within dvjs, this becomes dv.current(), so this.file.day should be dv.current().file.day. ( This will give a DateTime object (which is not the same as a moment() date object. ))

Within moment() we can’t use Dataview dates (aka DateTime object) directly, we need to convert them using .toISODate() (or similar) when passed to a constructor of moment() (or something which accepts the same parameters as a constructor).

So dvjs can extract dates from file names and YAML keys, but the syntax differs, and when used in combination with moment() you need to translate the date variables even a little more.

So your example therefore becomes:

`$= moment(dv.current().file.day.toISODate()).diff(dv.current().birthday.toISODate(), 'years')`

And if you use just moment() it’ll give todays date, but to display it you would typically do something like: `$= moment().format(“YYYY-MM-DD”) `.

1 Like

Thanks for the deep-dive explanation. It seems that the OP can get the YY format wanted when calculating ages.

Very grateful for your time and knowledge. :pray:

---
birthday: 1995-05-09
---

# 1. date calculated from ==date in file name== and birthday date in YAML header
```
`$= moment(dv.current().file.day.toISODate()).diff(dv.current().birthday.toISODate(), 'years')` years old
```

# 2. date calculated from ==date today== and birthday date in YAML header
```
`$= moment().diff(dv.current().birthday.toISODate(), 'years')` years old
```

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.