Dataview Date Difference Calculation Errors

What I’m trying to do

Hello all. I am having problems getting dataview to calculate the number of days between today and a person’s birthday this year. I am using version 0.5.67 of dataview. The property in the note is “birthday” and is in the format of yyyy-MM-dd. Here is the script I am using:

TABLE 
dateformat(birthday, "dd MMMM") AS "Birthday",
floor((date(today) - date(birthday)).years) AS "Age",
(daysUntilBirthday) AS "Days Away"
FROM ""
WHERE birthday
FLATTEN date(dateformat(date(today), "yyyy-MM-dd")) AS todayDate
FLATTEN date(todayDate.year + "-" + dateformat(birthday, "MM-dd")) AS birthdayThisYear
FLATTEN date((todayDate.year + 1) + "-" + dateformat(birthday, "MM-dd")) AS birthdayNextYear
FLATTEN choice(birthdayThisYear >= todayDate, birthdayThisYear, birthdayNextYear) AS nextBirthday
FLATTEN (nextBirthday - todayDate).days AS daysUntilBirthday
WHERE daysUntilBirthday <= 365 AND daysUntilBirthday >= 0
SORT daysUntilBirthday ASC
LIMIT 10

It appears to calculate correctly for all dates that are less than 28 days away. However, any dates 28 days or more away calculate 1-3 days more than actual. Here are some examples of script output:

NB: Today is 21 February

Birthday of 15 March = 22 days away (correct)
Birthday of 23 March = 32 days away (actual is 30)
Birthday of 17 May = 86 days away (actual is 85)

Things I have tried

I searched this forum. I asked ChatGPT, CoPilot and Gemini for help and they could not resolve it. I looked to see if the issue is with dataview itself but without luck. Any help would be appreciated.

1 Like

Hello.

I think this is a long-term bug:

Dataview is meant to be replaced by Datacore, although the original release estimate of January 2023 has long since passed. I think this bug is unlikely to be fixed in Dataview. :person_shrugging:

Someone might have a workaround (see the link above for one suggestion).

It’s a known issue with the date library used by dataview, that when it calculates durations over one month something strange happens. There is some logic, which I’ve never fully understood.

Some ways to remedy this is to use dateformat(someDate, "o") to get the ordinal day of the year, and use that in your day calculations.

Try out this query and see if you can make any sense out of it:

```dataview
TABLE WITHOUT ID birthday, thisYear, todayDate, dayDiff, age
WHERE birthday
FLATTEN date(today) as todayDate
FLATTEN date(todayDate.year + dateformat(birthday, "-MM-dd")) as thisYear
FLATTEN number(dateformat(thisYear, "o")) - number(dateformat(todayDate, "o")) as dayDiff
FLATTEN choice(dayDiff <= 0, 
  (todayDate.year - birthday.year) + " years, " + string(-1 * dayDiff) + " days",
  (todayDate.year - birthday.year -1)  + " years, " + (365 - dayDiff) + " days"
) as age 
```

Here if dayDiff is negative it’s a day in the past, meaning that their birthday has been this year, and the year calculation is correct. Vice versa, if the dayDiff is positive, it’s listing how many days until their birthday later this year.

A more directly related example to your query is achieved if you do the following in a random note:

birthdays:: 2020-01-09
birthdays:: 2020-03-15
birthdays:: 2020-03-23
birthdays:: 2020-05-17

```dataview
TABLE WITHOUT ID birthday, thisYear, todayDate, dayDiff, age, Next, durNext
WHERE file = this.file
FLATTEN this.birthdays as birthday
FLATTEN date(today) as todayDate
FLATTEN date(todayDate.year + dateformat(birthday, "-MM-dd")) as thisYear
FLATTEN number(dateformat(thisYear, "o")) - number(dateformat(todayDate, "o")) as dayDiff
FLATTEN choice(dayDiff <= 0, 
  (todayDate.year - birthday.year) + " years, " + string(-1 * dayDiff) + " days",
  (todayDate.year - birthday.year -1)  + " years, " + (365 - dayDiff) + " days"
) as age 
FLATTEN choice(dayDiff <= 0,
  "birthday was " + (-1 * dayDiff) + " days ago, and next is in " + (365 + dayDiff) + " days",
  "birthdays is in " + dayDiff + " days") as Next
FLATTEN (thisYear - todayDate).days as durNext
```

Which should give output similar to:

This illustrates both how using the ordinal day works (possibly with an error related to leap years having 366 days), and how the duration days doesn’t work.