Date fields in Drupal 8 and 9 are stored as strings in the database, with a maximum length of 20 characters [ varchar(20) ].
You can configure the date field to hold only the date value. In that case, the value is stored as a string like this 2020-12-31
Or you can configure the date field to hold both date and time. In that case, the value is stored as a string like this 2020-12-31T23:59:59
On the other hand, values for base fields created and changed are stored as integers [ int(11) ]. All content entities have these values and they indicate when the content was created and updated. These values look something like this 1473344734
Let's see how to programmatically set date field values.
use Drupal\node\Entity\Node;
// Set specific values.
$node = Node::load(1);
$node->set('field_date', '2025-12-31');
$node->set('field_datetime', '2025-12-31T23:59:59');
$node->set('created', '1760140799');
$node->save();
use Drupal\node\Entity\Node;
// Set the current date and time.
$node = Node::load(1);
$node->set('field_date', date('Y-m-d', time()));
$node->set('field_datetime', date('Y-m-d\TH:i:s', time()));
$node->set('created', time());
$node->save();
Time zone
If you take a look at the database table of your date field, you will see that time zone is not stored. That's because dates in Drupal 8 and 9 are stored in the UTC timezone.
So, before saving a datetime field programmatically you have to convert the date to UTC timezone:
use Drupal\node\Entity\Node;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
$now = DrupalDateTime::createFromTimestamp(time());
$now->setTimezone(new \DateTimeZone('UTC'));
// Set the current date and time.
$node = Node::load(1);
$node->set('field_date', $now->format('Y-m-d'));
$node->set('field_datetime', $now->format('Y-m-d\TH:i:s'));
$node->set('created', $now->getTimestamp());
$node->save();
Get the date field programmatically
To get and format a date field's value, you should use the date.formatter service like this:
use Drupal\node\Entity\Node;
use Drupal\Core\Datetime\DrupalDateTime;
$node = Node::load(1);
// For datetime fields.
$datetime = new DrupalDateTime($node->get('field_datetime')->value, 'UTC');
$date_formatter = \Drupal::service('date.formatter');
$date = $date_formatter->format($datetime->getTimestamp(), 'custom', 'Y-m-d H:i');
// For datetime fields you can also do this.
$date_formatter = \Drupal::service('date.formatter');
$date = $date_formatter->format($node->get('field_datetime')->date->getTimestamp(), 'custom', 'Y-m-d H:i');
// For timestamp fields (changed, created, ...)
$date_formatter = \Drupal::service('date.formatter');
$date = $date_formatter->format($node->get('changed')->value, 'custom', 'Y-m-d H:i');
For datetime fields, we first have to convert the datetime to timestamp. You can use the DrupalDateTime class to do it, just remember to set the timezone to UTC (second parameter of the constructor).
Otherwise, it will default to the system timezone and that's usually not UTC so you will have an incorrect value. You can configure the system timezone on the following page: admin/config/regional/settings
Datetime fields also have the computed date property (instance of DrupalDateTime class). Check out the second example for datetime fields above, to see how to get the timestamp value.
The format() method of the "date.formatter" service will use the system timezone and that's usually exactly what we need. If you want to display the value in some other timezone, then you also have to provide the timezone parameter:
$date = $date_formatter->format($node->get('changed')->value, 'custom', 'Y-m-d H:i', 'America/New_York');