Dates in Twig #
Date objects work similarly both in PHP and Twig - before outputting them to template, you need to transform them into human-redeable format. In PHP, this is done by date() function. In Twig, you do that using date() filter:
{{entry.postDate|date('m/d/Y')}}
You can find about date formatting syntax on this w3schools page.
In Craft CMS you can also use date()
filter to output date in the format used by current locale or set locale manually, as described in Craft documentation. This is important because different countries use different date formats - as shown in the picture below.
Default date format macro #
Dates tend to be showed in various parts of the website - for example, for blog websites it can be articles list and single article page. In order to make your templates easy to maintain, you should keep date format settings and date related code in one place - within Twig macro.
In this macro, date will be placed in time
HTML element, in order to keep your markup semantic. time
element will also have datetime
attribute which will make date machine-readable. You can learn more about time
element in this article on CSS tricks.
Macro code #
Default date format macro accepts two parameters:
date
- can be date object (likeentry.postDate
) or string representing date - likenow
or01-02-2018
.additionalAttributes
- optional parameter for adding HTML attributes. If a single string is passed, it will add class totime
element. If an object containing "attribute-value" pairs is passed, you can set what specific attributestime
element should have.
{%- macro defaultDateFormat(date, additionalAttributes) -%}
{% if date is defined %}
{# settings #}
{% set format = 'medium' %}
{# logic #}
{% set attributes = {
text: date|date(format),
datetime: date|date('yy-m-d')
} %}
{% if additionalAttributes is defined and additionalAttributes is not iterable %}
{% set attributes = attributes|merge({class: additionalAttributes}) %}
{% elseif additionalAttributes is iterable %}
{% set attributes = attributes|merge(additionalAttributes) %}
{% endif %}
{{tag('time',attributes)}}
{% endif %}
{%- endmacro -%}
Feel free to modify formatting settings at the beginning of macro contained in format
variable. You can also add logic that changes formatting depending on locale. Just don't change datetime
attribute formatting - it is set to a machine-readable format.
Technical details #
This macro uses tag() function added in Craft 3.3 and thus won't work in earlier versions. tag()
function works similarly to attr() function - it generates HTML element with attributes created from Twig object passed to function.
In this case, we first create an object containing text
and datetime
. text
is not really HTML attribute, but what tag()
function will use as content of time
tag. Then, we optionally merge this object with any additional attributes that were passed to macro as the second parameter. Finally, we pass the object containing all attributes to tag()
function.
So, for such parameters:
{{_self.defaultDateFormat('08-09-2019', {
some-attribute: 'xxxxxx',
}) }}
We will get this result:
<time some-attribute="xxxxxx" datetime="2019-09-08">Sep 8, 2019</time>
Time ago macro #
Sometimes showing detailed date is not desirable. Users might want to know just how much time has passed from a specific date - and giving them detailed date might require them to perform calculations in their heads.
That's where time ago macro comes in. It works pretty similar to default date format macro - but instead of showing formatted date, it shows time that passed from that date - in a human-readable format. Detailed date is added to title
attribute of time
element - so if someone wants to know it, he or she can just hover the mouse over time
element.
Macro code #
Time ago macro accepts two parameters:
date
- can be date object (likeentry.postDate
) or string representing date - likenow
or01-02-2018
.additionalAttributes
- optional parameter for adding HTML attributes. If a single string is passed, it will add class totime
element. If an object containing "attribute-value" pairs is passed, you can set what specific attributestime
element should have.
{%- macro timeAgo(date, additionalAttributes) -%}
{% if date is defined %}
{# settings #}
{% set format = 'medium' %}
{% set locale = currentSite.language %}
{# logic #}
{% set formatter = create({ class: 'craft\\i18n\\Formatter', locale: locale }) %}
{% set attributes = {
text: formatter.asRelativeTime(date),
datetime: date|date('yy-m-d'),
title: date|date(format),
} %}
{% if additionalAttributes is defined and additionalAttributes is not iterable %}
{% set attributes = attributes|merge({class: additionalAttributes}) %}
{% elseif additionalAttributes is iterable %}
{% set attributes = attributes|merge(additionalAttributes) %}
{% endif %}
{{tag('time',attributes)}}
{% endif %}
{%- endmacro -%}
Elapsed time is returned in the locale of the current site. If you want to change it, just change locale
variable at the beginning of macro to specific locale code.
Word of caution - don't use this macro along with template caching - the elapsed time is calculated on each page load, so if template is cached, it will show outdated value.
Technical details #
Macro works almost the same as the default date macro. The only significant difference is the usage of create()
function.
To use asRelativeTime
function that outputs elapsed time in human-readable format, we need to instantiate craft\i18n\Formatter object - and we use create()
for that. You can read more about it on nystudio blog.