Datetime overview

Last updated on
2 September 2026

About

The Datetime and Datetime Range modules provide three fields that stores dates and times.

  • Datetime: Stores a date as UTC in the format 'Y-m-d\TH:i:s'; it is stored as a varchar(20) field in the database
  • Datetime range: Same as datetime, but with an added end value

In addition, Drupal core provides one more date field type:

  • Timestamp: a large integer

Timestamp is not provided by a core module, thus cannot be uninstalled.

The Datetime module also provides the Form API elements datetime and datelist which other modules can make use of. See the Field module documentation and the Field UI module documentation pages for general information on fields and how to create and manage them.  For how to make use of the Form API elements in modules you program yourself, see the Form API documentation and the Form and render elements API reference documentation.

Comparison of field types

Timestamp Datetime Datetime range
Provided by Drupal core (not a module; cannot be removed) Datetime module, which is provided by Drupal core Datetime Range module, which is provided by Drupal core
Nullable Cannot be empty (null); when you save the entity, if the field is blank, then the current date and time is used. Can be empty Can be empty
Min 13 December 1901 01 January 0001 (no BCE years)
Max 19 January 2038 at 03:14:07 UTC 31 December 9999
Time optional Time is not optional Time is optional (using date-only setting) Time is optional (using date-only setting), and also an "all day" option
Storage in database Stored as an integer; specifically a Unix timestamp, which is the number of seconds since midnight UTC of 1 January 1970. Stored in ISO-8601 format. E.g.: "2000-12-31T23:59:59Z"
Form widgets Datetime timestamp Select list
Date and time
Select list
Date and time range
Display formatters Default: E.g. "1 Jan 2030 - 12:00"
Time ago: E.g. "1 year 1 month ago"
Default: E.g. "1 Jan 2030 - 12:00"
Plain: E.g. "2030-01-01T00:00:00"
Custom: E.g. "1st of January '30"
Time ago: E.g. "1 year 1 month ago"
Default: E.g. "1 Jan 2030 - 2 Jan 2030"
Plain: E.g. "2030-01-01T00:00:00 - 2030-01-02T00:00:00"
Custom: E.g. "1 Jan - 2 Jan"

Uses

Managing and displaying date fields

The settings and the display of the Date field can be configured separately. See the Field UI module documentation for more information on how to manage fields and their display.

Displaying dates

Dates can be displayed using either the Plain or Default formatter. The Plain formatter displays the date in the ISO 8601 format. If you choose the Default formatter, you can choose a format from a predefined list that can be managed on the Date and time formats page.

Adjust datetime formats at Manage > Configuration > Regional and language > Date and time formats (path: /admin/config/regional/date-time).

For more information, see Working With Content Types and Fields. For a list of the functions and their descriptions see the API documentation.

Formatting dates programmatically

The Datetime module provides a DateFormatter service that can be used to format timestamps.

use Drupal\Core\Datetime\DrupalDateTime;

/** @var Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
$date_formatter = \Drupal::service('date.formatter');

// Get saved timestamp from a DateTimeFieldItemList field.
$date_value = $node->field_date->value;
$date_time = new DrupalDateTime($date_value, new \DateTimeZone('UTC'));
$timestamp = $date_time->getTimestamp();

// All other arguments are optional:
// See DateFormatterInterface for built-in options, or use machine name of a date format in config.
$type = 'medium';
// Custom PHP date format if $type="custom".
$format = '';
// Timezone cannot be NULL otherwise it will default to the user's own
// timezone. That is why it should be set explicitly.
$timezone = 'UTC';
$langcode = NULL;

$formatted = $date_formatter->format($timestamp, $type, $format, $timezone, $langcode);

An everyday approach to formatting dates programmatically looks like this:

// Show a date stored in a node in format medium.
\Drupal::service('date.formatter')->format(strtotime($order_node->field_order_date->value), 'medium')

/*
Worth noting:

1. By summoning \Drupal::service('date.formatter') directly, you do not need a use statement to that effect in your code.
2. the first argument MUST be a timestamp. As you'll probably mostly store dates in the Drupal date format, you need to do a strtotime.
3. The type "medium" is a built-in core time format. You will find all your valid date formats at /admin/config/regional/date-time - but you'll have to edit them in order to learn their machine names. You MUST use the machine names when formatting dates programmatically.
4. If you supply a type other than "custom", you can leave format blank, ''.
5. As no timezone is set, a user with timezone "Europe/Copenhagen" will see something quite unlike the user with the timezone set to "Europe/Dublin". This is often not something you want.
6. As no language code is set, a user with langcode "da" will see something quite unlike a user with the language code "en". This is often something you want. But do test.

*/

Saving dates

Saving dates using the node forms and user forms is straightforward. The date is saved in the UTC timezone and the site will display the date using the sitewide timezone or the timezone of the individual users. This is all managed at the Regional settings page (/admin/config/regional/settings). Most sites will do well setting a default country and a default timezone. If it's a big country or a global site, you may wish to check Users may set their own time zone.

Saving dates programmatically

In Drupal dates are saved in varchar(20) fields in the database. An example: "2024-10-29T04:45:58".

The format is 'Y-m-d\TH:i:s' and the timezone is always 'UTC'. You cannot save a date like "2024-10-29T04:45:58 +0200".

Same goes for Dateranges. They're just Dates with a value and and end_value.

Timestamps are integers. UTC as well.

# Saving current time to a date field in a node
$now = (new \Drupal\Core\Datetime\DrupalDateTime('now', new \DateTimeZone('UTC')))->format('Y-m-d\TH:i:s');
$order_node->set('field_order_paid_date', $now); // You need to save the $order_node to make the date stick

# Saving a few dates (and times) to a daterange field in a node
$now = \Drupal::service('date.formatter')->format(time(), 'custom', 'Y-m-d\TH:i:s', 'UTC');
$an_hour_later = \Drupal::service('date.formatter')->format(time()+3600, 'custom', 'Y-m-d\TH:i:s', 'UTC');
$appointment_node->set('field_appointment', ['value' => $now, 'end_value' => $an_hour_later]); // The value set is an array of two values. Remember to save the $appointment_node

# Saving a timestamp
$now = (new \Drupal\Core\Datetime\DrupalDateTime('now', new \DateTimeZone('UTC')))->format('Y-m-d\TH:i:s');
$timestamp = strtotime($now);
$order_node->set('field_timestamp', $timestamp); // Remember to save

# Saving a timestamp tweaked to reflect the timezone of the site
$config_timezone = \Drupal::config('system.date')->get('timezone.default');
$now = new DrupalDateTime('now', new \DateTimeZone($config_timezone));
$timestamp = strtotime($now->format('Y-m-d\TH:i:s'));
$order_node->set('field_timestamp', $timestamp); // Remember to save

# Saving current time to a date field in a node - alternative version
$now = \Drupal::service('date.formatter')->format(time(), 'custom', 'Y-m-d\TH:i:s', 'UTC');
$order_node->set('field_order_paid_date', $now); // You need to save the $order_node to make the date stick

# Saving current date - and just the date - to a date field in a node. Fiddling with the datetime fields in content types and user accounts, you can set the field to solely store the date. Then you feed it a string:
$utc_date = \Drupal::service('date.formatter')->format(time(), 'custom', 'Y-m-d', 'UTC');
$user->set('field_membership_start', $utc_date); // You need to save the $user to make the date stick

# If you place a "use Drupal\Core\Datetime\DrupalDateTime;" at the top of your module, controller, block or form, you can cut the very complicated time fetching down to
$now = (new DrupalDateTime('now', new \DateTimeZone('UTC')))->format('Y-m-d\TH:i:s'); // slightly shorter but no less complicated.

# In all the above examples we expect the server to provide us with a UTC time. Check that this is correct whenever you install a new Drupal site!

Help improve this page

Page status: No known problems

You can: