From 31f9ebf7f5fb148b04f0822b9fbf2206ccbd0a04 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Tue, 1 Jan 2019 19:15:24 +0000
Subject: [PATCH] Issue #3008446 by alexpott, jcnventura, fenstrat, quietone,
 voleger, andypost: Complete the deprecation of format_date()

---
 core/includes/common.inc                      |  1 +
 core/includes/theme.inc                       |  6 ++--
 .../Drupal/Core/Datetime/Element/Datetime.php | 22 ++++++------
 .../lib/Drupal/Core/Test/TestRunnerKernel.php |  4 +--
 core/lib/Drupal/Core/Utility/token.api.php    |  2 +-
 core/modules/comment/comment.module           | 14 ++++----
 core/modules/comment/comment.tokens.inc       |  4 +--
 .../src/Functional/CommentPreviewTest.php     |  2 +-
 .../Functional/CommentTranslationUITest.php   |  6 ++--
 .../Functional/ConfigTranslationUiTest.php    |  2 +-
 .../src/ContentTranslationHandler.php         | 23 ++++++++++---
 .../Tests/ContentTranslationUITestBase.php    |  2 +-
 .../ContentTranslationUITestBase.php          |  2 +-
 .../src/Plugin/views/argument/Date.php        |  5 +--
 .../src/Functional/DateTimeFieldTest.php      | 11 +++---
 core/modules/file/file.module                 |  4 +--
 .../src/Functional/FileTokenReplaceTest.php   | 10 +++---
 .../LocaleConfigTranslationTest.php           |  2 +-
 .../Functional/LocaleUpdateInterfaceTest.php  |  5 ++-
 .../tests/src/Functional/LocaleUpdateTest.php |  6 ++--
 core/modules/node/node.tokens.inc             |  4 +--
 .../node/src/Controller/NodeController.php    |  2 +-
 .../node/src/Form/NodeRevisionDeleteForm.php  | 22 +++++++++---
 core/modules/node/src/NodeForm.php            | 18 ++++++++--
 .../node/src/NodeTranslationHandler.php       |  2 +-
 .../tests/src/Functional/NodeCreationTest.php |  4 +--
 .../tests/src/Functional/NodeEditFormTest.php |  4 +--
 .../src/Functional/NodeRevisionsAllTest.php   |  6 ++--
 .../src/Functional/NodeRevisionsTest.php      |  6 ++--
 .../src/Functional/NodeRevisionsUiTest.php    |  4 +--
 .../src/Functional/NodeTranslationUITest.php  |  6 ++--
 .../tests/src/Kernel/NodeTokenReplaceTest.php |  6 ++--
 .../src/Functional/CommentAttributesTest.php  |  4 +--
 .../src/Functional/StandardProfileTest.php    |  4 +--
 core/modules/search/search.pages.inc          |  2 +-
 .../tests/src/Functional/SearchExactTest.php  |  4 +--
 core/modules/statistics/statistics.tokens.inc |  2 +-
 .../Functional/StatisticsTokenReplaceTest.php |  6 ++--
 core/modules/system/system.tokens.inc         | 15 ++++----
 .../src/Functional/Common/FormatDateTest.php  | 13 ++++---
 core/modules/update/update.report.inc         |  2 +-
 .../src/Functional/UserTokenReplaceTest.php   | 11 +++---
 core/modules/user/user.tokens.inc             |  4 +--
 .../views/src/Plugin/views/argument/Date.php  | 17 ++++++++--
 .../src/Plugin/views/argument/DayDate.php     |  8 ++---
 .../src/Plugin/views/argument/FullDate.php    |  8 ++---
 .../src/Plugin/views/argument/MonthDate.php   |  8 ++---
 .../Plugin/views/argument/YearMonthDate.php   |  8 ++---
 .../views/src/Plugin/views/field/Date.php     |  6 ++--
 .../src/Functional/Handler/FilterDateTest.php | 34 ++++++++++++-------
 .../src/Kernel/Handler/FieldDateTest.php      | 31 +++++++++--------
 .../Core/Common/LegacyFunctionsTest.php       | 26 ++++++++++++++
 ...rmatDateTest.php => DateFormatterTest.php} |  9 +++--
 53 files changed, 284 insertions(+), 155 deletions(-)
 create mode 100644 core/tests/Drupal/KernelTests/Core/Common/LegacyFunctionsTest.php
 rename core/tests/Drupal/KernelTests/Core/Datetime/{FormatDateTest.php => DateFormatterTest.php} (96%)

diff --git a/core/includes/common.inc b/core/includes/common.inc
index 57746eb734f1..80225be546ed 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -329,6 +329,7 @@ function format_size($size, $langcode = NULL) {
  * @see https://www.drupal.org/node/1876852
  */
 function format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL) {
+  @trigger_error("format_date() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal::service('date.formatter')->format() instead. See https://www.drupal.org/node/1876852", E_USER_DEPRECATED);
   return \Drupal::service('date.formatter')->format($timestamp, $type, $format, $timezone, $langcode);
 }
 
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index f5f553ddf45c..757dfe0ab441 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -507,17 +507,19 @@ function theme_settings_convert_to_config(array $theme_settings, Config $config)
  *   - text:
  */
 function template_preprocess_time(&$variables) {
+  /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+  $date_formatter = \Drupal::service('date.formatter');
   // Format the 'datetime' attribute based on the timestamp.
   // @see http://www.w3.org/TR/html5-author/the-time-element.html#attr-time-datetime
   if (!isset($variables['attributes']['datetime']) && isset($variables['timestamp'])) {
-    $variables['attributes']['datetime'] = format_date($variables['timestamp'], 'html_datetime', '', 'UTC');
+    $variables['attributes']['datetime'] = $date_formatter->format($variables['timestamp'], 'html_datetime', '', 'UTC');
   }
 
   // If no text was provided, try to auto-generate it.
   if (!isset($variables['text'])) {
     // Format and use a human-readable version of the timestamp, if any.
     if (isset($variables['timestamp'])) {
-      $variables['text'] = format_date($variables['timestamp']);
+      $variables['text'] = $date_formatter->format($variables['timestamp']);
     }
     // Otherwise, use the literal datetime attribute.
     elseif (isset($variables['attributes']['datetime'])) {
diff --git a/core/lib/Drupal/Core/Datetime/Element/Datetime.php b/core/lib/Drupal/Core/Datetime/Element/Datetime.php
index 941db32b6f5d..4b6afaadf3a1 100644
--- a/core/lib/Drupal/Core/Datetime/Element/Datetime.php
+++ b/core/lib/Drupal/Core/Datetime/Element/Datetime.php
@@ -147,11 +147,11 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
    *   - #date_date_format: A date format string that describes the format that
    *     should be displayed to the end user for the date. When using HTML5
    *     elements the format MUST use the appropriate HTML5 format for that
-   *     element, no other format will work. See the format_date() function for a
-   *     list of the possible formats and HTML5 standards for the HTML5
-   *     requirements. Defaults to the right HTML5 format for the chosen element
-   *     if a HTML5 element is used, otherwise defaults to
-   *     DateFormat::load('html_date')->getPattern().
+   *     element, no other format will work. See the
+   *     DateFormatterInterface::format() function for a list of the possible
+   *     formats and HTML5 standards for the HTML5 requirements. Defaults to the
+   *     right HTML5 format for the chosen element if a HTML5 element is used,
+   *     otherwise defaults to DateFormat::load('html_date')->getPattern().
    *   - #date_date_element: The date element. Options are:
    *     - datetime: Use the HTML5 datetime element type.
    *     - datetime-local: Use the HTML5 datetime-local element type.
@@ -167,11 +167,11 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
    *   - #date_time_format: A date format string that describes the format that
    *     should be displayed to the end user for the time. When using HTML5
    *     elements the format MUST use the appropriate HTML5 format for that
-   *     element, no other format will work. See the format_date() function for
-   *     a list of the possible formats and HTML5 standards for the HTML5
-   *     requirements. Defaults to the right HTML5 format for the chosen element
-   *     if a HTML5 element is used, otherwise defaults to
-   *     DateFormat::load('html_time')->getPattern().
+   *     element, no other format will work. See the
+   *     DateFormatterInterface::format() function for a list of the possible
+   *     formats and HTML5 standards for the HTML5 requirements. Defaults to the
+   *     right HTML5 format for the chosen element if a HTML5 element is used,
+   *     otherwise defaults to DateFormat::load('html_time')->getPattern().
    *   - #date_time_callbacks: An array of optional callbacks for the time
    *     element. Can be used to add a jQuery timepicker or an 'All day' checkbox.
    *   - #date_year_range: A description of the range of years to allow, like
@@ -212,6 +212,8 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
    *
    * @return array
    *   The form element whose value has been processed.
+   *
+   * @see \Drupal\Core\Datetime\DateFormatterInterface::format()
    */
   public static function processDatetime(&$element, FormStateInterface $form_state, &$complete_form) {
     $format_settings = [];
diff --git a/core/lib/Drupal/Core/Test/TestRunnerKernel.php b/core/lib/Drupal/Core/Test/TestRunnerKernel.php
index 5be2b83669aa..b615ce356fa1 100644
--- a/core/lib/Drupal/Core/Test/TestRunnerKernel.php
+++ b/core/lib/Drupal/Core/Test/TestRunnerKernel.php
@@ -31,8 +31,8 @@ public function __construct($environment, $class_loader, $allow_dumping = FALSE,
     // Prime the module list and corresponding Extension objects.
     // @todo Remove System module. Needed because
     //   \Drupal\Core\Datetime\DateFormatter has a (needless) dependency on the
-    //   'date_format' entity, so calls to format_date()/format_interval() cause
-    //   a plugin not found exception.
+    //   'date_format' entity, so calls to DateFormatter::format() and
+    //   DateFormatter::formatInterval() cause a plugin not found exception.
     $this->moduleList = [
       'system' => 0,
       'simpletest' => 0,
diff --git a/core/lib/Drupal/Core/Utility/token.api.php b/core/lib/Drupal/Core/Utility/token.api.php
index de876cfb7b71..4ba239f67224 100644
--- a/core/lib/Drupal/Core/Utility/token.api.php
+++ b/core/lib/Drupal/Core/Utility/token.api.php
@@ -111,7 +111,7 @@ function hook_tokens($type, $tokens, array $data, array $options, \Drupal\Core\R
           break;
 
         case 'created':
-          $replacements[$original] = format_date($node->getCreatedTime(), 'medium', '', NULL, $langcode);
+          $replacements[$original] = \Drupal::service('date.formatter')->format($node->getCreatedTime(), 'medium', '', NULL, $langcode);
           break;
       }
     }
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index dd0acb35658f..8a63a7eae37c 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -623,6 +623,8 @@ function comment_preprocess_block(&$variables) {
  *     Array keys: #comment, #commented_entity.
  */
 function template_preprocess_comment(&$variables) {
+  /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+  $date_formatter = \Drupal::service('date.formatter');
   /** @var \Drupal\comment\CommentInterface $comment */
   $comment = $variables['elements']['#comment'];
   $commented_entity = $comment->getCommentedEntity();
@@ -638,13 +640,13 @@ function template_preprocess_comment(&$variables) {
   $variables['author'] = \Drupal::service('renderer')->render($username);
   $variables['author_id'] = $comment->getOwnerId();
   $variables['new_indicator_timestamp'] = $comment->getChangedTime();
-  $variables['created'] = format_date($comment->getCreatedTime());
-  // Avoid calling format_date() twice on the same timestamp.
+  $variables['created'] = $date_formatter->format($comment->getCreatedTime());
+  // Avoid calling DateFormatterInterface::format() twice on the same timestamp.
   if ($comment->getChangedTime() == $comment->getCreatedTime()) {
     $variables['changed'] = $variables['created'];
   }
   else {
-    $variables['changed'] = format_date($comment->getChangedTime());
+    $variables['changed'] = $date_formatter->format($comment->getChangedTime());
   }
 
   if (theme_get_setting('features.comment_user_picture')) {
@@ -682,13 +684,13 @@ function template_preprocess_comment(&$variables) {
       '#account' => $account_parent,
     ];
     $variables['parent_author'] = \Drupal::service('renderer')->render($username);
-    $variables['parent_created'] = format_date($comment_parent->getCreatedTime());
-    // Avoid calling format_date() twice on the same timestamp.
+    $variables['parent_created'] = $date_formatter->format($comment_parent->getCreatedTime());
+    // Avoid calling DateFormatterInterface::format() twice on same timestamp.
     if ($comment_parent->getChangedTime() == $comment_parent->getCreatedTime()) {
       $variables['parent_changed'] = $variables['parent_created'];
     }
     else {
-      $variables['parent_changed'] = format_date($comment_parent->getChangedTime());
+      $variables['parent_changed'] = $date_formatter->format($comment_parent->getChangedTime());
     }
     $permalink_uri_parent = $comment_parent->permalink();
     $attributes = $permalink_uri_parent->getOption('attributes') ?: [];
diff --git a/core/modules/comment/comment.tokens.inc b/core/modules/comment/comment.tokens.inc
index a9de4d6c38a6..38529c959d47 100644
--- a/core/modules/comment/comment.tokens.inc
+++ b/core/modules/comment/comment.tokens.inc
@@ -209,13 +209,13 @@ function comment_tokens($type, $tokens, array $data, array $options, BubbleableM
         case 'created':
           $date_format = DateFormat::load('medium');
           $bubbleable_metadata->addCacheableDependency($date_format);
-          $replacements[$original] = format_date($comment->getCreatedTime(), 'medium', '', NULL, $langcode);
+          $replacements[$original] = \Drupal::service('date.formatter')->format($comment->getCreatedTime(), 'medium', '', NULL, $langcode);
           break;
 
         case 'changed':
           $date_format = DateFormat::load('medium');
           $bubbleable_metadata->addCacheableDependency($date_format);
-          $replacements[$original] = format_date($comment->getChangedTime(), 'medium', '', NULL, $langcode);
+          $replacements[$original] = \Drupal::service('date.formatter')->format($comment->getChangedTime(), 'medium', '', NULL, $langcode);
           break;
 
         case 'entity':
diff --git a/core/modules/comment/tests/src/Functional/CommentPreviewTest.php b/core/modules/comment/tests/src/Functional/CommentPreviewTest.php
index 7945fe464524..cee08ae39c91 100644
--- a/core/modules/comment/tests/src/Functional/CommentPreviewTest.php
+++ b/core/modules/comment/tests/src/Functional/CommentPreviewTest.php
@@ -143,7 +143,7 @@ public function testCommentEditPreviewSave() {
     $edit['date[date]'] = $date->format('Y-m-d');
     $edit['date[time]'] = $date->format('H:i:s');
     $raw_date = $date->getTimestamp();
-    $expected_text_date = format_date($raw_date);
+    $expected_text_date = $this->container->get('date.formatter')->format($raw_date);
     $expected_form_date = $date->format('Y-m-d');
     $expected_form_time = $date->format('H:i:s');
     $comment = $this->postComment($this->node, $edit['subject[0][value]'], $edit['comment_body[0][value]'], TRUE);
diff --git a/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
index daf673f10ecf..3652b1733c70 100644
--- a/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
+++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
@@ -162,10 +162,12 @@ protected function doTestAuthoringInfo() {
         'uid' => $user->id(),
         'created' => REQUEST_TIME - mt_rand(0, 1000),
       ];
+      /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+      $date_formatter = $this->container->get('date.formatter');
       $edit = [
         'uid' => $user->getAccountName() . ' (' . $user->id() . ')',
-        'date[date]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d'),
-        'date[time]' => format_date($values[$langcode]['created'], 'custom', 'H:i:s'),
+        'date[date]' => $date_formatter->format($values[$langcode]['created'], 'custom', 'Y-m-d'),
+        'date[time]' => $date_formatter->format($values[$langcode]['created'], 'custom', 'H:i:s'),
       ];
       $this->drupalPostForm($url, $edit, $this->getFormSubmitAction($entity, $langcode));
     }
diff --git a/core/modules/config_translation/tests/src/Functional/ConfigTranslationUiTest.php b/core/modules/config_translation/tests/src/Functional/ConfigTranslationUiTest.php
index 64fde483e008..d2a0608f2d1d 100644
--- a/core/modules/config_translation/tests/src/Functional/ConfigTranslationUiTest.php
+++ b/core/modules/config_translation/tests/src/Functional/ConfigTranslationUiTest.php
@@ -495,7 +495,7 @@ public function testDateFormatTranslation() {
 
       // Formatting the date 8 / 27 / 1985 @ 13:37 EST with pattern D should
       // display "Tue".
-      $formatted_date = format_date(494015820, $id, NULL, 'America/New_York', 'fr');
+      $formatted_date = $this->container->get('date.formatter')->format(494015820, $id, NULL, 'America/New_York', 'fr');
       $this->assertEqual($formatted_date, 'Tue', 'Got the right formatted date using the date format translation pattern.');
     }
   }
diff --git a/core/modules/content_translation/src/ContentTranslationHandler.php b/core/modules/content_translation/src/ContentTranslationHandler.php
index 1767dcdb0670..20b0206185f4 100644
--- a/core/modules/content_translation/src/ContentTranslationHandler.php
+++ b/core/modules/content_translation/src/ContentTranslationHandler.php
@@ -3,6 +3,7 @@
 namespace Drupal\content_translation;
 
 use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\Entity\EntityChangedInterface;
 use Drupal\Core\Entity\EntityChangesDetectionTrait;
@@ -90,6 +91,13 @@ class ContentTranslationHandler implements ContentTranslationHandlerInterface, E
    */
   protected $messenger;
 
+  /**
+   * The date formatter service.
+   *
+   * @var \Drupal\Core\Datetime\DateFormatterInterface
+   */
+  protected $dateFormatter;
+
   /**
    * Initializes an instance of the content translation controller.
    *
@@ -105,8 +113,10 @@ class ContentTranslationHandler implements ContentTranslationHandlerInterface, E
    *   The current user.
    * @param \Drupal\Core\Messenger\MessengerInterface $messenger
    *   The messenger service.
+   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
+   *   The date formatter service.
    */
-  public function __construct(EntityTypeInterface $entity_type, LanguageManagerInterface $language_manager, ContentTranslationManagerInterface $manager, EntityManagerInterface $entity_manager, AccountInterface $current_user, MessengerInterface $messenger) {
+  public function __construct(EntityTypeInterface $entity_type, LanguageManagerInterface $language_manager, ContentTranslationManagerInterface $manager, EntityManagerInterface $entity_manager, AccountInterface $current_user, MessengerInterface $messenger, DateFormatterInterface $date_formatter) {
     $this->entityTypeId = $entity_type->id();
     $this->entityType = $entity_type;
     $this->languageManager = $language_manager;
@@ -115,6 +125,7 @@ public function __construct(EntityTypeInterface $entity_type, LanguageManagerInt
     $this->currentUser = $current_user;
     $this->fieldStorageDefinitions = $entity_manager->getLastInstalledFieldStorageDefinitions($this->entityTypeId);
     $this->messenger = $messenger;
+    $this->dateFormatter = $date_formatter;
   }
 
   /**
@@ -127,7 +138,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $container->get('content_translation.manager'),
       $container->get('entity.manager'),
       $container->get('current_user'),
-      $container->get('messenger')
+      $container->get('messenger'),
+      $container->get('date.formatter')
     );
   }
 
@@ -508,8 +520,11 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, En
         '#type' => 'textfield',
         '#title' => t('Authored on'),
         '#maxlength' => 25,
-        '#description' => t('Format: %time. The date format is YYYY-MM-DD and %timezone is the time zone offset from UTC. Leave blank to use the time of form submission.', ['%time' => format_date(REQUEST_TIME, 'custom', 'Y-m-d H:i:s O'), '%timezone' => format_date(REQUEST_TIME, 'custom', 'O')]),
-        '#default_value' => $new_translation || !$date ? '' : format_date($date, 'custom', 'Y-m-d H:i:s O'),
+        '#description' => t('Format: %time. The date format is YYYY-MM-DD and %timezone is the time zone offset from UTC. Leave blank to use the time of form submission.', [
+          '%time' => $this->dateFormatter->format(REQUEST_TIME, 'custom', 'Y-m-d H:i:s O'),
+          '%timezone' => $this->dateFormatter->format(REQUEST_TIME, 'custom', 'O'),
+        ]),
+        '#default_value' => $new_translation || !$date ? '' : $this->dateFormatter->format($date, 'custom', 'Y-m-d H:i:s O'),
       ];
 
       $form['#process'][] = [$this, 'entityFormSharedElements'];
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
index e63086a77a7b..5a8a4cf519ac 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
+++ b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
@@ -329,7 +329,7 @@ protected function doTestAuthoringInfo() {
       ];
       $edit = [
         'content_translation[uid]' => $user->getAccountName(),
-        'content_translation[created]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d H:i:s O'),
+        'content_translation[created]' => $this->container->get('date.formatter')->format($values[$langcode]['created'], 'custom', 'Y-m-d H:i:s O'),
       ];
       $url = $entity->toUrl('edit-form', ['language' => ConfigurableLanguage::load($langcode)]);
       $this->drupalPostForm($url, $edit, $this->getFormSubmitAction($entity, $langcode));
diff --git a/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php b/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php
index 2f6487819ca7..024f95e91eb6 100644
--- a/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php
+++ b/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php
@@ -322,7 +322,7 @@ protected function doTestAuthoringInfo() {
       ];
       $edit = [
         'content_translation[uid]' => $user->getAccountName(),
-        'content_translation[created]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d H:i:s O'),
+        'content_translation[created]' => $this->container->get('date.formatter')->format($values[$langcode]['created'], 'custom', 'Y-m-d H:i:s O'),
       ];
       $url = $entity->toUrl('edit-form', ['language' => ConfigurableLanguage::load($langcode)]);
       $this->drupalPostForm($url, $edit, $this->getFormSubmitAction($entity, $langcode));
diff --git a/core/modules/datetime/src/Plugin/views/argument/Date.php b/core/modules/datetime/src/Plugin/views/argument/Date.php
index 4b8caa57c6aa..3b16a3150b42 100644
--- a/core/modules/datetime/src/Plugin/views/argument/Date.php
+++ b/core/modules/datetime/src/Plugin/views/argument/Date.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\datetime\Plugin\views\argument;
 
+use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
 use Drupal\views\FieldAPIHandlerTrait;
@@ -37,8 +38,8 @@ class Date extends NumericDate {
   /**
    * {@inheritdoc}
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition, $route_match);
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match, DateFormatterInterface $date_formatter) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $route_match, $date_formatter);
 
     $definition = $this->getFieldStorageDefinition();
     if ($definition->getSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATE) {
diff --git a/core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php b/core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php
index a994cc82c849..792e75bef036 100644
--- a/core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php
+++ b/core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php
@@ -113,8 +113,10 @@ public function testDateField() {
             case 'format_type':
               // Verify that a date is displayed. Since this is a date-only
               // field, it is expected to display the time as 00:00:00.
-              $expected = format_date($date->getTimestamp(), $new_value, '', DateTimeItemInterface::STORAGE_TIMEZONE);
-              $expected_iso = format_date($date->getTimestamp(), 'custom', 'Y-m-d\TH:i:s\Z', DateTimeItemInterface::STORAGE_TIMEZONE);
+              /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+              $date_formatter = $this->container->get('date.formatter');
+              $expected = $date_formatter->format($date->getTimestamp(), $new_value, '', DateTimeItemInterface::STORAGE_TIMEZONE);
+              $expected_iso = $date_formatter->format($date->getTimestamp(), 'custom', 'Y-m-d\TH:i:s\Z', DateTimeItemInterface::STORAGE_TIMEZONE);
               $output = $this->renderTestEntity($id);
               $expected_markup = '<time datetime="' . $expected_iso . '" class="datetime">' . $expected . '</time>';
               $this->assertContains($expected_markup, $output, new FormattableMarkup('Formatted date field using %value format displayed as %expected with %expected_iso attribute in %timezone.', [
@@ -279,8 +281,9 @@ public function testDatetimeField() {
         switch ($setting) {
           case 'format_type':
             // Verify that a date is displayed.
-            $expected = format_date($date->getTimestamp(), $new_value);
-            $expected_iso = format_date($date->getTimestamp(), 'custom', 'Y-m-d\TH:i:s\Z', 'UTC');
+            $date_formatter = $this->container->get('date.formatter');
+            $expected = $date_formatter->format($date->getTimestamp(), $new_value);
+            $expected_iso = $date_formatter->format($date->getTimestamp(), 'custom', 'Y-m-d\TH:i:s\Z', 'UTC');
             $output = $this->renderTestEntity($id);
             $expected_markup = '<time datetime="' . $expected_iso . '" class="datetime">' . $expected . '</time>';
             $this->assertContains($expected_markup, $output, new FormattableMarkup('Formatted date field using %value format displayed as %expected with %expected_iso attribute.', ['%value' => $new_value, '%expected' => $expected, '%expected_iso' => $expected_iso]));
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index e0d2cb7a5838..b7467e7f5681 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -1179,13 +1179,13 @@ function file_tokens($type, $tokens, array $data, array $options, BubbleableMeta
         case 'created':
           $date_format = DateFormat::load('medium');
           $bubbleable_metadata->addCacheableDependency($date_format);
-          $replacements[$original] = format_date($file->getCreatedTime(), 'medium', '', NULL, $langcode);
+          $replacements[$original] = \Drupal::service('date.formatter')->format($file->getCreatedTime(), 'medium', '', NULL, $langcode);
           break;
 
         case 'changed':
           $date_format = DateFormat::load('medium');
           $bubbleable_metadata = $bubbleable_metadata->addCacheableDependency($date_format);
-          $replacements[$original] = format_date($file->getChangedTime(), 'medium', '', NULL, $langcode);
+          $replacements[$original] = \Drupal::service('date.formatter')->format($file->getChangedTime(), 'medium', '', NULL, $langcode);
           break;
 
         case 'owner':
diff --git a/core/modules/file/tests/src/Functional/FileTokenReplaceTest.php b/core/modules/file/tests/src/Functional/FileTokenReplaceTest.php
index b3f32b7844e2..2ccb77ea91f9 100644
--- a/core/modules/file/tests/src/Functional/FileTokenReplaceTest.php
+++ b/core/modules/file/tests/src/Functional/FileTokenReplaceTest.php
@@ -21,6 +21,8 @@ public function testFileTokenReplacement() {
     $node_storage = $this->container->get('entity.manager')->getStorage('node');
     $token_service = \Drupal::token();
     $language_interface = \Drupal::languageManager()->getCurrentLanguage();
+    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+    $date_formatter = $this->container->get('date.formatter');
 
     // Create file field.
     $type_name = 'article';
@@ -48,10 +50,10 @@ public function testFileTokenReplacement() {
     $tests['[file:mime]'] = Html::escape($file->getMimeType());
     $tests['[file:size]'] = format_size($file->getSize());
     $tests['[file:url]'] = Html::escape(file_create_url($file->getFileUri()));
-    $tests['[file:created]'] = format_date($file->getCreatedTime(), 'medium', '', NULL, $language_interface->getId());
-    $tests['[file:created:short]'] = format_date($file->getCreatedTime(), 'short', '', NULL, $language_interface->getId());
-    $tests['[file:changed]'] = format_date($file->getChangedTime(), 'medium', '', NULL, $language_interface->getId());
-    $tests['[file:changed:short]'] = format_date($file->getChangedTime(), 'short', '', NULL, $language_interface->getId());
+    $tests['[file:created]'] = $date_formatter->format($file->getCreatedTime(), 'medium', '', NULL, $language_interface->getId());
+    $tests['[file:created:short]'] = $date_formatter->format($file->getCreatedTime(), 'short', '', NULL, $language_interface->getId());
+    $tests['[file:changed]'] = $date_formatter->format($file->getChangedTime(), 'medium', '', NULL, $language_interface->getId());
+    $tests['[file:changed:short]'] = $date_formatter->format($file->getChangedTime(), 'short', '', NULL, $language_interface->getId());
     $tests['[file:owner]'] = Html::escape($this->adminUser->getDisplayName());
     $tests['[file:owner:uid]'] = $file->getOwnerId();
 
diff --git a/core/modules/locale/tests/src/Functional/LocaleConfigTranslationTest.php b/core/modules/locale/tests/src/Functional/LocaleConfigTranslationTest.php
index 3d6c95084a74..f3217691d62a 100644
--- a/core/modules/locale/tests/src/Functional/LocaleConfigTranslationTest.php
+++ b/core/modules/locale/tests/src/Functional/LocaleConfigTranslationTest.php
@@ -112,7 +112,7 @@ public function testConfigTranslation() {
 
     // Formatting the date 8 / 27 / 1985 @ 13:37 EST with pattern D should
     // display "Tue".
-    $formatted_date = format_date(494015820, $type = 'medium', NULL, 'America/New_York', $this->langcode);
+    $formatted_date = $this->container->get('date.formatter')->format(494015820, $type = 'medium', NULL, 'America/New_York', $this->langcode);
     $this->assertEqual($formatted_date, 'Tue', 'Got the right formatted date using the date format translation pattern.');
 
     // Assert strings from image module config are not available.
diff --git a/core/modules/locale/tests/src/Functional/LocaleUpdateInterfaceTest.php b/core/modules/locale/tests/src/Functional/LocaleUpdateInterfaceTest.php
index 0ab558503c73..2cfd7ef05162 100644
--- a/core/modules/locale/tests/src/Functional/LocaleUpdateInterfaceTest.php
+++ b/core/modules/locale/tests/src/Functional/LocaleUpdateInterfaceTest.php
@@ -111,7 +111,10 @@ public function testInterface() {
     // Check if translations are available for Drupal core.
     $this->drupalGet('admin/reports/translations');
     $this->assertText(t('Updates for: @project', ['@project' => t('Drupal core')]), 'Translations found');
-    $this->assertText(new FormattableMarkup('@module (@date)', ['@module' => t('Drupal core'), '@date' => format_date(REQUEST_TIME, 'html_date')]), 'Core translation update');
+    $this->assertText(new FormattableMarkup('@module (@date)', [
+      '@module' => t('Drupal core'),
+      '@date' => $this->container->get('date.formatter')->format(REQUEST_TIME, 'html_date'),
+    ]), 'Core translation update');
     $update_button = $this->xpath('//input[@type="submit"][@value="' . t('Update translations') . '"]');
     $this->assertTrue($update_button, 'Update translations button');
   }
diff --git a/core/modules/locale/tests/src/Functional/LocaleUpdateTest.php b/core/modules/locale/tests/src/Functional/LocaleUpdateTest.php
index 907e572c428d..b5b71e940eb8 100644
--- a/core/modules/locale/tests/src/Functional/LocaleUpdateTest.php
+++ b/core/modules/locale/tests/src/Functional/LocaleUpdateTest.php
@@ -136,8 +136,10 @@ public function testUpdateImportSourceRemote() {
     // Check the status on the Available translation status page.
     $this->assertRaw('<label for="edit-langcodes-de" class="visually-hidden">Update German</label>', 'German language found');
     $this->assertText('Updates for: Contributed module one, Contributed module two, Custom module one, Locale test', 'Updates found');
-    $this->assertText('Contributed module one (' . format_date($this->timestampNew, 'html_date') . ')', 'Updates for Contrib module one');
-    $this->assertText('Contributed module two (' . format_date($this->timestampNew, 'html_date') . ')', 'Updates for Contrib module two');
+    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+    $date_formatter = $this->container->get('date.formatter');
+    $this->assertText('Contributed module one (' . $date_formatter->format($this->timestampNew, 'html_date') . ')', 'Updates for Contrib module one');
+    $this->assertText('Contributed module two (' . $date_formatter->format($this->timestampNew, 'html_date') . ')', 'Updates for Contrib module two');
 
     // Execute the translation update.
     $this->drupalPostForm('admin/reports/translations', [], t('Update translations'));
diff --git a/core/modules/node/node.tokens.inc b/core/modules/node/node.tokens.inc
index 6133700387a8..9b7d7f91e536 100644
--- a/core/modules/node/node.tokens.inc
+++ b/core/modules/node/node.tokens.inc
@@ -183,13 +183,13 @@ function node_tokens($type, $tokens, array $data, array $options, BubbleableMeta
         case 'created':
           $date_format = DateFormat::load('medium');
           $bubbleable_metadata->addCacheableDependency($date_format);
-          $replacements[$original] = format_date($node->getCreatedTime(), 'medium', '', NULL, $langcode);
+          $replacements[$original] = \Drupal::service('date.formatter')->format($node->getCreatedTime(), 'medium', '', NULL, $langcode);
           break;
 
         case 'changed':
           $date_format = DateFormat::load('medium');
           $bubbleable_metadata->addCacheableDependency($date_format);
-          $replacements[$original] = format_date($node->getChangedTime(), 'medium', '', NULL, $langcode);
+          $replacements[$original] = \Drupal::service('date.formatter')->format($node->getChangedTime(), 'medium', '', NULL, $langcode);
           break;
       }
     }
diff --git a/core/modules/node/src/Controller/NodeController.php b/core/modules/node/src/Controller/NodeController.php
index 83e7d1f021dd..9fbc3a8a0b28 100644
--- a/core/modules/node/src/Controller/NodeController.php
+++ b/core/modules/node/src/Controller/NodeController.php
@@ -144,7 +144,7 @@ public function revisionShow($node_revision) {
    */
   public function revisionPageTitle($node_revision) {
     $node = $this->entityManager()->getStorage('node')->loadRevision($node_revision);
-    return $this->t('Revision of %title from %date', ['%title' => $node->label(), '%date' => format_date($node->getRevisionCreationTime())]);
+    return $this->t('Revision of %title from %date', ['%title' => $node->label(), '%date' => $this->dateFormatter->format($node->getRevisionCreationTime())]);
   }
 
   /**
diff --git a/core/modules/node/src/Form/NodeRevisionDeleteForm.php b/core/modules/node/src/Form/NodeRevisionDeleteForm.php
index d2145a55fb34..3d5807af3f28 100644
--- a/core/modules/node/src/Form/NodeRevisionDeleteForm.php
+++ b/core/modules/node/src/Form/NodeRevisionDeleteForm.php
@@ -3,6 +3,7 @@
 namespace Drupal\node\Form;
 
 use Drupal\Core\Database\Connection;
+use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
@@ -44,6 +45,13 @@ class NodeRevisionDeleteForm extends ConfirmFormBase {
    */
   protected $connection;
 
+  /**
+   * The date formatter service.
+   *
+   * @var \Drupal\Core\Datetime\DateFormatterInterface
+   */
+  protected $dateFormatter;
+
   /**
    * Constructs a new NodeRevisionDeleteForm.
    *
@@ -53,11 +61,14 @@ class NodeRevisionDeleteForm extends ConfirmFormBase {
    *   The node type storage.
    * @param \Drupal\Core\Database\Connection $connection
    *   The database connection.
+   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
+   *   The date formatter service.
    */
-  public function __construct(EntityStorageInterface $node_storage, EntityStorageInterface $node_type_storage, Connection $connection) {
+  public function __construct(EntityStorageInterface $node_storage, EntityStorageInterface $node_type_storage, Connection $connection, DateFormatterInterface $date_formatter) {
     $this->nodeStorage = $node_storage;
     $this->nodeTypeStorage = $node_type_storage;
     $this->connection = $connection;
+    $this->dateFormatter = $date_formatter;
   }
 
   /**
@@ -68,7 +79,8 @@ public static function create(ContainerInterface $container) {
     return new static(
       $entity_manager->getStorage('node'),
       $entity_manager->getStorage('node_type'),
-      $container->get('database')
+      $container->get('database'),
+      $container->get('date.formatter')
     );
   }
 
@@ -83,7 +95,9 @@ public function getFormId() {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return t('Are you sure you want to delete the revision from %revision-date?', ['%revision-date' => format_date($this->revision->getRevisionCreationTime())]);
+    return t('Are you sure you want to delete the revision from %revision-date?', [
+      '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()),
+    ]);
   }
 
   /**
@@ -120,7 +134,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     $node_type = $this->nodeTypeStorage->load($this->revision->bundle())->label();
     $this->messenger()
       ->addStatus($this->t('Revision from %revision-date of @type %title has been deleted.', [
-        '%revision-date' => format_date($this->revision->getRevisionCreationTime()),
+        '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()),
         '@type' => $node_type,
         '%title' => $this->revision->label(),
       ]));
diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php
index 107f2a01b444..f5380846b7e1 100644
--- a/core/modules/node/src/NodeForm.php
+++ b/core/modules/node/src/NodeForm.php
@@ -3,6 +3,7 @@
 namespace Drupal\node;
 
 use Drupal\Component\Datetime\TimeInterface;
+use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
@@ -32,6 +33,13 @@ class NodeForm extends ContentEntityForm {
    */
   protected $currentUser;
 
+  /**
+   * The date formatter service.
+   *
+   * @var \Drupal\Core\Datetime\DateFormatterInterface
+   */
+  protected $dateFormatter;
+
   /**
    * Constructs a NodeForm object.
    *
@@ -45,11 +53,14 @@ class NodeForm extends ContentEntityForm {
    *   The time service.
    * @param \Drupal\Core\Session\AccountInterface $current_user
    *   The current user.
+   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
+   *   The date formatter service.
    */
-  public function __construct(EntityRepositoryInterface $entity_repository, PrivateTempStoreFactory $temp_store_factory, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL, AccountInterface $current_user) {
+  public function __construct(EntityRepositoryInterface $entity_repository, PrivateTempStoreFactory $temp_store_factory, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL, AccountInterface $current_user, DateFormatterInterface $date_formatter) {
     parent::__construct($entity_repository, $entity_type_bundle_info, $time);
     $this->tempStoreFactory = $temp_store_factory;
     $this->currentUser = $current_user;
+    $this->dateFormatter = $date_formatter;
   }
 
   /**
@@ -61,7 +72,8 @@ public static function create(ContainerInterface $container) {
       $container->get('tempstore.private'),
       $container->get('entity_type.bundle.info'),
       $container->get('datetime.time'),
-      $container->get('current_user')
+      $container->get('current_user'),
+      $container->get('date.formatter')
     );
   }
 
@@ -134,7 +146,7 @@ public function form(array $form, FormStateInterface $form_state) {
     $form['meta']['changed'] = [
       '#type' => 'item',
       '#title' => $this->t('Last saved'),
-      '#markup' => !$node->isNew() ? format_date($node->getChangedTime(), 'short') : $this->t('Not saved yet'),
+      '#markup' => !$node->isNew() ? $this->dateFormatter->format($node->getChangedTime(), 'short') : $this->t('Not saved yet'),
       '#wrapper_attributes' => ['class' => ['entity-meta__last-saved']],
     ];
     $form['meta']['author'] = [
diff --git a/core/modules/node/src/NodeTranslationHandler.php b/core/modules/node/src/NodeTranslationHandler.php
index 8b69645d1f4c..244a0535a260 100644
--- a/core/modules/node/src/NodeTranslationHandler.php
+++ b/core/modules/node/src/NodeTranslationHandler.php
@@ -63,7 +63,7 @@ public function entityFormEntityBuild($entity_type, EntityInterface $entity, arr
       $translation['status'] = $entity->isPublished();
       $account = $entity->uid->entity;
       $translation['uid'] = $account ? $account->id() : 0;
-      $translation['created'] = format_date($entity->created->value, 'custom', 'Y-m-d H:i:s O');
+      $translation['created'] = $this->dateFormatter->format($entity->created->value, 'custom', 'Y-m-d H:i:s O');
     }
     parent::entityFormEntityBuild($entity_type, $entity, $form, $form_state);
   }
diff --git a/core/modules/node/tests/src/Functional/NodeCreationTest.php b/core/modules/node/tests/src/Functional/NodeCreationTest.php
index 0e4a4adb103f..25e741f6c0a0 100644
--- a/core/modules/node/tests/src/Functional/NodeCreationTest.php
+++ b/core/modules/node/tests/src/Functional/NodeCreationTest.php
@@ -61,7 +61,7 @@ public function testNodeCreation() {
     // Verify that pages do not show submitted information by default.
     $this->drupalGet('node/' . $node->id());
     $this->assertNoText($node->getOwner()->getAccountName());
-    $this->assertNoText(format_date($node->getCreatedTime()));
+    $this->assertNoText($this->container->get('date.formatter')->format($node->getCreatedTime()));
 
     // Change the node type setting to show submitted by information.
     /** @var \Drupal\node\NodeTypeInterface $node_type */
@@ -71,7 +71,7 @@ public function testNodeCreation() {
 
     $this->drupalGet('node/' . $node->id());
     $this->assertText($node->getOwner()->getAccountName());
-    $this->assertText(format_date($node->getCreatedTime()));
+    $this->assertText($this->container->get('date.formatter')->format($node->getCreatedTime()));
 
     // Check if the node revision checkbox is not rendered on node creation form.
     $admin_user = $this->drupalCreateUser(['administer nodes', 'create page content']);
diff --git a/core/modules/node/tests/src/Functional/NodeEditFormTest.php b/core/modules/node/tests/src/Functional/NodeEditFormTest.php
index 9c9df5b0ca81..89f891a64317 100644
--- a/core/modules/node/tests/src/Functional/NodeEditFormTest.php
+++ b/core/modules/node/tests/src/Functional/NodeEditFormTest.php
@@ -217,7 +217,7 @@ public function testNodeMetaInformation() {
     $node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
     $this->drupalGet("node/" . $node->id() . "/edit");
     $this->assertNoText('Published');
-    $this->assertNoText(format_date($node->getChangedTime(), 'short'));
+    $this->assertNoText($this->container->get('date.formatter')->format($node->getChangedTime(), 'short'));
 
     // Check that users with the 'administer nodes' permission can see the meta
     // information.
@@ -233,7 +233,7 @@ public function testNodeMetaInformation() {
     $node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
     $this->drupalGet("node/" . $node->id() . "/edit");
     $this->assertText('Published');
-    $this->assertText(format_date($node->getChangedTime(), 'short'));
+    $this->assertText($this->container->get('date.formatter')->format($node->getChangedTime(), 'short'));
   }
 
   /**
diff --git a/core/modules/node/tests/src/Functional/NodeRevisionsAllTest.php b/core/modules/node/tests/src/Functional/NodeRevisionsAllTest.php
index 2226894d6707..e7f7e88aeeac 100644
--- a/core/modules/node/tests/src/Functional/NodeRevisionsAllTest.php
+++ b/core/modules/node/tests/src/Functional/NodeRevisionsAllTest.php
@@ -148,7 +148,7 @@ public function testRevisions() {
       [
         '@type' => 'Basic page',
         '%title' => $nodes[1]->getTitle(),
-        '%revision-date' => format_date($nodes[1]->getRevisionCreationTime()),
+        '%revision-date' => $this->container->get('date.formatter')->format($nodes[1]->getRevisionCreationTime()),
       ]),
       'Revision reverted.');
     $node_storage->resetCache([$node->id()]);
@@ -173,7 +173,7 @@ public function testRevisions() {
     $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", [], t('Delete'));
     $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.',
       [
-        '%revision-date' => format_date($nodes[1]->getRevisionCreationTime()),
+        '%revision-date' => $this->container->get('date.formatter')->format($nodes[1]->getRevisionCreationTime()),
         '@type' => 'Basic page',
         '%title' => $nodes[1]->getTitle(),
       ]),
@@ -196,7 +196,7 @@ public function testRevisions() {
     $this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', [
       '@type' => 'Basic page',
       '%title' => $nodes[2]->getTitle(),
-      '%revision-date' => format_date($old_revision_date),
+      '%revision-date' => $this->container->get('date.formatter')->format($old_revision_date),
     ]));
 
     // Create 50 more revisions in order to trigger paging on the revisions
diff --git a/core/modules/node/tests/src/Functional/NodeRevisionsTest.php b/core/modules/node/tests/src/Functional/NodeRevisionsTest.php
index 9e97012feb8c..d25bb8bf85af 100644
--- a/core/modules/node/tests/src/Functional/NodeRevisionsTest.php
+++ b/core/modules/node/tests/src/Functional/NodeRevisionsTest.php
@@ -164,7 +164,7 @@ public function testRevisions() {
     $this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', [
       '@type' => 'Basic page',
       '%title' => $nodes[1]->label(),
-      '%revision-date' => format_date($nodes[1]->getRevisionCreationTime()),
+      '%revision-date' => $this->container->get('date.formatter')->format($nodes[1]->getRevisionCreationTime()),
     ]), 'Revision reverted.');
     $node_storage->resetCache([$node->id()]);
     $reverted_node = $node_storage->load($node->id());
@@ -181,7 +181,7 @@ public function testRevisions() {
     // Confirm revisions delete properly.
     $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", [], t('Delete'));
     $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.', [
-      '%revision-date' => format_date($nodes[1]->getRevisionCreationTime()),
+      '%revision-date' => $this->container->get('date.formatter')->format($nodes[1]->getRevisionCreationTime()),
       '@type' => 'Basic page',
       '%title' => $nodes[1]->label(),
     ]), 'Revision deleted.');
@@ -202,7 +202,7 @@ public function testRevisions() {
     $this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', [
       '@type' => 'Basic page',
       '%title' => $nodes[2]->label(),
-      '%revision-date' => format_date($old_revision_date),
+      '%revision-date' => $this->container->get('date.formatter')->format($old_revision_date),
     ]));
 
     // Make a new revision and set it to not be default.
diff --git a/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php b/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php
index 0648e5b60010..4b04a77b120d 100644
--- a/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php
+++ b/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php
@@ -112,12 +112,12 @@ public function testNodeRevisionDoubleEscapeFix() {
     $this->drupalGet('node/' . $node->id() . '/revisions');
 
     // Assert the old revision message.
-    $date = format_date($nodes[0]->revision_timestamp->value, 'short');
+    $date = $this->container->get('date.formatter')->format($nodes[0]->revision_timestamp->value, 'short');
     $url = new Url('entity.node.revision', ['node' => $nodes[0]->id(), 'node_revision' => $nodes[0]->getRevisionId()]);
     $this->assertRaw(\Drupal::l($date, $url) . ' by ' . $editor);
 
     // Assert the current revision message.
-    $date = format_date($nodes[1]->revision_timestamp->value, 'short');
+    $date = $this->container->get('date.formatter')->format($nodes[1]->revision_timestamp->value, 'short');
     $this->assertRaw($nodes[1]->toLink($date)->toString() . ' by ' . $editor . '<p class="revision-log">' . $revision_log . '</p>');
   }
 
diff --git a/core/modules/node/tests/src/Functional/NodeTranslationUITest.php b/core/modules/node/tests/src/Functional/NodeTranslationUITest.php
index 2fbee14c3a7e..ffda545d3507 100644
--- a/core/modules/node/tests/src/Functional/NodeTranslationUITest.php
+++ b/core/modules/node/tests/src/Functional/NodeTranslationUITest.php
@@ -196,10 +196,12 @@ protected function doTestAuthoringInfo() {
         'sticky' => (bool) mt_rand(0, 1),
         'promote' => (bool) mt_rand(0, 1),
       ];
+      /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+      $date_formatter = $this->container->get('date.formatter');
       $edit = [
         'uid[0][target_id]' => $user->getAccountName(),
-        'created[0][value][date]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d'),
-        'created[0][value][time]' => format_date($values[$langcode]['created'], 'custom', 'H:i:s'),
+        'created[0][value][date]' => $date_formatter->format($values[$langcode]['created'], 'custom', 'Y-m-d'),
+        'created[0][value][time]' => $date_formatter->format($values[$langcode]['created'], 'custom', 'H:i:s'),
         'sticky[value]' => $values[$langcode]['sticky'],
         'promote[value]' => $values[$langcode]['promote'],
       ];
diff --git a/core/modules/node/tests/src/Kernel/NodeTokenReplaceTest.php b/core/modules/node/tests/src/Kernel/NodeTokenReplaceTest.php
index d4c51bc442e9..016807897d71 100644
--- a/core/modules/node/tests/src/Kernel/NodeTokenReplaceTest.php
+++ b/core/modules/node/tests/src/Kernel/NodeTokenReplaceTest.php
@@ -72,8 +72,10 @@ public function testNodeTokenReplacement() {
     $tests['[node:author]'] = $account->getAccountName();
     $tests['[node:author:uid]'] = $node->getOwnerId();
     $tests['[node:author:name]'] = $account->getAccountName();
-    $tests['[node:created:since]'] = \Drupal::service('date.formatter')->formatTimeDiffSince($node->getCreatedTime(), ['langcode' => $this->interfaceLanguage->getId()]);
-    $tests['[node:changed:since]'] = \Drupal::service('date.formatter')->formatTimeDiffSince($node->getChangedTime(), ['langcode' => $this->interfaceLanguage->getId()]);
+    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+    $date_formatter = $this->container->get('date.formatter');
+    $tests['[node:created:since]'] = $date_formatter->formatTimeDiffSince($node->getCreatedTime(), ['langcode' => $this->interfaceLanguage->getId()]);
+    $tests['[node:changed:since]'] = $date_formatter->formatTimeDiffSince($node->getChangedTime(), ['langcode' => $this->interfaceLanguage->getId()]);
 
     $base_bubbleable_metadata = BubbleableMetadata::createFromObject($node);
 
diff --git a/core/modules/rdf/tests/src/Functional/CommentAttributesTest.php b/core/modules/rdf/tests/src/Functional/CommentAttributesTest.php
index 3266eb6b7f70..b278c35aac38 100644
--- a/core/modules/rdf/tests/src/Functional/CommentAttributesTest.php
+++ b/core/modules/rdf/tests/src/Functional/CommentAttributesTest.php
@@ -278,14 +278,14 @@ public function _testBasicCommentRdfaMarkup($graph, CommentInterface $comment, $
     // Comment date.
     $expected_value = [
       'type' => 'literal',
-      'value' => format_date($comment->getCreatedTime(), 'custom', 'c', 'UTC'),
+      'value' => $this->container->get('date.formatter')->format($comment->getCreatedTime(), 'custom', 'c', 'UTC'),
       'datatype' => 'http://www.w3.org/2001/XMLSchema#dateTime',
     ];
     $this->assertTrue($graph->hasProperty($comment_uri, 'http://purl.org/dc/terms/date', $expected_value), 'Comment date found in RDF output (dc:date).');
     // Comment date.
     $expected_value = [
       'type' => 'literal',
-      'value' => format_date($comment->getCreatedTime(), 'custom', 'c', 'UTC'),
+      'value' => $this->container->get('date.formatter')->format($comment->getCreatedTime(), 'custom', 'c', 'UTC'),
       'datatype' => 'http://www.w3.org/2001/XMLSchema#dateTime',
     ];
     $this->assertTrue($graph->hasProperty($comment_uri, 'http://purl.org/dc/terms/created', $expected_value), 'Comment date found in RDF output (dc:created).');
diff --git a/core/modules/rdf/tests/src/Functional/StandardProfileTest.php b/core/modules/rdf/tests/src/Functional/StandardProfileTest.php
index 083e637e9656..928b2fb48f88 100644
--- a/core/modules/rdf/tests/src/Functional/StandardProfileTest.php
+++ b/core/modules/rdf/tests/src/Functional/StandardProfileTest.php
@@ -358,7 +358,7 @@ protected function assertRdfaCommonNodeProperties($graph, NodeInterface $node, $
     // Created date.
     $expected_value = [
       'type' => 'literal',
-      'value' => format_date($node->get('created')->value, 'custom', 'c', 'UTC'),
+      'value' => $this->container->get('date.formatter')->format($node->get('created')->value, 'custom', 'c', 'UTC'),
       'lang' => 'en',
     ];
     $this->assertTrue($graph->hasProperty($uri, 'http://schema.org/dateCreated', $expected_value), "$message_prefix created date was found (schema:dateCreated) in teaser.");
@@ -447,7 +447,7 @@ protected function assertRdfaNodeCommentProperties($graph) {
     // Comment created date.
     $expected_value = [
       'type' => 'literal',
-      'value' => format_date($this->articleComment->get('created')->value, 'custom', 'c', 'UTC'),
+      'value' => $this->container->get('date.formatter')->format($this->articleComment->get('created')->value, 'custom', 'c', 'UTC'),
       'lang' => 'en',
     ];
     $this->assertTrue($graph->hasProperty($this->articleCommentUri, 'http://schema.org/dateCreated', $expected_value), 'Article comment created date was found (schema:dateCreated).');
diff --git a/core/modules/search/search.pages.inc b/core/modules/search/search.pages.inc
index 703b2ff550ca..85923a8f09a9 100644
--- a/core/modules/search/search.pages.inc
+++ b/core/modules/search/search.pages.inc
@@ -43,7 +43,7 @@ function template_preprocess_search_result(&$variables) {
     $info['user'] = $result['user'];
   }
   if (!empty($result['date'])) {
-    $info['date'] = format_date($result['date'], 'short');
+    $info['date'] = \Drupal::service('date.formatter')->format($result['date'], 'short');
   }
   if (isset($result['extra']) && is_array($result['extra'])) {
     $info = array_merge($info, $result['extra']);
diff --git a/core/modules/search/tests/src/Functional/SearchExactTest.php b/core/modules/search/tests/src/Functional/SearchExactTest.php
index 7eac8ffe328c..94de349ebde5 100644
--- a/core/modules/search/tests/src/Functional/SearchExactTest.php
+++ b/core/modules/search/tests/src/Functional/SearchExactTest.php
@@ -73,7 +73,7 @@ public function testExactQuery() {
     $edit = ['keys' => 'Druplicon'];
     $this->drupalPostForm('search/node', $edit, t('Search'));
     $this->assertText($user->getAccountName(), 'Basic page node displays author name when post settings are on.');
-    $this->assertText(format_date($node->getChangedTime(), 'short'), 'Basic page node displays post date when post settings are on.');
+    $this->assertText($this->container->get('date.formatter')->format($node->getChangedTime(), 'short'), 'Basic page node displays post date when post settings are on.');
 
     // Check that with post settings turned off the user and changed date
     // information is not displayed.
@@ -82,7 +82,7 @@ public function testExactQuery() {
     $edit = ['keys' => 'Druplicon'];
     $this->drupalPostForm('search/node', $edit, t('Search'));
     $this->assertNoText($user->getAccountName(), 'Basic page node does not display author name when post settings are off.');
-    $this->assertNoText(format_date($node->getChangedTime(), 'short'), 'Basic page node does not display post date when post settings are off.');
+    $this->assertNoText($this->container->get('date.formatter')->format($node->getChangedTime(), 'short'), 'Basic page node does not display post date when post settings are off.');
 
   }
 
diff --git a/core/modules/statistics/statistics.tokens.inc b/core/modules/statistics/statistics.tokens.inc
index 96500b898278..056cac45f38f 100644
--- a/core/modules/statistics/statistics.tokens.inc
+++ b/core/modules/statistics/statistics.tokens.inc
@@ -52,7 +52,7 @@ function statistics_tokens($type, $tokens, array $data, array $options, Bubbleab
       }
       elseif ($name == 'last-view') {
         $statistics = statistics_get($node->id());
-        $replacements[$original] = format_date($statistics['timestamp']);
+        $replacements[$original] = \Drupal::service('date.formatter')->format($statistics['timestamp']);
       }
     }
 
diff --git a/core/modules/statistics/tests/src/Functional/StatisticsTokenReplaceTest.php b/core/modules/statistics/tests/src/Functional/StatisticsTokenReplaceTest.php
index 50616af23aad..70f2f4298d2c 100644
--- a/core/modules/statistics/tests/src/Functional/StatisticsTokenReplaceTest.php
+++ b/core/modules/statistics/tests/src/Functional/StatisticsTokenReplaceTest.php
@@ -37,8 +37,10 @@ public function testStatisticsTokenReplacement() {
     $tests = [];
     $tests['[node:total-count]'] = 1;
     $tests['[node:day-count]'] = 1;
-    $tests['[node:last-view]'] = format_date($statistics['timestamp']);
-    $tests['[node:last-view:short]'] = format_date($statistics['timestamp'], 'short');
+    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+    $date_formatter = $this->container->get('date.formatter');
+    $tests['[node:last-view]'] = $date_formatter->format($statistics['timestamp']);
+    $tests['[node:last-view:short]'] = $date_formatter->format($statistics['timestamp'], 'short');
 
     // Test to make sure that we generated something for each token.
     $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
diff --git a/core/modules/system/system.tokens.inc b/core/modules/system/system.tokens.inc
index 55c89ae9f92e..a3a670a00236 100644
--- a/core/modules/system/system.tokens.inc
+++ b/core/modules/system/system.tokens.inc
@@ -49,18 +49,21 @@ function system_token_info() {
     'description' => t("The URL of the site's login page."),
   ];
 
+  /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+  $date_formatter = \Drupal::service('date.formatter');
+
   // Date related tokens.
   $date['short'] = [
     'name' => t("Short format"),
-    'description' => t("A date in 'short' format. (%date)", ['%date' => format_date(REQUEST_TIME, 'short')]),
+    'description' => t("A date in 'short' format. (%date)", ['%date' => $date_formatter->format(REQUEST_TIME, 'short')]),
   ];
   $date['medium'] = [
     'name' => t("Medium format"),
-    'description' => t("A date in 'medium' format. (%date)", ['%date' => format_date(REQUEST_TIME, 'medium')]),
+    'description' => t("A date in 'medium' format. (%date)", ['%date' => $date_formatter->format(REQUEST_TIME, 'medium')]),
   ];
   $date['long'] = [
     'name' => t("Long format"),
-    'description' => t("A date in 'long' format. (%date)", ['%date' => format_date(REQUEST_TIME, 'long')]),
+    'description' => t("A date in 'long' format. (%date)", ['%date' => $date_formatter->format(REQUEST_TIME, 'long')]),
   ];
   $date['custom'] = [
     'name' => t("Custom format"),
@@ -68,7 +71,7 @@ function system_token_info() {
   ];
   $date['since'] = [
     'name' => t("Time-since"),
-    'description' => t("A date in 'time-since' format. (%date)", ['%date' => \Drupal::service('date.formatter')->formatTimeDiffSince(REQUEST_TIME - 360)]),
+    'description' => t("A date in 'time-since' format. (%date)", ['%date' => $date_formatter->formatTimeDiffSince(REQUEST_TIME - 360)]),
   ];
   $date['raw'] = [
     'name' => t("Raw timestamp"),
@@ -169,7 +172,7 @@ function system_tokens($type, $tokens, array $data, array $options, BubbleableMe
         case 'long':
           $date_format = DateFormat::load($name);
           $bubbleable_metadata->addCacheableDependency($date_format);
-          $replacements[$original] = format_date($date, $name, '', NULL, $langcode);
+          $replacements[$original] = \Drupal::service('date.formatter')->format($date, $name, '', NULL, $langcode);
           break;
 
         case 'since':
@@ -185,7 +188,7 @@ function system_tokens($type, $tokens, array $data, array $options, BubbleableMe
 
     if ($created_tokens = $token_service->findWithPrefix($tokens, 'custom')) {
       foreach ($created_tokens as $name => $original) {
-        $replacements[$original] = format_date($date, 'custom', $name, NULL, $langcode);
+        $replacements[$original] = \Drupal::service('date.formatter')->format($date, 'custom', $name, NULL, $langcode);
       }
     }
   }
diff --git a/core/modules/system/tests/src/Functional/Common/FormatDateTest.php b/core/modules/system/tests/src/Functional/Common/FormatDateTest.php
index 062d6f412403..a595db77809d 100644
--- a/core/modules/system/tests/src/Functional/Common/FormatDateTest.php
+++ b/core/modules/system/tests/src/Functional/Common/FormatDateTest.php
@@ -5,14 +5,14 @@
 use Drupal\Tests\BrowserTestBase;
 
 /**
- * Tests the format_date() function.
+ * Tests the DateFormatterInterface::format() function.
  *
  * @group Common
  */
 class FormatDateTest extends BrowserTestBase {
 
   /**
-   * Tests admin-defined formats in format_date().
+   * Tests admin-defined formats in DateFormatterInterface::format().
    */
   public function testAdminDefinedFormatDate() {
     // Create and log in an admin user.
@@ -35,10 +35,13 @@ public function testAdminDefinedFormatDate() {
     $this->drupalPostForm('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
     $this->assertText(t('Custom date format added.'));
 
+    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+    $date_formatter = $this->container->get('date.formatter');
+
     $timestamp = strtotime('2007-03-10T00:00:00+00:00');
-    $this->assertIdentical(format_date($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07');
-    $this->assertIdentical(format_date($timestamp, 'example_style_uppercase', '', 'America/Los_Angeles'), '9 Mar 2007');
-    $this->assertIdentical(format_date($timestamp, 'undefined_style'), format_date($timestamp, 'fallback'), 'Test format_date() defaulting to `fallback` when $type not found.');
+    $this->assertIdentical($date_formatter->format($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07');
+    $this->assertIdentical($date_formatter->format($timestamp, 'example_style_uppercase', '', 'America/Los_Angeles'), '9 Mar 2007');
+    $this->assertIdentical($date_formatter->format($timestamp, 'undefined_style'), $date_formatter->format($timestamp, 'fallback'), 'Test DateFormatterInterface::format() defaulting to `fallback` when $type not found.');
   }
 
 }
diff --git a/core/modules/update/update.report.inc b/core/modules/update/update.report.inc
index e42093cf7a2a..035b46e930b4 100644
--- a/core/modules/update/update.report.inc
+++ b/core/modules/update/update.report.inc
@@ -118,7 +118,7 @@ function template_preprocess_update_project_status(&$variables) {
 
   $variables['install_type'] = $project['install_type'];
   if ($project['install_type'] == 'dev' && !empty($project['datestamp'])) {
-    $variables['datestamp'] = format_date($project['datestamp'], 'custom', 'Y-M-d');
+    $variables['datestamp'] = \Drupal::service('date.formatter')->format($project['datestamp'], 'custom', 'Y-M-d');
   }
 
   $variables['existing_version'] = $project['existing_version'];
diff --git a/core/modules/user/tests/src/Functional/UserTokenReplaceTest.php b/core/modules/user/tests/src/Functional/UserTokenReplaceTest.php
index 774119866bbd..eb566846c8b9 100644
--- a/core/modules/user/tests/src/Functional/UserTokenReplaceTest.php
+++ b/core/modules/user/tests/src/Functional/UserTokenReplaceTest.php
@@ -55,6 +55,9 @@ public function testUserTokenReplacement() {
     $account = User::load($user1->id());
     $global_account = User::load(\Drupal::currentUser()->id());
 
+    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+    $date_formatter = $this->container->get('date.formatter');
+
     // Generate and test tokens.
     $tests = [];
     $tests['[user:uid]'] = $account->id();
@@ -64,10 +67,10 @@ public function testUserTokenReplacement() {
     $tests['[user:mail]'] = $account->getEmail();
     $tests['[user:url]'] = $account->toUrl('canonical', $url_options)->toString();
     $tests['[user:edit-url]'] = $account->toUrl('edit-form', $url_options)->toString();
-    $tests['[user:last-login]'] = format_date($account->getLastLoginTime(), 'medium', '', NULL, $language_interface->getId());
-    $tests['[user:last-login:short]'] = format_date($account->getLastLoginTime(), 'short', '', NULL, $language_interface->getId());
-    $tests['[user:created]'] = format_date($account->getCreatedTime(), 'medium', '', NULL, $language_interface->getId());
-    $tests['[user:created:short]'] = format_date($account->getCreatedTime(), 'short', '', NULL, $language_interface->getId());
+    $tests['[user:last-login]'] = $date_formatter->format($account->getLastLoginTime(), 'medium', '', NULL, $language_interface->getId());
+    $tests['[user:last-login:short]'] = $date_formatter->format($account->getLastLoginTime(), 'short', '', NULL, $language_interface->getId());
+    $tests['[user:created]'] = $date_formatter->format($account->getCreatedTime(), 'medium', '', NULL, $language_interface->getId());
+    $tests['[user:created:short]'] = $date_formatter->format($account->getCreatedTime(), 'short', '', NULL, $language_interface->getId());
     $tests['[current-user:name]'] = $global_account->getAccountName();
     $tests['[current-user:account-name]'] = $global_account->getAccountName();
     $tests['[current-user:display-name]'] = $global_account->getDisplayName();
diff --git a/core/modules/user/user.tokens.inc b/core/modules/user/user.tokens.inc
index df1e1443d85f..9baf90d10ebd 100644
--- a/core/modules/user/user.tokens.inc
+++ b/core/modules/user/user.tokens.inc
@@ -129,14 +129,14 @@ function user_tokens($type, $tokens, array $data, array $options, BubbleableMeta
         case 'last-login':
           $date_format = DateFormat::load('medium');
           $bubbleable_metadata->addCacheableDependency($date_format);
-          $replacements[$original] = $account->getLastLoginTime() ? format_date($account->getLastLoginTime(), 'medium', '', NULL, $langcode) : t('never');
+          $replacements[$original] = $account->getLastLoginTime() ? \Drupal::service('date.formatter')->format($account->getLastLoginTime(), 'medium', '', NULL, $langcode) : t('never');
           break;
 
         case 'created':
           $date_format = DateFormat::load('medium');
           $bubbleable_metadata->addCacheableDependency($date_format);
           // In the case of user_presave the created date may not yet be set.
-          $replacements[$original] = $account->getCreatedTime() ? format_date($account->getCreatedTime(), 'medium', '', NULL, $langcode) : t('not yet created');
+          $replacements[$original] = $account->getCreatedTime() ? \Drupal::service('date.formatter')->format($account->getCreatedTime(), 'medium', '', NULL, $langcode) : t('not yet created');
           break;
       }
     }
diff --git a/core/modules/views/src/Plugin/views/argument/Date.php b/core/modules/views/src/Plugin/views/argument/Date.php
index a751d561b7dc..852e21f04b19 100644
--- a/core/modules/views/src/Plugin/views/argument/Date.php
+++ b/core/modules/views/src/Plugin/views/argument/Date.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\views\Plugin\views\argument;
 
+use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
@@ -49,6 +50,13 @@ class Date extends Formula implements ContainerFactoryPluginInterface {
    */
   protected $routeMatch;
 
+  /**
+   * The date formatter service.
+   *
+   * @var \Drupal\Core\Datetime\DateFormatterInterface
+   */
+  protected $dateFormatter;
+
   /**
    * Constructs a new Date instance.
    *
@@ -58,14 +66,16 @@ class Date extends Formula implements ContainerFactoryPluginInterface {
    *   The plugin_id for the plugin instance.
    * @param mixed $plugin_definition
    *   The plugin implementation definition.
-   *
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
    *   The route match.
+   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
+   *   The date formatter service.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match, DateFormatterInterface $date_formatter) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     $this->routeMatch = $route_match;
+    $this->dateFormatter = $date_formatter;
   }
 
   /**
@@ -76,7 +86,8 @@ public static function create(ContainerInterface $container, array $configuratio
       $configuration,
       $plugin_id,
       $plugin_definition,
-      $container->get('current_route_match')
+      $container->get('current_route_match'),
+      $container->get('date.formatter')
     );
   }
 
diff --git a/core/modules/views/src/Plugin/views/argument/DayDate.php b/core/modules/views/src/Plugin/views/argument/DayDate.php
index 42bd81743c29..369ff0fe4b58 100644
--- a/core/modules/views/src/Plugin/views/argument/DayDate.php
+++ b/core/modules/views/src/Plugin/views/argument/DayDate.php
@@ -20,20 +20,20 @@ class DayDate extends Date {
   protected $argFormat = 'd';
 
   /**
-   * Provide a link to the next level of the view
+   * {@inheritdoc}
    */
   public function summaryName($data) {
     $day = str_pad($data->{$this->name_alias}, 2, '0', STR_PAD_LEFT);
     // strtotime respects server timezone, so we need to set the time fixed as utc time
-    return format_date(strtotime("2005" . "05" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
+    return $this->dateFormatter->format(strtotime("2005" . "05" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
   }
 
   /**
-   * Provide a link to the next level of the view
+   * {@inheritdoc}
    */
   public function title() {
     $day = str_pad($this->argument, 2, '0', STR_PAD_LEFT);
-    return format_date(strtotime("2005" . "05" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
+    return $this->dateFormatter->format(strtotime("2005" . "05" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
   }
 
   public function summaryArgument($data) {
diff --git a/core/modules/views/src/Plugin/views/argument/FullDate.php b/core/modules/views/src/Plugin/views/argument/FullDate.php
index ca4ca9f60d12..8114d8302f5a 100644
--- a/core/modules/views/src/Plugin/views/argument/FullDate.php
+++ b/core/modules/views/src/Plugin/views/argument/FullDate.php
@@ -20,18 +20,18 @@ class FullDate extends Date {
   protected $argFormat = 'Ymd';
 
   /**
-   * Provide a link to the next level of the view
+   * {@inheritdoc}
    */
   public function summaryName($data) {
     $created = $data->{$this->name_alias};
-    return format_date(strtotime($created . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
+    return $this->dateFormatter->format(strtotime($created . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
   }
 
   /**
-   * Provide a link to the next level of the view
+   * {@inheritdoc}
    */
   public function title() {
-    return format_date(strtotime($this->argument . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
+    return $this->dateFormatter->format(strtotime($this->argument . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
   }
 
 }
diff --git a/core/modules/views/src/Plugin/views/argument/MonthDate.php b/core/modules/views/src/Plugin/views/argument/MonthDate.php
index a22824df8c2d..941457f822dd 100644
--- a/core/modules/views/src/Plugin/views/argument/MonthDate.php
+++ b/core/modules/views/src/Plugin/views/argument/MonthDate.php
@@ -20,19 +20,19 @@ class MonthDate extends Date {
   protected $argFormat = 'm';
 
   /**
-   * Provide a link to the next level of the view
+   * {@inheritdoc}
    */
   public function summaryName($data) {
     $month = str_pad($data->{$this->name_alias}, 2, '0', STR_PAD_LEFT);
-    return format_date(strtotime("2005" . $month . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
+    return $this->dateFormatter->format(strtotime("2005" . $month . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
   }
 
   /**
-   * Provide a link to the next level of the view
+   * {@inheritdoc}
    */
   public function title() {
     $month = str_pad($this->argument, 2, '0', STR_PAD_LEFT);
-    return format_date(strtotime("2005" . $month . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
+    return $this->dateFormatter->format(strtotime("2005" . $month . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
   }
 
   public function summaryArgument($data) {
diff --git a/core/modules/views/src/Plugin/views/argument/YearMonthDate.php b/core/modules/views/src/Plugin/views/argument/YearMonthDate.php
index 1e1effe1c73b..781c8be98edf 100644
--- a/core/modules/views/src/Plugin/views/argument/YearMonthDate.php
+++ b/core/modules/views/src/Plugin/views/argument/YearMonthDate.php
@@ -20,18 +20,18 @@ class YearMonthDate extends Date {
   protected $argFormat = 'Ym';
 
   /**
-   * Provide a link to the next level of the view
+   * {@inheritdoc}
    */
   public function summaryName($data) {
     $created = $data->{$this->name_alias};
-    return format_date(strtotime($created . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
+    return $this->dateFormatter->format(strtotime($created . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
   }
 
   /**
-   * Provide a link to the next level of the view
+   * {@inheritdoc}
    */
   public function title() {
-    return format_date(strtotime($this->argument . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
+    return $this->dateFormatter->format(strtotime($this->argument . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC');
   }
 
 }
diff --git a/core/modules/views/src/Plugin/views/field/Date.php b/core/modules/views/src/Plugin/views/field/Date.php
index ee38a4a6c3d0..aff879c5d53a 100644
--- a/core/modules/views/src/Plugin/views/field/Date.php
+++ b/core/modules/views/src/Plugin/views/field/Date.php
@@ -171,12 +171,12 @@ public function render(ResultRow $values) {
 
         case 'custom':
           if ($custom_format == 'r') {
-            return format_date($value, $format, $custom_format, $timezone, 'en');
+            return $this->dateFormatter->format($value, $format, $custom_format, $timezone, 'en');
           }
-          return format_date($value, $format, $custom_format, $timezone);
+          return $this->dateFormatter->format($value, $format, $custom_format, $timezone);
 
         default:
-          return format_date($value, $format, '', $timezone);
+          return $this->dateFormatter->format($value, $format, '', $timezone);
       }
     }
   }
diff --git a/core/modules/views/tests/src/Functional/Handler/FilterDateTest.php b/core/modules/views/tests/src/Functional/Handler/FilterDateTest.php
index ff408ff9ec8f..90bddc5f7a7d 100644
--- a/core/modules/views/tests/src/Functional/Handler/FilterDateTest.php
+++ b/core/modules/views/tests/src/Functional/Handler/FilterDateTest.php
@@ -31,8 +31,16 @@ class FilterDateTest extends ViewTestBase {
    */
   public static $modules = ['node', 'views_ui', 'datetime'];
 
+  /**
+   * The date formatter.
+   *
+   * @var \Drupal\Core\Datetime\DateFormatterInterface
+   */
+  public $dateFormatter;
+
   protected function setUp($import_test_views = TRUE) {
     parent::setUp($import_test_views);
+    $this->dateFormatter = $this->container->get('date.formatter');
 
     // Add a date field so we can test datetime handling.
     NodeType::create([
@@ -119,8 +127,8 @@ protected function _testBetween() {
     // Test between with min and max.
     $view->initHandlers();
     $view->filter['created']->operator = 'between';
-    $view->filter['created']->value['min'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
-    $view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
+    $view->filter['created']->value['min'] = $this->dateFormatter->format(150000, 'custom', 'Y-m-d H:i:s');
+    $view->filter['created']->value['max'] = $this->dateFormatter->format(200000, 'custom', 'Y-m-d H:i:s');
     $view->executeDisplay('default');
     $expected_result = [
       ['nid' => $this->nodes[1]->id()],
@@ -131,7 +139,7 @@ protected function _testBetween() {
     // Test between with just max.
     $view->initHandlers();
     $view->filter['created']->operator = 'between';
-    $view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
+    $view->filter['created']->value['max'] = $this->dateFormatter->format(200000, 'custom', 'Y-m-d H:i:s');
     $view->executeDisplay('default');
     $expected_result = [
       ['nid' => $this->nodes[0]->id()],
@@ -143,8 +151,8 @@ protected function _testBetween() {
     // Test not between with min and max.
     $view->initHandlers();
     $view->filter['created']->operator = 'not between';
-    $view->filter['created']->value['min'] = format_date(100000, 'custom', 'Y-m-d H:i:s');
-    $view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
+    $view->filter['created']->value['min'] = $this->dateFormatter->format(100000, 'custom', 'Y-m-d H:i:s');
+    $view->filter['created']->value['max'] = $this->dateFormatter->format(200000, 'custom', 'Y-m-d H:i:s');
 
     $view->executeDisplay('default');
     $expected_result = [
@@ -157,7 +165,7 @@ protected function _testBetween() {
     // Test not between with just max.
     $view->initHandlers();
     $view->filter['created']->operator = 'not between';
-    $view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
+    $view->filter['created']->value['max'] = $this->dateFormatter->format(200000, 'custom', 'Y-m-d H:i:s');
     $view->executeDisplay('default');
     $expected_result = [
       ['nid' => $this->nodes[2]->id()],
@@ -204,8 +212,8 @@ protected function _testFilterDateUI() {
     $edit['options[group_info][group_items][2][value][max]'] = '+2 days';
     $edit['options[group_info][group_items][3][title]'] = 'between-date';
     $edit['options[group_info][group_items][3][operator]'] = 'between';
-    $edit['options[group_info][group_items][3][value][min]'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
-    $edit['options[group_info][group_items][3][value][max]'] = format_date(250000, 'custom', 'Y-m-d H:i:s');
+    $edit['options[group_info][group_items][3][value][min]'] = $this->dateFormatter->format(150000, 'custom', 'Y-m-d H:i:s');
+    $edit['options[group_info][group_items][3][value][max]'] = $this->dateFormatter->format(250000, 'custom', 'Y-m-d H:i:s');
 
     $this->drupalPostForm(NULL, $edit, t('Apply'));
 
@@ -250,7 +258,7 @@ protected function _testFilterDateUI() {
     $edit = [];
     $edit['options[operator]'] = '>';
     $edit['options[value][type]'] = 'date';
-    $edit['options[value][value]'] = format_date(350000, 'custom', 'Y-m-d H:i:s');
+    $edit['options[value][value]'] = $this->dateFormatter->format(350000, 'custom', 'Y-m-d H:i:s');
     $this->drupalPostForm(NULL, $edit, t('Apply'));
     $this->drupalPostForm('admin/structure/views/view/test_filter_date_between', [], t('Save'));
     $this->assertConfigSchemaByName('views.view.test_filter_date_between');
@@ -260,7 +268,9 @@ protected function _testFilterDateUI() {
     $results = $this->cssSelect('.view-content .field-content');
     $this->assertEqual(count($results), 1);
     $this->assertEqual($results[0]->getText(), $this->nodes[3]->id());
-    $this->drupalPostForm(NULL, ['created' => format_date(250000, 'custom', 'Y-m-d H:i:s')], 'Apply');
+    $this->drupalPostForm(NULL, [
+      'created' => $this->dateFormatter->format(250000, 'custom', 'Y-m-d H:i:s'),
+    ], 'Apply');
     $results = $this->cssSelect('.view-content .field-content');
     $this->assertEqual(count($results), 2);
     $this->assertEqual($results[0]->getText(), $this->nodes[2]->id());
@@ -289,8 +299,8 @@ protected function _testFilterDatetimeUI() {
     $edit['options[group_info][group_items][2][value][max]'] = '+2 days';
     $edit['options[group_info][group_items][3][title]'] = 'between-date';
     $edit['options[group_info][group_items][3][operator]'] = 'between';
-    $edit['options[group_info][group_items][3][value][min]'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
-    $edit['options[group_info][group_items][3][value][max]'] = format_date(250000, 'custom', 'Y-m-d H:i:s');
+    $edit['options[group_info][group_items][3][value][min]'] = $this->dateFormatter->format(150000, 'custom', 'Y-m-d H:i:s');
+    $edit['options[group_info][group_items][3][value][max]'] = $this->dateFormatter->format(250000, 'custom', 'Y-m-d H:i:s');
 
     $this->drupalPostForm(NULL, $edit, t('Apply'));
 
diff --git a/core/modules/views/tests/src/Kernel/Handler/FieldDateTest.php b/core/modules/views/tests/src/Kernel/Handler/FieldDateTest.php
index 833b5c99d193..caa12a98e592 100644
--- a/core/modules/views/tests/src/Kernel/Handler/FieldDateTest.php
+++ b/core/modules/views/tests/src/Kernel/Handler/FieldDateTest.php
@@ -96,27 +96,30 @@ public function testFieldDate() {
       'America/New_York',
     ];
 
+    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
+    $date_formatter = $this->container->get('date.formatter');
+
     // Check each date/time in various timezones.
     foreach ($timezones as $timezone) {
       $dates = [
-        'short' => format_date($time, 'short', '', $timezone),
-        'medium' => format_date($time, 'medium', '', $timezone),
-        'long' => format_date($time, 'long', '', $timezone),
-        'custom' => format_date($time, 'custom', 'c', $timezone),
-        'fallback' => format_date($time, 'fallback', '', $timezone),
-        'html_date' => format_date($time, 'html_date', '', $timezone),
-        'html_datetime' => format_date($time, 'html_datetime', '', $timezone),
-        'html_month' => format_date($time, 'html_month', '', $timezone),
-        'html_time' => format_date($time, 'html_time', '', $timezone),
-        'html_week' => format_date($time, 'html_week', '', $timezone),
-        'html_year' => format_date($time, 'html_year', '', $timezone),
-        'html_yearless_date' => format_date($time, 'html_yearless_date', '', $timezone),
+        'short' => $date_formatter->format($time, 'short', '', $timezone),
+        'medium' => $date_formatter->format($time, 'medium', '', $timezone),
+        'long' => $date_formatter->format($time, 'long', '', $timezone),
+        'custom' => $date_formatter->format($time, 'custom', 'c', $timezone),
+        'fallback' => $date_formatter->format($time, 'fallback', '', $timezone),
+        'html_date' => $date_formatter->format($time, 'html_date', '', $timezone),
+        'html_datetime' => $date_formatter->format($time, 'html_datetime', '', $timezone),
+        'html_month' => $date_formatter->format($time, 'html_month', '', $timezone),
+        'html_time' => $date_formatter->format($time, 'html_time', '', $timezone),
+        'html_week' => $date_formatter->format($time, 'html_week', '', $timezone),
+        'html_year' => $date_formatter->format($time, 'html_year', '', $timezone),
+        'html_yearless_date' => $date_formatter->format($time, 'html_yearless_date', '', $timezone),
       ];
       $this->assertRenderedDatesEqual($view, $dates, $timezone);
     }
 
     // Check times in the past.
-    $time_since = $this->container->get('date.formatter')->formatTimeDiffSince($time);
+    $time_since = $date_formatter->formatTimeDiffSince($time);
     $intervals = [
       'raw time ago' => $time_since,
       'time ago' => t('%time ago', ['%time' => $time_since]),
@@ -128,7 +131,7 @@ public function testFieldDate() {
 
     // Check times in the future.
     $time = gmmktime(0, 0, 0, 1, 1, 2050);
-    $formatted = $this->container->get('date.formatter')->formatTimeDiffUntil($time);
+    $formatted = $date_formatter->formatTimeDiffUntil($time);
     $intervals = [
       'raw time span' => "-$formatted",
       'time span' => t('%time hence', [
diff --git a/core/tests/Drupal/KernelTests/Core/Common/LegacyFunctionsTest.php b/core/tests/Drupal/KernelTests/Core/Common/LegacyFunctionsTest.php
new file mode 100644
index 000000000000..8e1d1acbb206
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Common/LegacyFunctionsTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Common;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests legacy functions in common.inc
+ *
+ * @group Common
+ * @group legacy
+ */
+class LegacyFunctionsTest extends KernelTestBase {
+
+  /**
+   * Tests format_date().
+   *
+   * @expectedDeprecation format_date() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal::service('date.formatter')->format() instead. See https://www.drupal.org/node/1876852
+   */
+  public function testFormatDate() {
+    // Provide arguments otherwise the system module configuration is required.
+    $date = format_date(0, 'custom', 'Y-m-d');
+    $this->assertEquals('1970-01-01', $date);
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Datetime/FormatDateTest.php b/core/tests/Drupal/KernelTests/Core/Datetime/DateFormatterTest.php
similarity index 96%
rename from core/tests/Drupal/KernelTests/Core/Datetime/FormatDateTest.php
rename to core/tests/Drupal/KernelTests/Core/Datetime/DateFormatterTest.php
index 036b385ae43a..06e312383da5 100644
--- a/core/tests/Drupal/KernelTests/Core/Datetime/FormatDateTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Datetime/DateFormatterTest.php
@@ -9,8 +9,9 @@
  * Tests date formatting.
  *
  * @group Common
+ * @coversDefaultClass \Drupal\Core\Datetime\DateFormatter
  */
-class FormatDateTest extends KernelTestBase {
+class DateFormatterTest extends KernelTestBase {
 
   /**
    * {@inheritdoc}
@@ -46,9 +47,11 @@ protected function setUp() {
   }
 
   /**
-   * Tests the format_date() function.
+   * Tests DateFormatter::format().
+   *
+   * @covers ::format
    */
-  public function testFormatDate() {
+  public function testFormat() {
     /** @var \Drupal\Core\Datetime\DateFormatterInterface $formatter */
     $formatter = $this->container->get('date.formatter');
     /** @var \Drupal\Core\Language\LanguageManagerInterface $language_manager */
-- 
GitLab