Recognise dataview results as date

What I’m trying to do

I want to use the result (data type is date) of a Dataview inline query as an argument in other Dataview calculations.

The file name is ‘Test’.

I have these properties in the file:
date10:: 1460-01-01
date11:: = [[Test]].date10

The query is:
= date([[Test]].date11) - dur(1 year)

I use the filename for reference because I want to use the query across different files.

The system tells me: “Dataview (for inline query ‘= date([[Test]].date11) - dur(1 year)’): No implementation found for ‘null - duration’”
Thus, I deduce the problem is that the data is not recognised as date.

Things I have tried

I’ve searched the documentation and this forum but couldn’t find anything. I’ve deactivated all my plugins, reset the computer, but no change.

I’ve verified that date11 is recognised as date, it shows that date10 is recognised as date but not date11:
date10a:: = date([[Test]].date10) → 01-01-1460
date11a:: = date([[Test]].date11) → -

I’ve tried the query based on date11a which refers to the result of date11a as a date but it gives the same answer as above.

I don’t understand why the fields date11 and date11a are not recognised as date data.

Part of the explanation for your strange results, is that when you do date11:: `= [[Test]].date11` the inline field doesn’t hold the result of that query, but it holds the actual query itself.

In many cases, you’ll never see this, since dataview can evaluate markdown & queries when it presents other query results. But when you try to do `= date(`= [[Test]].date`) - dur( 1 year)` it is getting confused and returns null since it doesn’t make sense to make a date out of that inline query.

A better test would be the following:

`= typeof( [[Test]].date10 )` vs `= typeof( [[Test]].date11 )` 

which should give you date vs string, since the latter is in fact the inline query string.


When I found out this was how dataview handled inline fields set to equal an inline query, I looked a round (a little while) before I decided to just repeat the query in any resulting table in other pages.

So that’s the gist of explaining why it can’t work like you intend for it, in its current variant. The question now becomes why do you really want to do this, and what type of queries do you want to store in the original file and reuse in another file?

1 Like

There is a function for dataviewjs called “dv.tryEvaluate()” which can execute the query inline and give you actual return object. So if you use dataview inline js rather than reguar dataview inline (add a $ sign), you can do this:

$= dv.tryEvaluate(dv.current().date11.slice(2).slice(0, -1).trim())

which will execute and return the data11 date object. You can then add in the duration stuff, but you’ll have to use dv date functions rather than dur(). I think this would work:

$= dv.tryEvaluate(dv.current().date11.slice(2).slice(0, -1).trim()).minus(dv.duration("1 year"))

You can combine slices to make it cleaner:
$= dv.tryEvaluate(dv.current().date11.slice(2, -1).trim())

and
$= dv.tryEvaluate(dv.current().date11.slice(2, -1).trim()).minus(dv.duration("1 year"))

That’s an interesting idea, and if you want to take that even one step further, I reckon you could use a similar approach for any inline field with a query and set the context to be that file? If so, you should theoretically be able to reuse those inline field query from with a query context as well, and not only from using dv.current()

Hmm… I might need to look into this concept another day, it could prove to be useful if it actually functions.

Oh I didn’t even notice he asked for a query in a different page. The quickest way I can think of is to just replace dv.current() with a dv search. Lol this is extremely verbose, but this works:

$= dv.tryEvaluate(dv.pages().where(p => p.file.name == "test")[0].date11.slice(2, -1).trim()).minus(dv.duration("1 year"))

Thanks so much for your help. This looks really promissing. However, I’m not used to dataview inline js, I’m trying to find my way, though. So far, I still get only errors. Where is my mistake:

With $= dv.tryEvaluate(dv.current().date11.slice(2).slice(0, -1).trim()) I get:
Dataview (for inline JS query ‘dv.tryEvaluate(dv.current().date11.slice(2).slice(0, -1).trim())’): Error: Failed to parse expression “= [[Test]].date10`”

With $= dv.tryEvaluate(dv.pages().where(p => p.file.name == "test")[0].date11.slice(2, -1).trim()).minus(dv.duration("1 year")) I get:
Dataview (for inline JS query ‘dv.tryEvaluate(dv.pages().where(p => p.file.name == “test”)[0].date11.slice(2, -1).trim()).minus(dv.duration(“1 year”))’): TypeError: Cannot read properties of undefined (reading ‘date11’)

For the first issue, did you change the date11 field at all? If so you should change it back to how you had it at the start, just- date11:: `= date(this.date10)`
The method I gave means you can still use normal dataview inline for everything and only dataview inline js when you need to interpret another dataview line. If you didn’t change the date11 field, then try doing `$= dv.current().date11.slice(2, -1).trim()` and seeing what it spits out.

For the second one, you need to replace “test” with the name of the file, which seems to be “Test” for you.

Do note that the latest post are to be considered a hack, and might very well be broken in a future update of Dataview. So I’m going to try to ask again, why do you want to do this in the first place? What’s the use case for you to repeat the “inline query field thingy” in another file?

There might be better approaches to achieve whatever you’re attempting to do, but for us to suggest something like that, we do need to know what you’re actually trying to do.

Thank you! For the first issue: I hadn’t changed field date11. However, $= dv.current().date11.slice(2, -1).trim() gives me the query, not the value: = [Test].date10, or if I use the ‘this’-version: = date(this.date10)

For the second issue: Changing test to Test doesn’t change anything. Result is still: Dataview (for inline JS query ‘dv.tryEvaluate(dv.pages().where(p => p.file.name == “Test”)[0].date11.slice(2, -1).trim()).minus(dv.duration(“1 year”))’): Error: Failed to parse expression “= [[Test]].date10`”

Thanks for asking again. I’m working with historical data concerning historical persons and historical manuscripts. The dates are often unclear and must be deduced from circumstances, for instance: I can narrow down the span of the production date of a certain manuscript to lay between the span of the production date of another manuscript and the death of the author. I want to make my deductions transparent and to keep them flexible in case any of the dates change due to new findings (which happens often). Thus if I for instance learn a precise production date of the second manuscript, I want this to automatically change the production date span of the first manuscript.

I have several notes per person and also several notes per manuscript. Each note gives exactely one action (like birth, death, creation, annotation …) The field names in all notes are identical so that I can refer to them with one and the same query. Therefore I need to refer my inline queries to dates of various notes.

If I understand you correctly each note has exactly one date, related to a few (but known) actions, so you could have some notes related to the Codex Leicester and they refer to Leonardo da Vinci, and you’d get notes like:

  • "Leonardo da Vinci - birth " - some date, action = “birth”
  • “Codex Leicester - production” - some date, action = “production”
  • “Leonardo da Vinci - married?” - some date, action = “married”

And you’ll want to do a query determining the exact production dates of the Codes when you find out that it was written by Leonard, but before he was married? (This is of course a very constructed use case)


My question then becomes, wouldn’t it suffice in each note to have just that one date field (which would allow for the use of file.day in other queries), and rather have a action field to determine the actual action?

That would allow for easier (and legal) queries against the file.day to compare or look for connections, and you could have another column/clause related to action when you need to do that?

Going down a road “misusing” inline field queries, I believe is just bound to cause you misery, and I think better approaches can be found like possibly the one I just suggested.

I understand and of course share your concerns. Your da Vinci example shows what I mean. Yet, my case is more complex. I have 4 dates per note to represent the time span of an action process and its uncertainties:

To represent the time span when I think that an action may have started (i.e. the production date started at the earliest 20 years after Leonardo’s birth, at the latest before he finished a certain other manuscript):
date-start-begin::
date-start-end::

To represent the time span when I think that an action may have ended (The production process (which can take several years) may have ended at the earliest after he left Rome and at the latest when he died):
date-end-begin::
date-end-end::

Thus, I don’t think that file.day could solve my problem.

Oh, and I do have an action field in every note to determine which action is refered to.

Yeah I agree with holroy. While there are legitimate use cases of chaining queries, I found it’s really only useful when you’re forced into having like 3+ layers of notes depending on each other, or having layers of calculations.

I’ll still give the chaining solution for the sake of completeness, or for anyone in the future:
The goal of dv.current().date11.slice(2, -1).trim() is to slice off the backticks and ‘=’ part of `= [[Test]].date10` so you’re just left with the instruction “[[Test]].date10”, which you can then evaluate with tryEvaluate.

The numbers in slice is saying how many characters to remove (2 from front, 1 from back), so that when you run `$= dv.current().date11.slice(x, y).trim()` you should get just “[[Test]].date10”.

For some reason you have extra characters (could be spaces?), but it looks like slice(3, -1) or slice(3, -2) would work based on what you sent, and if not you can adjust the slice values until you get just the instruction. Once you find slice numbers that only give the instruction, you can use those in the commands and that should work.

Though I’m now very curious why removing the first 2 characters and last character didn’t work, as it works for me with the line date11:: `= [[test]].date10`. I’d be interested in seeing what this gives you: `$= dv.current().date11.slice(1)`

Is it the date-*-end you’ve defined using the inline queries? And are they really just a duration related to the date-*-start part? In that case you should actually store them as just that, durations.

I’m thinking something along the lines of:

start:: 2022-01-01
start-uncertainty:: 1 year

end:: 2024-02-28
end-uncertainty:: 1 day

Then you could use that within the note to show the “other” date using stuff like:

`= this.start + this.start-uncertainty `

Or in another query as start + start-uncertainty, which would give the other date related to you uncertainty. Such a scheme would be easier and a whole lot safer to use.

Thanks so much for this explanation. Now, I understand what you’re after and yes, it works fine now. This was only a misunderstanding from my side, sorry for being a nuissance.

No, it’s not the date-*-end I defined using the inline queries, at least not necessarily. It depends on the case, it’s sometimes all four of the dates which I define using inline queries which relate to different notes. And I almost never have absolute process durations.

I.e. I know that the production process of manuscript B started some time after the finalisation of manuscript A but before the author moved to town X. And I know that the process ended at the earliest before yet another move to town Z and at the latest when the author died in that town.

Thus,
the start-begin date of the production of manuscript B is after the end-end date of the production of manuscript A. → referring to note ‘production MS B’
The start-end date of manuscript B is before the move of its author to town X. → referring to note ‘Person1 moveX’
The end-begin date of manuscript B is after the move to town Z. → referring to note ‘Person1 moveZ’
The end-end date is before his death. → referring to note ‘Person1 death’

It could also be that still more manuscripts and more persons are involved in my reasoning.

I’m sure there is a better way than trying to use inline fields holding queries to solve your use case, but without seeing/understanding more of your use case, which currently at best is unclear it’s hard to provide any good advice.

My best advice is two-folded:

  1. Consider using dataviewjs scripts on a given page, to do the query and store the actual date into a local property using app.fileManager.processFrontMatter(). This way you can do other queries related to this note on a field with a proper date

  2. Show some full scenario examples, with all of the data for at least two different cases, with corresponding queries as they stand where your explain what works and what don’t work. I for one, don’t have enough information to give any more advice than that already provided on the limited information available.

Oh yeah @holroy processFrontMatter is a really cool option. @Gerda you’d have to replace all the inline queries that you’d want to reference into dataviewjs blocks, but it would cleanly add the fields to the yaml in the top of the page for use in other pages. Here is one way to do that implementation for your original scenario, the output is identical to the inline and you just have to change the propertyName and propertyValue variables as you see fit.

date10:: 1460-01-01

```dataviewjs
const propertyName = "date11";
const propertyValue = dv.date( dv.pages().where(p => p.file.name == "Test")[0].date10 );

//Implementation:
const thisTfile = app.vault.getAbstractFileByPath(dv.current().file.path);
app.fileManager.processFrontMatter(thisTfile, (frontmatter) => frontmatter[propertyName] = propertyValue);
dv.span(propertyName + ": " + dv.date(dv.current()[propertyName]).toISODate() ); // or   dv.span(propertyName + ": " + dv.current()[propertyName]);  for nondate results
```
```dataviewjs
const propertyName = "date11a";
const propertyValue = (dv.date(dv.pages().where(p => p.file.name == "Test")[0].date10).minus(dv.duration("1 year")));

//Implementation:
const thisTfile = app.vault.getAbstractFileByPath(dv.current().file.path);
app.fileManager.processFrontMatter(thisTfile, (frontmatter) => frontmatter[propertyName] = propertyValue);
dv.span(propertyName + ": " + dv.date(dv.current()[propertyName]).toISODate()); // or   dv.span(propertyName + ": " + dv.current()[propertyName]);  for nondate results
```

So it’s up to you what method to use. One advantage of the above is that because you’re generating the text to show, you can add to the output the page this date info is coming from. So you can get output like this:
“date_end_begin::: 1480-09-01 | from Leonardo Moves to Rome”
That code would be:

```dataviewjs
const propertyName = "date_end_begin";
const retrieveFromFile = dv.pages().where(p => p.file.name == "Leonardo Moves to Rome")[0];  // or  dv.current() if you're retrieving from this file
const propertyValue = dv.date(retrieveFromFile.date10);

//Implementation:
const thisTfile = app.vault.getAbstractFileByPath(dv.current().file.path);
app.fileManager.processFrontMatter(thisTfile, (frontmatter) => frontmatter[propertyName] = propertyValue);

//Output
dv.span(propertyName + ": " + dv.date(dv.current()[propertyName]).toISODate() + " | from " + retrieveFromFile.file.name);
``` 

And don’t worry you’re not being a nuisance. Your system for handling the overlapping ambiguity of dates is really smart, I’m gonna steal some of these ideas :slight_smile: