Les dates avec hugo

Mis à jour à la fin du billet. Une deuxième fois.

Ces derniers jours, je me suis un peu cassé la tête avec la manière dont hugo conçoit et traite les dates. Ce que je cherchais à réaliser ne me semblait pourtant pas si exotique. Lorsque l’on crée un nouveau contenu, par exemple un nouveau billet de blog, à l’aide de la commande hugo new (et en utilisant l’archetype par défaut), hugo ajoute dans les métadonnées (le FrontMatter) une valeur au champ date. Ce qui donne pour le fichier du texte que je rédige à l’instant : date: 2019-08-25T13:11:00+02:00.

Dans le template qui permet d’afficher la date du billet de blog une fois le site généré, on peut trouver du HTML simplissime :

<li>Publié le&#x202F;: {{ .date.Format "2006-01-02" }}</li>

Jusqu’ici, tout va bien. Pourtant, le plus souvent cette date ne correspond pas à la date effective de publication du billet, parce qu’entre le moment où je crée le fichier et le moment où il est suffisamment prêt pour être publié, il peut se passer plusieurs jours. Ça tombe bien, hugo propose une autre variable à ajouter, manuellement, dans les métadonnées, publishdate. Enfin, il peut également arriver qu’après la publication, il soit nécessaire de modifier un billet. Là aussi, il existe une variable, lastmod. Celle-ci peut-être ajoutée à la main ou renseignée par la date du dernier commit de modification du fichier, si enableGitInfo est activé dans le fichier de configuration du site.

Tout va bien dans le meilleur des mondes ? Presque. Assez logiquement, je trouve, je voulais afficher d’abord une date de publication, par exemple date ou publishdate si cette dernière date existe, et, le cas échéant, la date de la dernière modification. Ce faisant, j’ai été confronté à deux difficultés. La première était que toutes mes méthodes de tests logiques (si publishdate existe, alors affiche cette date, sinon affiche date, par exemple), provoquaient des erreurs lors de la génération du site. Pour avancer quand même, chaotiquement comme c’est mon habitude, j’ai fait abstraction des tests et tenter d’afficher toutes les dates.

D’abord, j’ai été surpris de constater que si l’une d’elle n’existe pas, elle n’est simplement pas affichée. Il y a là un mécanisme qui m’échappe, mais pourquoi pas. L’autre point déroutant, est que les valeurs des dates affichées ne correspondaient pas à ce que j’avais imaginé. Souvent, date et publishdate étaient identiques, parfois lastmod également, parfois lastmod avait bien la valeur du dernier commit correspondant à la dernière modification du billet concerné~~, mais pas lorsqu’il s’agissait du premier commit~~.

J’ai essayé de nombreuses choses, tenté de comprendre la documentation de hugo, fouillé dans les forums… de m’arracher mes cheveux, de jurer et d’insulter le Web, en vain. Avant de tomber sur une discussion sur le forum de hugo dans laquelle était signalée la section suivante de la documentation : Configure dates. Je l’ai lue attentivement et j’ai fini par comprendre ce qui se passait, à défaut de tout à fait comprendre la logique à l’œuvre. Pour obtenir un comportement qui correspond à ce que je voudrais, il faut que dans le fichier de configuration de mon site (config.toml), je redéfinisse à ma guise la manière dont les variables de dates sont renseignées.

[frontmatter]
date = ["date", "publishDate"]
lastmod = [":git", "lastmod"]

Avec cette méthode, j’évite que le champ date puisse récupérer la valeur de lastmod et que celui-ci puisse obtenir la valeur de date ou publishdate. Du coup, je peux les distinguer, pour avoir une date de publication et/ou une date de dernière mise à jour. Si la date de publication est différente de la date de création du fichier, je dois manuellement, soit modifier la valeur de date dans le FrontMatter, soit y ajouter la variable publishdate. lastmod par contre, peut-être inférée de l’historique git, pour autant que enableGitInfo soit bien à true dans la configuration.

Au niveau des template, ça peut donner ceci :

<li>Publié le&#x202F;: {{ dateFormat "2006-01-02" (default .Date (.PublishDate)) }}</li>
{{ if isset .Params "lastmod" }}
  <li>Dernière mise à jour&#x202F;: {{ .Lastmod.Format "2006-01-02" }}</li>
{{ end }}

Il n’est pas du tout invraisemblable que cette solution puisse être améliorée. Ce que je retiens de cette aventure, c’est que hugo est décidément très puissant, le résultat d’une réflexion plutôt poussée et que j’ai encore beaucoup de travail avant d’arriver à un niveau suffisant de compréhension de son fonctionnement.

Mise à jour

Visiblement la logique ci-dessus est incomplète (et risque bien de l’être après cette mise à jour, mais c’est ainsi). Sur ce même billet, lors de la publication, enfin un peu après, j’ai constaté que la date de modification était plus récente que la date de publication, ce qui est logique, parce que la date du commit est plus ancienne que publishdate, contrairement à ce que je prétends plus haut.

Première publication, avec la mauvaise date

Première publication, avec la mauvaise date

Aussi, j’ai rajouté un test dans le template :

{{ if (and (isset .Params "lastmod") (gt .Lastmod .PublishDate)) }}

D’abord, on vérifie que la variable lastmod est bien renseignée, puis que sa date est plus récente que publishdate, avant de l’afficher. Voilà, j’espère que désormais je vais obtenir le comportement que je souhaite.

Une mise à jour supplémentaire

« Voilà, j’espère que désormais je vais obtenir le comportement que je souhaite. »

Hé bien non. Souvent, la lastmod est affichée, alors qu’elle est du même jour que la publishdate, et en fait, c’est logique. Il se trouve que je renseigne la publishdate manuellement, parce que je veux qu’elle soit différente de la date de création du fichier (le résultat de la commande hugo new) et qu’elle ne soit pas modifiée par les dates des commits qui viendraient après, puisque ces modifications sont des mises à jour, pas un changement de la date de publication. Or, je ne m’amuse pas à créer une date de publication à la seconde près, une date du type 2020-05-22 me suffit.

Par contre, pour la lastmod, la date vient de git, et là c’est précis, à la seconde près. Ce qui a pour conséquence qu’une comparaison d’une date de publication et et la date du dernier commit qui tombent le même jour, donnera toujours la lastmod comme plus grande que la publishdate. Mon gabarit va dont l’afficher.

La solution, évidente pour des gens dont c’est le métier, j’imagine, est de traiter ces dates pour pouvoir les comparer de manière sensée :

{{ $LastmodFormatted := dateFormat "2006-01-02" (.Lastmod) }}
{{ $PublishdateFormatted := dateFormat "2006-01-02" (.PublishDate) }}

On compare ces dates formatées et on affiche la dernière modification si elle est plus récente que le jour de publication :

{{ if (and (isset .Params "lastmod") (gt $LastmodFormatted $PublishdateFormatted)) }}
  <li>Dernière mise à jour&#x202F;: {{ .Lastmod.Format "2006-01-02" }}</li>
{{ end }}

Et si on fait des mises à jour le même jour, ça ne sera pas affiché, mais peut-être bien que c’est sensé, au fond.