Calculate difference in years

This is not a question rather than a tip for anyone else trying to do this very simple operation. I had a couple of places I wanted to show a difference in years. Both in relation to today but that is not necessary.

What you can use is a very small Hugo shortcode template. And instead of using separate shortcodes for each year calculation you can use a positional parameter.

So you call the shortcode in the markdown like this

He is {{% years-till-today 1972 %}} years old.

And in the shortcode file years-till-today.html:

{{ sub now.Year (.Get 0) }}

… and year.html

{{ now.Format "2006" }}

PS The calculation is a bit messy as it does not account for months of the year.

9 Likes

If you want to use Javascript instead of relying on Hugo to generate the difference in years and make it more “live” then you can use a different shortcode:

<span class="date">{{ (.Get 0) }}</span>

Then you need to call the javascript below any text that include the years you want to calculate. I have tried putting it in the footer but id didn’t work.

<script>
    // Get the current year
    var currentYear = new Date().getFullYear();

    // Get all elements with the "date" class
    var dateElements = document.getElementsByClassName("date");

    // Loop through each date element
    for (var i = 0; i < dateElements.length; i++) {
    // Replace the date with the number of years since it occurred
    dateElements[i].innerHTML = currentYear - parseInt(dateElements[i].innerHTML);
    }
</script>

The easiest way is to create another shortcode file, for example years-till-today-js.html and then add this

{{% years-till-today-js %}}

at the end of the md file. Again, if anyone has a better suggestion please feel free to add.
The Mainroad theme I am using does have the option os using custom.js but even though I edit it it does not appear on the deployed site.

PS: I’m not the sharpest of coders but I actually had some good help from the rather renowned AI tool Chat GPT.

timeago.js fuzzes and localizes your dates.

npm install timeago.js

assets/js/main.js [1]

import * as timeago from 'timeago.js';
import { de, en_US as en, fr } from 'timeago.js/lib/lang';

window.addEventListener('DOMContentLoaded', (event) => {
  const els = document.querySelectorAll('time.fuzzy');
  if (els.length) {
    timeago.register('de', de);
    timeago.register('en', en);
    timeago.register('fr', fr);
    const locale = (navigator.language) ? navigator.language.substring(0,2) : 'en';
    timeago.render(els, locale);
  }
});

layouts/_default/baseof.html

<head>
  ...
  {{ with resources.Get "js/main.js" | js.Build }}
    <script src="{{ .RelPermalink }}"></script>
  {{ end }}
  ...
</head>

Then do something like this in your templates:

<time class="fuzzy" datetime="{{ .Date.Format "2006-01-02T15:04:05-07:00" }}">
  {{ .Date | time.Format ":date_long" }}
</time>

  1. The length check is required to workaround this issue. ↩︎

5 Likes

A simpler solution

{{ sub now.Year 1972 }} <!-- replace 1972 with your own -->

PS The calculation is a bit messy as it does not account for months of the year.

I suppose it depends on how you want it to react on part years,
If you subtract Years isn’t 1/1/23 and 31/12/22 is going to give you 1 year ago.
It is last year, so maybe that is what you want but it isn’t really a 1 year ago, its only a day.

I think this works except (at least!) if one year is a leap year then it will count 22-12-12 and 28-12-11 as 6 full years.

{{ $date1 := time (.Get "date1") }}
{{ $date2 := time (.Get "date2") }}
{{ $dayofyearadjust := sub (math.Min (div $date2.YearDay $date1.YearDay) 1) 1 }}
{{ add (sub $date2.Year $date1.Year) $dayofyearadjust }}