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.

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. ↩︎

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 }}