# Drupal: Setting the 'Date' field value

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

```php
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`](https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Datetime%21DrupalDateTime.php/class/DrupalDateTime/9.4.x) extends the [`DateTimePlus`](https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Component%21Datetime%21DateTimePlus.php/class/DateTimePlus/9.4.x) (with drupal specific functionalities), which wraps the regular PHP [`DateTime`](https://www.php.net/manual/en/class.datetime.php) object (adding extra functionality and error handling).

The datetime field always saves with the [`STORAGE_TIMEZONE`](https://api.drupal.org/api/drupal/core%21modules%21datetime%21src%21Plugin%21Field%21FieldType%21DateTimeItemInterface.php/constant/DateTimeItemInterface%3A%3ASTORAGE_TIMEZONE/9.4.x) (UTC) timezone, so use the [`setTimezone`](https://www.php.net/manual/en/datetime.settimezone.php) function with a [`DateTimeZone`](https://www.php.net/manual/en/class.datetimezone.php) to make sure of this.

Use the correct storage format depending on the datetime\_type field settings. [`DATETIME_STORAGE_FORMAT`](https://api.drupal.org/api/drupal/core%21modules%21datetime%21src%21Plugin%21Field%21FieldType%21DateTimeItemInterface.php/constant/DateTimeItemInterface%3A%3ADATETIME_STORAGE_FORMAT/9.4.x) for *Date and time* or [`DATE_STORAGE_FORMAT`](https://api.drupal.org/api/drupal/core%21modules%21datetime%21src%21Plugin%21Field%21FieldType%21DateTimeItemInterface.php/constant/DateTimeItemInterface%3A%3ADATE_STORAGE_FORMAT/9.4.x) 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.

```php
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.

```php
// 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()`](https://www.php.net/manual/en/function.date-default-timezone-get.php), 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](https://www.php.net/manual/en/datetimezone.construct.php), 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()`](https://www.php.net/manual/en/datetimezone.listidentifiers.php) or [`DateTimeZone::listAbbreviations()`](https://www.php.net/manual/en/datetimezone.listabbreviations.php) functions.

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

```php
// 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](https://www.php.net/manual/en/datetime.formats.php) in the PHP manual.

But if the given date and time format isn't parsable, the [`DateTimePlus`](https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Component%21Datetime%21DateTimePlus.php/class/DateTimePlus/9.4.x) (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.
