Calculating Date Difference Incorrectly

What I’m trying to do

I want to show the age difference between Birthdate and Deathdate. If there is no deathdate, use today’s date

Things I have tried

I’m using syntax that I found here: How to Calculate Duration between Dates in Dataview - #3 by ryanjamurphy

But it is calculating things slightly incorrectly.

Here is what I’m using in mine:

TABLE WITHOUT ID as Person, Birthdate, DeathDate as "Death Date", choice(!DeathDate, date(today), DeathDate) - Birthdate as Age
FROM "Family Tree/People"
WHERE !contains(tags,"Template") AND BirthMonth = "January"

For example, Jim is born on 1/5/83 and today is 1/3/24. It is rendering his age as 41 years, 1 day, when it should be 40 years, 11 months, 29 days. Any idea why this might be?

I ran the following query in a note of its own:

Birthdate:: 1983-01-05

  Birthdate, DeathDate as "Death Date", 
  ageDuration as Age, ageDuration.days as "Age days", 
  ageInDays, dur(ageInDays  + "days"),
  DeathDays, BirthDays, DeathDays - BirthDays, dur((DeathDays - BirthDays) + " days")
WHERE file = this.file
FLATTEN list(date(2024-01-02), date(2024-01-03), date(2024-01-04), date(2024-01-05)) as DeathDate
FLATTEN default(DeathDate, date(today)) - Birthdate as ageDuration
FLATTEN (number(dateformat(DeathDate, "x")) - number(dateformat(Birthdate, "x")))/86400/1000 as ageInDays
FLATTEN (DeathDate - date(1950-01-01)).days as DeathDays
FLATTEN (Birthdate - date(1950-01-01)).days as BirthDays

365 multiplied by 41 = `= 41 * 365`

And I got really confused… The various results differs from 41 years to 44 years and 6 months… And various variants in between those…

In short, date calculations are tricky. Very tricky. We as humans automatically do stuff related to years and leap years, months having 28 (29), 30 or 31 days, which is not as easy to do with computers. And it do seem like dataview is not very good at this stuff…

For a little read up on the topic, see Fix month and year diffs by timrwood · Pull Request #571 · moment/moment · GitHub

Would this be better using dataviewjs… Maybe? Maybe not?

I put together the following:

const birthDate = dv.current().Birthdate

for (let deathDateStr of ["2024-01-01", "2024-01-02", "2024-01-03", "2024-01-04", "2024-01-05"]) {
  const a = moment(deathDateStr)
  const b = moment(birthDate.toISODate())
 dv.header(3,  a.format("YYYY-MM-DD") + " vs " + b.format("YYYY-MM-DD"))
 dv.paragraph( a.from(b) + " / " + 
   a.diff(b, "days")  + " // " +
   moment.duration(a.diff(b)).humanize({d: 365})
 const yearDiff = a.diff(b, "years")
 const monthDiff = a.diff(b, "months") - yearDiff*12 
 dv.paragraph( a.diff(b, "years") + " | " + monthDiff + " | " + a.diff(b, "days") + "???")

with the output of:

At least it can be persuaded into giving the correct number of years and month between the dates. But was that easy to achieve? Nope… Can we calculate the days part… Nah… Not in the time span I dedicated to answer this request. The days part is the really icky part since that needs to account for leap years, when in the year we’re currently at, which day of month we’re in, and so on…

The moment.js documentation does however indicate that it could show more humanize() variants of its duration, which should account for proximity in days across month boundaries and so on… So maybe?

This latter method, could however at least calculate the age in years and month accurately, using some variation over:

 const yearDiff = a.diff(b, "years")
 const monthDiff = a.diff(b, "months") - yearDiff*12 
 dv.paragraph( a.diff(b, "years") + " | " + monthDiff )

Hopefully this gives some hints as to the complexity and strangeness of date calculations. Sorry, it’s not the answer you might have wanted to have.

1 Like

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