The Problems
- You want to show the last modified date of a post (or item in any collection) without having to remember to edit it manually every time.
- You want to format a date nicely.
Solution Summary
Use "Last Modified" or "git Last Modified" as your date
in your frontmatter.
date: Last Modified
Use toLocaleString
to format your date
<!-- In a page -->
{{ page.date.toLocaleString()}}
// Or custom filter
eleventyConfig.addFilter("postDate", (dateObj) => {
return dateObj.toLocaleString(undefined, {
year: "numeric",
month: "long",
day: "numeric",
});
});
The Explanation
Use last modified date
The simplest way to show the last modified date of a post (or item in any collection) without having to remember to edit it manually every time is by setting "Last Modified" as your date
in the frontmatter of the post.
Note: See 11ty dates docs for other date options like
git Last Modified
. WhereasLast Modified
"automatically resolves to the file’s last modified date",git Last Modified
"automatically resolves to the file’s latest git commit." This is a bit more resource intensive though, so you might want to use aposts.11tydata.js
solution. I think the main difference isLast Modified
might count a file as modified if its layout was modified. Not 100% sure about that though. Generally though, thegit
one seems a bit more accurate.
Update frontmatter
In your 11ty collection item, update the date
in your frontmatter. For example, the frontmatter of this post (posts/how-to-handle-dates-in-11ty.md) would be:
---
layout: layouts/post.njk
tags: post
title: How to handle dates in 11ty
date: Last Modified
draft: true
---
## A heading
The content of your post goes here...
I use YAML syntax. You can use other formats too.
Use in pages
You can then use the date in pages or layouts.
For example, in my posts/index.njk
page I have a list of posts:
{%- for post in collections.post -%}
<li>
<a href="{{ post.url }}">
<h2>{{ post.data.title }}</h2>
<p>Last updated: {{ post.date }}</p>
</a>
</li>
{%- endfor -%}
Note that for looping through a collection list we use
post.data
.
and I show the date in my _includes/post.njk
Post page layout:
<article>
<h1>{{title}}</h1>
<p>Last updated: {{page.date}}</p>
<div>{{ content | safe }}</div>
</article>
Note that for a template layout we use
page.date
instead of justdate
. See 11ty docs
Format date
This shows up as Thu Sep 19 2024 08:38:16 GMT-0500 (Central Daylight Time)
. You might want a shorter date or to format it differently.
In our _includes/post.njk
Post page layout, where we're using page.date
, we can call Javascript methods on the output like {{page.date.toLocaleString()}}
. This only works in Nunjucks though, not LiquidSee Docs. "You could add your own toUTCString
filter in Liquid to perform the same task."
In _includes/post.njk
:
<article>
<h1>{{title}}</h1>
<p>Last updated: {{page.date.toLocaleString()}}</p>
<div>{{ content | safe }}</div>
</article>
If we use toLocaleString()
our date Thu Sep 19 2024 08:38:16 GMT-0500 (Central Daylight Time)
will become 9/19/2024, 9:40:51 AM
.
You can pass options to toLocaleString() to change how you want it formatted - like if you want it to show the time or not.
Example toLocaleString formatting
toLocaleString
takes two arguments, locales
and options
, like toLocaleString(locales, options)
;
locales
is a string. For the locales we can either define one like "en-US"
or "ko-KR"
and it will render the dates how they should look in those places (the US and Korea, respectively).
If we just want it to render based on where the user is located, we pass in undefined
so it will grab the user's default language for their locale.
options
is an object. If we want our date formatted like September 19, 2024
, we'd pass in the options
like this:
const options = {
year: "numeric",
month: "long",
day: "numeric",
};
const locales = undefined;
const date = new Date(); // gets today's date by default
date.toLocaleString(locales, options);
Read the docs to see all your options.
How we'd use this in _includes/post.njk
:
<p>
Last updated: {{page.date.toLocaleString( undefined, { year: 'numeric', month:
'long', day: 'numeric' })}}
</p>
How we'd use this in posts/index.njk
:
{%- for post in collections.post -%}
<li>
<a href="{{ post.url }}">
<h2>{{ post.data.title }}</h2>
<p>
Last updated: {{post.date.toLocaleString( undefined, { year: 'numeric',
month: 'long', day: 'numeric' })}}
</p>
</a>
</li>
{%- endfor -%}
Make custom filter to use same formatting options across pages
This works in both places, but since we're using the same toLocaleString( undefined, { year: 'numeric',month: 'long', day: 'numeric' })
options in multiple places, it'd probably make more sense to make our own date filter.
In our .eleventy.js
at the root of our 11ty project, we're going to use the addFilter
function, like this:
module.exports = function (eleventyConfig) {
// put your other configurations and functions alongside this one inside of `module.exports`
// there can only be one `module.exports` inside of `.eleventy.js`
eleventyConfig.addFilter("postDate", (dateObj) => {
// Can use toLocaleString the same way we were before
return dateObj.toLocaleString(undefined, {
year: "numeric",
month: "long",
day: "numeric",
});
});
};
Then use the new filter we've made in our pages.
How we'd use this in _includes/post.njk
:
<p>Last updated: {{page.date | postDate}}</p>
How we'd use this in posts/index.njk
:
{%- for post in collections.post -%}
<li>
<a href="{{ post.url }}">
<h2>{{ post.data.title }}</h2>
<p>Last updated: {{post.date | postDate}}</p>
</a>
</li>
{%- endfor -%}