Drupal: Setting the 'Date' field value

Making sure the timezone and date format is set accordingly

I tend to forget how to set the Drupal datetime field programmatically, so this post works as a note for my self and anyone else who's in the same boat.

Snippet

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;

// ...

// Use the DrupalDateTime object to modify (or parse) datetimes.
$datetime = new DrupalDateTime('now');
// Set the timezone to UTC (the stored timezone).
$datetime->setTimezone(new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);

// Date and time.
$entity->field_dateandtime = $datetime->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT);
// Or date only.
$entity->field_dateonly = $datetime->format(DateTimeItemInterface::DATE_STORAGE_FORMAT);

The DrupalDateTime extends the DateTimePlus (with drupal specific functionalities), which wraps the regular PHP DateTime object (adding extra functionality and error handling).

The datetime field always saves with the STORAGE_TIMEZONE (UTC) timezone, so use the setTimezone function with a DateTimeZone to make sure of this.

Use the correct storage format depending on the datetime_type field settings. DATETIME_STORAGE_FORMAT for Date and time or DATE_STORAGE_FORMAT for Date only.

Automatically determine date and time or date only.

For a more generic version, use the field storage settings to determine what format to save as.

use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;

// ...

// Get the setting from the field settings.
$datetime_type = $entity->field_datetime->getFieldDefinition()->getFieldStorageDefinition()->getSetting('datetime_type');

// Determine the format.
$format = match ($datetime_type) {
    DateTimeItem::DATETIME_TYPE_DATE => DateTimeItemInterface::DATE_STORAGE_FORMAT,
    DateTimeItem::DATETIME_TYPE_DATETIME => DateTimeItemInterface::DATETIME_STORAGE_FORMAT,
};

// Set using the correct format.
$entity->field_datetime = $datetime->format($format);

What is up with timezones

tl;dr
Set the timezone of the given time when creating the DrupalDateTime, and set the timezone to the STORAGE_TIMEZONE format before setting the datetime field value.

// Set the timezone of the given time.
$datetime = new DrupalDateTime($time, $time_timezone);

// Set the timezone to the storage format, and set the value.
$datetime->setTimezone(new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);
$entity->field_datetime = $datetime->format($format);

Setting field value is always the same, but it's important to know what timezone your data comes from to instantiate it with the correct zone.

Creating the DrupalDateTime object.

The DrupalDateTime defaults the timezone to the date_default_timezone_get(), but it takes a $timezone parameter (second parameter) which is the timezone of the given time (first argument).

The timezone is passed directly the DateTimeZone constructor, so it supports the following:

One of the supported timezone names, an offset value (+0200), or a timezone abbreviation (BST).

You can get a list of timezone names or abbreviation by using the static DateTimeZone::listIdentifiers() or DateTimeZone::listAbbreviations() functions.

If the given time is a timestamp or has specified a timezone, it will ignore the $timezone parameter.

// This will ignore the 'UTC' parameter.
$datetime = new DrupalDateTime('2022-05-28T12:00:00+02:00', 'UTC');
echo $datetime->format(\DateTime::ISO8601, ['timezone' => 'UTC']);
// 2022-05-28T10:00:00+0000 (notice it says 10 and not 12).

// Without the timezone it uses UTC.
$datetime = new DrupalDateTime('2022-05-28T12:00:00', 'UTC');
$datetime->format(\DateTime::ISO8601, ['timezone' => 'UTC'])
// 2022-05-28T12:00:00+0000 (stays 12, because it's in the same zone).

If lucky the DrupalDateTime will simply read the time given, and return an object with the correct date and time. Check out the Supported Date and Time Formats in the PHP manual.

But if the given date and time format isn't parsable, the DateTimePlus (which DrupalDateTime inherits from) has some static helpers. Look for functions prefixed with createFrom and find the one suited for the current date time input.

Did you find this article valuable?

Support Philip Birk-Jensen by becoming a sponsor. Any amount is appreciated!