You are here

Print formatted date with correct timezone from datetime or daterange field in node and Views templates - Drupal 8

I've been working on a site with events, and tearing my hair out over how to print formatted dates with the correct timezone value in Twig templates, specifically node.html.twig and views-view-fields.html.twig.

The issue was first, getting the formatted date to display in the template; and secondly, when I managed to get it displaying, it was not in the correct timezone; it was off by several hours. The accepted answer to this StackExchange question was the key to cracking the problem.

Basically, Drupal internally stores dates in UTC format. When the date is displayed, it gets converted to the user-chosen or site timezone, depending on the site settings.

If you print the raw value of the field in a Twig template, you get the UTC time. What you need is the DrupalDateTime object, the correctly timezone-formatted value of the field.

Daterange field values

For a daterange field (which collects a start and end date), you can get those converted values separately like so (assuming your field's machine name is event_date):

In node.html.twig:

node.field_event_date.start_date
node.field_event_date.end_date

(NOT node.field_event_date.value or node.field_event_date.end_value, which will give you the unconverted UTC values).

In views-view-fields.html.twig:

row._entity.field_event_date.start_date
row._entity.field_event_date.end_date

(Not row._entity.field_event_date.value, which is the UTC date, or fields.field_event_date.content, which I couldn't get converted to a formattable date value, no matter how I tried).

Datetime field value

For a datetime field, which does not collect an end date, the value is date: node.field_event_date.date (note: not content.field_event_date.date) or row._entity.field_event_date.date.

I haven't had to use these values in other templates, but you should be able to use these examples to figure out what they should be.

Examples of usage

Node.html.twig

In the site I'm working on, I want the date to display differently on the event nodes based on whether it's a single-day or multi-day event. If it's single-day, it will display like this:

May 8, 2020 from 9:10 am to 11:10 am

Multi-day: May 21, 2019 9:00 am to May 28, 2019 5:00 pm

How to do this? First, we set up a couple of variables in the node template. We want variables for the start day and end day, formatted to a numerical string so they can be compared, excluding the time, because we only need to see if the day is different (the end time will always be different even if it's a single-day event).

Here are our variables:

{% set start_day = node.field_event_date.start_date|date(format='Ynj') %}
{% set end_day = node.field_event_date.end_date|date(format='Ynj') %}

We're taking those converted start and end date values and formatting them as a string with the 4-digit year, the single-digit month number, then the single-digit number of the day of the month (you can find all the possible values in the PHP date manual).

This creates a string like: "2019521". We can then use those values for comparison. If the end day is greater than the start day, we print the date one way; if not, it's a single-day event and we print it another way:

{% if end_day > start_day %}
    {{ node.field_event_date.start_date|date(format='F j, Y g:i a') }}
    {{ 'to'|t }}
    {{ node.field_event_date.end_date|date(format='F j, Y g:i a') }}
{% else %}
    {{ node.field_event_date.start_date|date(format='F j, Y') }}
    {{ 'from'|t }}
    {{ node.field_event_date.start_date|date(format='g:i a') }}
    {{ 'to'|t }}
    {{ node.field_event_date.end_date|date(format='g:i a') }}
{% endif %}

This results in "May 8, 2020 from 9:10 am to 11:10 am" for a single day event or "May 21, 2019 9:00 am to May 28, 2019 5:00 pm" for multi-day.

Note that |date is a Twig filter. Instead of directly passing a date format to that filter, you can give it the value 'U' which converts it to a Unix timestamp, then add the |format_date filter and pass it the machine name of a Drupal date format, e.g.:

{{ node.field_event_date.start_date|date('U')|format_date('long_date') }}

Views-view-fields.html.twig

Let's say we want to create a Views listing of events with a nicely-formatted calendar date block. This is how I achieved it in views-view-fields--events--page.html.twig:

<div class="cal--thumb">
    <div class="cal--month">
      {{ row._entity.field_event_date.start_date|date(format='F') }}
    </div>
    <div class="cal--day">
      {{ row._entity.field_event_date.start_date|date(format='j') }}
    </div>
    <div class="cal--year">
      {{ row._entity.field_event_date.start_date|date(format='Y') }}
    </div>
</div>

This results in something like this (with CSS styling applied, of course):

A nicely formatted calendar date reading May 8, 2020

Add new comment

Full HTML

  • To post pieces of code, surround them with <code>...</code> tags. For PHP code, you can use <?php ... ?>, which will also colour it based on syntax.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Filtered HTML

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.