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.