Post and Author Age Without Plugins

How to display post and author age in Jekyll via JavaScript.

This article was tagged with: Jekyll

There are 1523 words in this article, and it will probably take you less than 8 minutes to read it.

This article was published 2023-11-13 00:00:00 -0500, which makes this post and me old when I published it.


It started out as simply wanting to display the date the post was published, which is a very simple task in Jekyll. This led me to think about showing the post age because I think it would be interesting to me to see how old one of my articles is without requiring the reader to do any kind of math. Then I got to thinking about contextualizing the time in my life where I was writing these articles, and how it would be pretty easy to calculate my age alongside the post age. Displaying these two ages together is something unique to my blog (at least I think so since I haven’t seen it anywhere else) and something that is really more done for me than for the reader. I think that it is personally interesting to be able to see what time in my life I was in when I was writing these articles.

Doing it in Liquid

At first I did it in Liquid, which was a doozy because of how verbose you have to be to do anything remotely complex. I ended up settling on this solution, which maybe isn’t the prettiest, but it gets the job done:

{% assign secondsInHour = 60 | times: 60 %}
{% assign secondsInDay = secondsInHour | times: 24 %}
{% assign secondsInMonth = secondsInDay | times: 30 %}
{% assign secondsInYear = secondsInMonth | times: 12 %}

{% assign secondsSincePost = today | minus: post_date %}

{% assign yearsSincePost = secondsSincePost | divided_by: secondsInYear %}
{{ yearsSincePost }} years,

{% assign leftoverSecondsFromYears = secondsSincePost | modulo: secondsInYear %}
{% assign monthsSincePost = leftoverSecondsFromYears | divided_by: secondsInMonth %}
{{ monthsSincePost }} months,
{% assign secondsLeftoverFromMonths = leftoverSecondsFromYears | modulo: secondsInMonth %}
{% assign daysSincePost = secondsLeftoverFromMonths | divided_by: secondsInDay %}
{{ daysSincePost }} days, and

{% assign secondsLeftoverFromHours = secondsSincePost | modulo: secondsInDay %}
{% assign hoursSincePost = secondsLeftoverFromHours | divided_by: secondsInHour %}
{{ hoursSincePost }} hours

However this solution was short-lived because I realized that I shouldn’t be doing this in Liquid because Jekyll renders static files meaning that it would display from the time of the publish of the post to the last render, which is against what I wanted in the first place.

Doing it in JavaScript

You can see how the code placed is in relation to rest of my article template here.

<p style="margin-bottom: .5em">
    This article was published <span id="postedOn">{{}}</span>, 
    which makes this post <span id="postAge"></span> 
    and me <span id="meAge"></span> old when I published it.
// date constants
const postDate = new Date(`{{ | date: "%m/%d/%Y" }}`);
const startedAtDate = new Date("{{page.started_at}}");
const birthDate = new Date("July 9, 2000 17:00:00");
const today = new Date();

const options = {
    weekday: "long",
    year: "numeric",
    month: "long",
    day: "numeric"

function calcDate(d1, d2) {
    let dy = d1.getYear()  - d2.getYear();
    let dm = d1.getMonth() - d2.getMonth();
    let dd = d1.getDate()  - d2.getDate();

    if (dd < 0) { dm -= 1; dd += 30; }
    if (dm < 0) { dy -= 1; dm += 12; }

    const yearUnit = dy == 1 ? "year" : "years";
    const monthUnit = dm == 1 ? "month" : "months";
    const dayUnit = dd == 1 ? "day" : "days";

    if (dy == 0)
        if (dm == 0)
            return `${dd} ${dayUnit}`;
        return `${dm} ${monthUnit} and ${dd} ${dayUnit}`;

    return `${dy} ${yearUnit}, ${dm} ${monthUnit}, and ${dd} ${dayUnit}`;

let postedOn;
if (today.setHours(0, 0, 0, 0) == postDate.setHours(0, 0, 0, 0))
    postedOn = "today";
    document.getElementById("postAge").innerText = "brand new";
    postedOn = `on ${postDate.toLocaleDateString("en-US", options)}`;
    document.getElementById("postAge").innerText = calcDate(today, postDate) + " old";

if (!isNaN(startedAtDate))
    document.getElementById("writingTimeP").style.display = "";
    document.getElementById("writingTime").innerText = calcDate(postDate, startedAtDate);

document.getElementById("meAge").innerText = calcDate(postDate, birthDate);
document.getElementById("postedOn").innerText = postedOn;

One issue I ran into during my implementation of this solution was that the Jekyll date with no filter was being output with timezone which Safari was failing to parse, while Chrome was fine. I tested on Brave (Chromium) so I didn’t notice that Safari parses dates differently. I got around this by doing | date: "%m/%d/%Y" so that it would only use the relevant Jekyll date information to create the Date object in JavaScript. This wasn’t a difficult fix at all, I was just so confused what was going on while I was debugging.

Potential Improvements

One potential improvement that I thought about was having the post age increase in real time. I would have done this by creating a JavaScript timer to increase the post age and re-render the post age text. It wouldn’t be CPU intensive at all so it wouldn’t affect page performance and I think it would be a cool statement animation. I ultimately decided against this because Jekyll has article post dates, but not post time. I could define something in the frontmatter, but I would have to make up times for publishing because that wasn’t metadata that I preserved.

Other Jekyll Articles

Search with SimpleJekyllSearch

My modifications to Jake Lee's configuration of SimpleJekyllSearch to fit my Digital Garden.

Creating a Flexible Permalinking System in Jekyll

How to create and maintain a flexible permalinking system in Jekyll for your posts.

Using jekyll-feed + XSLT with GitHub Pages

A guide on how to set up and use the jekyll-feed plugin on GitHub Pages to create a stylized feed.xml for RSS feeds.

Word Count Statistics Without Plugins

Word Count Statistics Without Plugins

Numeric Value Humanization Without Plugins

Numeric Value Humanization Without Plugins