Drupal's Datetime element is a great convenience, providing a UI for data and time entry and rendering date output. This is, of course, as long as you use the built in features. If you access the date directly, the date and time format may provide unexpected results.
Datetime field data is stored in UTC
UTC is Coordinated Universal Time, also known as Greenwich Mean Time or GMT. When you enter the date and time in the form, it appears in the timezone that is set up for the site and it gets converted to UTC when stored. As long as you're using the API to access the data, it's all good.
Timezone is important. Drupal is going to reference the timezone defined for your website when rendering through the API.
Keeping this in mind, here are a few ways to manipulate the data in the output format you want.
Use the API
If you're only rendering once, this may be your best bet.
- Go to Manage Display for your entity
- Select the correct display mode
- Choose the date format.
- There is an option for "custom" format if needed.
Then in twig, you can render the date using the "content" collection, which runs through the API.
{{ content.field_start_date }}
Pre-process the data
This is where it can get a little tricky. When you access the data directly, it will be in UTC. When you create a DateTime object using this data, you need to set the DateTimeZone to UTC while creating the object. Once you do this, then you can convert to another Timezone.
When you call date_default_timezone_get(), this will be returned as a string. Note that drupal_get_user_timezone() was deprecated in Drupal 8.8.
Here's my function.
This can be called in an entity pre-process hook.
/**
* Helper to manage Drupal Date fields that store data in UTC
*
* @param string $data Date string Data
* @param string $format Format to return date in
* @param string $tzone Timezone string to convert to
*
* @return string
* @throws \Exception
*/
public function date_fromutc($data, $format, $tzone=NULL) {
if (!$tzone) {
$tzone = date_default_timezone_get();
}
$date = new \DateTime($data, new \DateTimeZone('UTC'));
$date->setTimezone(new \DateTimeZone($tzone));
return $date->format($format);
}
I created a custom Twig filter using this function to make it reusable.
{% set date_start_month = node.field_date_start.value|date_fromutc('F') %}
{% set date_start_day = node.field_date_start.value|date_fromutc('j') %}
{% set date_start_time = node.field_date_start.value|date_fromutc('g:i a') %}
{{ date_start_month }}
{{ date_start_day }} | {{ date_start_time }}