Using time from YAML in `where`


I’m having some trouble with using dates from YAML in a template. I’m running into the issue of dates in YAML being strings while TOML has a datetime type.

From a list of events, I want to grab the one that is next up, i.e., the first after now. What I’d like to do is

{{ $next := index (where .Site.Data.calendar "date" ">=" now) 0 }}

but it returns an empty $next.

If the data is in TOML, the following works:

{{ $next := index (where .Site.Data.calendar.event "date" ">=" now) 0 }}

The YAML looks like

- date: 2022-01-14
  other-data: etc.
- date: 2022-01-15
  other-data: etc.

and TOML:

date = 2022-01-14T00:00:00
date = 2022-01-15T00:00:00

Formatting the YAML like the TOML doesn’t work, but YAML doesn’t have datetime types so I assume to problem is just fundamental in that respect.

How would I do "find the first element in calendar that is after now"? If I just wanted to filter, I could add an if after a range (which I actually do somewhere else on my site), but I would then need to somehow stop iterating after the first item is found. Is there a way to, in a where, apply a function (time.AsTime) to a field (date) before executing the criteria test? Something like

{{ $next := index (where .Site.Data.calendar (time.AsTime "date") ">=" now) 0 }}

I admit I’m not that familiar with Go templating or Go itself, for that matter. Would it be way to complicated to somehow write a custom function for this?

A previous (now-archived) question had the same problem, but no solution as far as I could tell.

(I know I could just switch to TOML but where’s the fun in that? :crazy_face: Besides, that feels like giving up.)

Thanks in advance.

I have also tried:

{{ $calendar := .Site.Data.calendar }}
{{ range $calendar }}
  {{ $.isodate := time.AsTime .isodate }}
{{ end }}
{{ $next := index (where $calendar "isodate" ">=" now) 0 }}

which didn’t work. But, as my knowledge of Go templating is limited to what I learnt through using hugo, I don’t know if this doesn’t work because it is impossible or because I’ve done something wrong. Are variables in templates even mutable?

Update 2
Repo of working site by using TOML now available on github at trespaul/anmari/ on the calendar branch; relevant code here.

You are correct.


Yes. Initialize ( := ) outside the block, and assign ( = ) within.

{{ $var := 0 }}
{{ if true }}
  {{ $var = 1 }}
{{ else }}
  {{ $var = 2 }}
{{ end }}

Related example from the documentation:

If the format of the datetime value within your data file is consistently YYYY-MM-DD, you can perform a string comparison instead of datetime comparison.

Obtain a map of the next event with:

{{ $nextEvent := index (sort (where site.Data.calendar "date" "gt" (now.Format "2006-01-02")) "date") 0 }}

Thank you so much! A string comparison was exactly the blind spot I needed an outside perspective to see. And thank you for the other info as well.

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