Weird anomaly when comparing dates with Dataview

I’m having a weird anomaly when using multiple conditions in a dataview query for fetching tasks. My daily note’s format is as such: “Mon Mar 31 2025”

Here’s a query I use for my daily notes, which works great but the problem is that I’m going to lose tasks from the previous month since I’m only checking tasks contained within the month.

TASK WHERE
  // if link to "do later"
  contains(outlinks, [[🕒 Later]])
  // if due or overdue
	OR (due AND due <= date(this.file.name, "ccc LLL dd yyyy"))
  OR (
    // if the note has the "daily notes" category
    contains(categories, [[📆 Daily Notes]])
    // check if note contains the same month and if the date is lower to the current note's date
    AND contains(this.file.name, split(this.file.name, " ")[1]) AND split(file.name, " ")[2] < split(this.file.name, " ")[2]
  )
  // if the note is not completed
  AND (!completed AND status != "-")
GROUP BY file.link

I’m trying to fetch any tasks that are contained to a daily note prior to the current day’s note. So I tweaked my query to this:

TASK WHERE
  // if link to "do later"
  contains(outlinks, [[🕒 Later]])
  // if due or overdue
	OR (due AND due <= date(this.file.name, "ccc LLL dd yyyy"))
  OR (
    // if the note has the "daily notes" category
    contains(categories, [[📆 Daily Notes]])
    // TWEAKED LINE IS HERE:
    // and if the note title converted to a date is less than or equal to the current note's title converted to a date
    AND date(file.name, "ccc LLL dd yyyy") <= date(this.file.name, "ccc LLL dd yyyy")
  )
  // if the note is not completed
  AND (!completed AND status != "-")
GROUP BY file.link

Somehow if I change the line:
AND contains(this.file.name, split(this.file.name, " ")[1]) AND split(file.name, " ")[2] < split(this.file.name, " ")[2]
to
AND date(file.name, "ccc LLL dd yyyy") <= date(this.file.name, "ccc LLL dd yyyy"), every previous conditions are being ignored.

So for instance, any tasks that linked to [[🕒 Later]] are being ignored using my new query but nothing has really changed except that I’m using a date comparison instead of comparing strings which is very peculiar.

I don’t know if that’s a bug or I’m just oblivious to some mistake I’ve made in the query. Anyone has a suggestion?

Thanks!


EDIT: Here’s another great example of the date clause taking precedence over the other clause even though it’s an OR condition:

This shows the tasks linking to [[🕒 Later]]

TASK WHERE (
    contains(outlinks, [[🕒 Later]])
) AND (!completed AND status != "-")
GROUP BY file.link

But this does NOT show them, only the task from previous daily notes show up:

TASK WHERE (
    contains(outlinks, [[🕒 Later]]) 
    OR date(file.name, "ccc LLL dd yyyy") <= date(this.file.name, "ccc LLL dd yyyy")
) AND (!completed AND status != "-")
GROUP BY file.link

When in fact, it should because it should show if something links to [[🕒 Later]] OR if it is from a previous daily note.


EDIT2: If I replace the condition with AND file.cdate <= this.file.cdate it does work. This is a good temporary fix but sometimes I might not create the daily notes in order (ie. I create tomorrow’s daily note but today)

So yeah, the problem is with this line: date(file.name, "ccc LLL dd yyyy") <= date(this.file.name, "ccc LLL dd yyyy")… I even tried checking if the dates were not null, if the dates were of the actual type “date”, etc…


I’m so confused :person_shrugging:

It could be that in your date format string, you’re using the standalone rather than the format tokens for the day of the week and the month. They should be “EEE” and “MMM” respectively.

1 Like

I tried and unfortunately it didn’t help. Thanks for looking into it though!

Can you check that these date expressions are evaluating how you expect?

Yes, I’ve been using this syntax everywhere in my vault and it’s been working fine.

I’ll still will start using the format tokens in the future just to avoid situations where it could be an actual problem.

So if I understand right, the standalone vs format token would be needed in this situation:

// only use one token
contains(file.name, dateformat(date(today), "LLL")) AND
// use multiple tokens
split(file.name, " ")[2] < split(dateformat(date(today), "EEE MMM dd yyyy"), " ")[2]

That’s interesting. I had never noticed that before.

Somehow, it doesn’t help in this case:

TASK WHERE (
  contains(outlinks, [[🕒 Later]])
  OR (due AND due <= date(this.file.name, "EEE MMM dd yyyy"))
  OR (
    contains(categories, [[📆 Daily Notes]]) 
    AND date(file.name, "EEE MMM dd yyyy") <= date(this.file.name, "EEE MMM dd yyyy")
  )
) AND (!completed AND status != "-")
GROUP BY file.link

:person_shrugging: but thanks, I didn’t know that!

I’m starting to feel like it’s an actual bug because I don’t see why, in any case, should one statement should supercede all the others statements when inside a OR condition.

  -- this statement gets ignoed:
  contains(outlinks, [[🕒 Later]])
  -- and this statement gets ignoed:
  OR (due AND due <= date(this.file.name, "EEE MMM dd yyyy"))
  OR (
    contains(categories, [[📆 Daily Notes]]) 
    -- WHEN I ADD THIS LINE:
    AND date(file.name, "EEE MMM dd yyyy") <= date(this.file.name, "EEE MMM dd yyyy")
  )

When I use something else than that date() <= date() comparison line, all 3 cases show up in the list. Otherwise, it’s only tasks that have been filtered by the date() <= date() comparison :exploding_head:

I might try to convert this query to dataviewjs just to bypass the problem at this point.

Even when using dv.date() I’m having issues converting dates. I worked around my problem using dataviewjs and JS’ Date() object instead.

const currentDate = new Date(Date.parse(dv.current().file.name));
const yesterdayDate = new Date(currentDate.valueOf()).setDate(currentDate.getDate() - 1);

const groupedTasks = dv.pages().file.tasks.array().reduce((acc, task) => {
    if (task.completed || task.status === "-") return acc;

    const isDue = task.due && new Date(Date.parse(task.due)) <= currentDate;
    const isScheduled = task.scheduled && new Date(Date.parse(task.scheduled)) <= currentDate;
    const hasLaterOutlink = task.outlinks?.some(o => o.path.includes("🕒 Later"));

    const note = dv.page(task.path);
    const isFromDailyNote = note.categories?.some(c => c.path.includes("📆 Daily Notes"));
    const isDailyNoteInThePast = isFromDailyNote && new Date(Date.parse(note.file.name)) <= yesterdayDate;

    if (hasLaterOutlink || isDue || isScheduled || isDailyNoteInThePast) {
        if (!acc[task.link]) {
            acc[task.link] = [];
        }
        acc[task.link].push(task);
    }

    return acc;
}, {});

dv.taskList(Object.values(groupedTasks).flat());

This actually gives me the exact output I wanted.

Bottom line is, there is definitively an issue with Dataview’s date object.

For instance this will never work for me:

console.log(dv.date("Sun Mar 30 2025", "EEE MMM d yyyy")) // always returns NULL
console.log(dv.date("Sun Mar 30 2025", "ccc LLL d yyyy")) // always returns NULL

I didn’t try your dataviewjs code, but your before and after dataview queries gave me the exact results you described. Two little changes fixed it in my sandbox (and fixed the issue of the disappearing Later tasks):

  • Use task.file.name instead of file.name in the “Daily Note”-category date check.

  • In the date comparison, I had to change due to date(due) and add its date format to make even your before query work. I don’t know if you’re using the Tasks plugin or another date-related plugin (I’m not) and whether that’s what made it work for you originally, but I needed to specify that due is a date in order to work with it.

Code:

```dataview
TASK WHERE (
  contains(outlinks, [[🕒 Later]])
  OR (due AND date(due, "EEE MMM dd yyyy") <= date(this.file.name, "EEE MMM dd yyyy"))
  OR (
    contains(categories, [[📆 Daily Notes]])
    AND date(task.file.name, "EEE MMM dd yyyy") <= date(this.file.name, "EEE MMM dd yyyy")
  )
) AND (!completed AND status != "-")
GROUP BY file.link
```

If I’ve understood your issue, then this makes it seem like it might not be a date comparison bug.

In case it helps you resolve it or investigate further, here’s what the comparison looked like with a few test notes and tasks:

You’re touching on very many different issues here, and I’m not sure I’ve got the answers to all of them, but there are few key issues I can address.

  • Yes, date recognition with locale specific dates is troublesome - The library that Dataview uses, in combination with how the locale is setup, is occasionally returning errors when some of the locale specific format tokens are used (like “ccc” or “LLL”). One example of such a failure for me when I’m using the Norwegian locale in general on my computer: `= date(dateformat(date(today), "ccc LLL d yyyy"), "ccc LLL d yyyy")`. In theory this should format the date according to the tokens, and then recognise the date using the same token. It fails…

  • A failed date recognition can cause rows to disappear - Up until and including version 0.5.68, there is a bug related to how some of the date (and duration) handling can actually cause that entire row to disappear from the result. This can happen if any of the expressions used handling that row causes an error. Especially tricky is cases where the WHERE normally wouldn’t apply, but in the OR case there is some date recognition which fails. Hopefully this will be handled in the next version, if I can only decide on how to better handle the error output related to these cases.

  • Tokens might work when displaying, but not recognising - Using the tokens in dateformat(date, format) and date(text, format) is vastly different. You can display correctly according to your current locale, and still have the recognising being wrong (as demonstrated above)

  • dv.date() and dv.func.date() might be different - The latter is the version used in a DQL query like a TASK query. I don’t remember the details, but they might differ…

  • Doing date and link comparisons in javascript requires special functions - In javascript you can’t use compare two dates using = operator. You need to use special functions like aDate.equals(bDate). Similar for links. Try the code below to mess with your mind…

` =` is **not** OK: `$= new Date("2023-03-31") == new Date("2023-03-31")`
dv.date is OK: `$= dv.date("2025-03-31").equals(dv.date("2025-03-31")) `
dv.func.contains on dv.func.date is OK: `$= dv.func.contains(dv.func.date("2025-03-31"), dv.func.date("2025-03-31")) `
dv.func.date is OK: `$= dv.func.date("2025-03-31").equals(dv.func.date("2025-03-31")) `
  • Using task.file.name seems strange - I’m not sure why you would want to do that outside of a TABLE query where you’ve done FLATTEN file.tasks as task. In a TASK query that just seems to be wrong

What’s the way forward?!

You’ve got mainly two options. Either you wait until the next version and see if that is better at handling locale specific date conversions. I’m not sure what I’m able to correct though, but one way or another I either want the queries to report errors or defintively not remove rows from the result set.

Or, and this is the better option as I see it, loop through your files and add a property called date which is populated with a proper ISO 8601 date value. This will allow your queries to use file.day to get that date in a uniform and consistent way, and you’ll not need to keep converting dates back and forth.

The latter option would still allow you to have file names like you want them, but also to allow a way better date handling within Dataview queries. You can then also of course presents the days in any way you feel like, but the query will work a whole lot better (even in current (or older) versions of Dataview).

1 Like

I’m not the OP but just returning to say (1) that’s very interesting, holroy, and explicit error handling of that date recognition issue sounds like a good idea, whatever method you go with.

(2) I was the one who brought up task.file.name (not the OP) . I don’t know the reason it created the desired result while file.name left out lots of rows but guessed it had to do with where it’s being evaluated in the task query:

TASK
WHERE
  ...
  OR (
    ...
    AND
    date(task.file.name ... ) <= date(...)
  )
  AND ...

I don’t have a dog in this and don’t need a response, but here is the difference if you’re interested or feel like expounding:

screenshot

Query results on a handful of test notes that mimicked the OP’s set-up:

markdown file with dataview queries for testing

note name: Mon Apr 14 2025.md

## using `file.name`

```dataview
TASK
WHERE
  contains(outlinks, [[🕒 Later]])
  OR (due AND date(due, "EEE MMM dd yyyy") <= date(this.file.name, "EEE MMM dd yyyy"))
  OR (
    contains(categories, [[📆 Daily Notes]])
    AND date(file.name, "EEE MMM dd yyyy") <= date(this.file.name, "EEE MMM dd yyyy")
  )
  AND !completed AND status != "-"
GROUP BY file.link
```

---

## using `task.file.name`

```dataview
TASK
WHERE
  contains(outlinks, [[🕒 Later]])
  OR (due AND date(due, "EEE MMM dd yyyy") <= date(this.file.name, "EEE MMM dd yyyy"))
  OR (
    contains(categories, [[📆 Daily Notes]])
    AND date(task.file.name, "EEE MMM dd yyyy") <= date(this.file.name, "EEE MMM dd yyyy")
  )
  AND !completed AND status != "-"
GROUP BY file.link
```

It might be it created the “desired” result simply because null <= date(...(), @dawni .

Oh my gosh. Yes. Oops. Thanks for taking the time, @holroy

1 Like