In Twig (and Craft) we work with dates a lot. Here's how you compare them.
In Twig (and Craft) we work with dates a lot. Most of the time we’re probably just outputting a date from an entry or some other Craft element. However, we also need to compare them, too. This is how you do it.
When we get a date back from Craft to use in our Twig templates, this will usually come as a DateTime object. This can make comparing dates (like today’s date versus the date of an Entry) a little trickier because there’s more to a DateTime object than you might think.
Here I have the postDate
of an entry from Craft CMS and another DateTime field called lessonDate
. They’re both DateTime objects.
I’m comparing them and if they’re the same I output “same”.
{% if entry.postDate == entry.lessonDate %} same {% endif %}
But can we reliably compare them like this?
We can. Twig will inspect the objects’ properties and do the comparison for us. Pretty great, right?
Like an equivalency comparison in the first example, we can also do a greater-less-than comparison:
{% if entry.postDate > entry.lessonDate %} postDate is later/greater {% endif %}
But there’s an important catch: this type of comparison is fine as long as we know the full Date and Time are being compared and we are okay with that level of detail.
Why is that?
A DateTime object comparison is a full comparison of the object properties. Let’s dump the properties and values of an instance of an object to see (I’m using the excellent Dumper plugin to get nicely formatted output):
{{ dd(entry.postDate) }}
And the output we get is this:
DateTime {#836 ▼
+"date": "2019-03-15 14:18:00.000000"
+"timezone_type": 3
+"timezone": "America/Chicago"
}
Let’s create our own DateTime object and then compare it to the entry.postDate
.
{% set ryansDate = date("2019-03-15") %}
To create a DateTime object in Twig we use the date()
function and pass in a date string. I’m using the same exact year-month-day string as in the entry.postDate
DateTime object.
The contents of this object are (again using {{ dd(ryansDate) }}
:
DateTime {#1596 ▼
+"date": "2019-03-15 00:00:00.000000"
+"timezone_type": 3
+"timezone": "America/Chicago"
}
The only thing to point out here is that the timestamp is not the same as the other object. This means that any equivalency comparison between the two would not evaluate true.
{% if entry.postDate == ryansDate %} same {% endif %}
Nothing would show because it evaluates false. We could be more specific when creating the object by adding the same timestamps.
Or, even, better, just do the comparison without time.
The two objects from above have the same date but different times. Therefore, the comparison will fail. But what if we are looking to compare just the date and not the time?
We can do that using the date
filter in Twig. This filter converts a DateTime object to a string.
{{ entry.postDate | date }}
That outputs:
Mar 15, 2019
Now let’s use the date
filter in our comparison:
{% if entry.postDate | date == ryansDate | date %} same {% endif %}
And that will evaluate to true
and output “same”.
(By using the date
filter without a formatting argument, we get the default date output: short month, day number, 4 digit year. But we can use any valid format we want.)
In the date
filter we can filter to whatever part of the DateTime object we need. Let’s say we want to check if the two dates are in the same month. How would we do that?
{{entry.postDate | date('M') }}
This will output the 3 letter month name. Like Jul.
The comparison we’d do to see if both dates are in July would be like this:
{% if entry.postDate | date("M") == ryansDate | date("M") %} same month {% endif %}
Just like with the month, if want to compare the name of the day, we need to get the weekday from each date. To do that we’d need to convert the date to just the number of the day and then compare it to today, which we also convert to the number of the day.
{% if entry.postDate | date("l") == ryansDate | date("l") %} same day {% endif %}
A more practical example you might run into in your work is checking if the date of something is the week day as today.
The first thing we need to do is get today. We do that using the now
string in Twig. We can pass this string through the date
filter and get a string of today’s date.
{{ "now" | date }}
This is handy because now we can convert that string to a more usable date format that we can then compare to something we get from the (Craft) database.
We’ll do that using the a parameter on the date
filter to format the date to a string. In this case we just want to output the day of the week via the date
filter:
{{ entry.postDate | date("l") }}
And now we can do a comparison with that:
{% if entry.postDate | date("l") == "now" | date("l") %}
same day!
{% endif %}
Or using a ternary operator we could write it as:
{{ entry.postDate | date("l") == "now" | date('l') ? 'same day!' : 'different day' }}
An example of some code I use here on CraftQuest for the dashboard, I used the following:
{{ item.dateAdded | date("l") == "now" | date('l') ? 'Today' : 'on ' ~ item.dateAdded | date("l") }}
This checks if the day the item was added is the same today. If so, it’s prints out ‘Today’. If not, it prints out the name of the day.
This isn’t foolproof, however, because using the l
format on the date will just output the name of the day as the string. If the date is last Tuesday, it will show as “same day” even though it’s a week apart.
In my implementation this is okay because I’m limiting the outputted entries to only the last five days, so the days themselves will never repeat, therefore offering reliable comparisons.
But what if wanted to match beyond 5 days and still know whether it’s the same day or not?
We can do that using a different formatting option in the date filter. This time we’ll filter to the numerical day, month, and year and then compare that with the formatted “now” string.
{{ entry.postDate | date == "now" ? 'Today' : 'not today' }}
In this case we are not using any formatting parameters on the date filter because by default Twig will output the date to the string e.g. April 26, 2019, as we learned earlier.
So this code will also let us know if the day now is the same as the entry.postDate.
We could also use the Epoch time string as a way to filter the date.
To do that we’d pass a string “now” into the date
filter and then use the “U” string formatting to output Unix time (or Epoch time).
{{ "now" | date("U") }}
And this will output epoch time for right now (which will change every second).
This can be handy for comparing time but it’s very exact — down to the second. Almost too exact.
So that’s how we can compare dates in Twig. The main thing is to get both dates in the same format and then compare. If you need specificity, you can use Epoch time; if you need less specificity, you can convert the date to a string and compare them that way.
Also, take advantage of the now
string if you need to compare something to this second, minute, hour, day, month, or year.