diff --git a/core/includes/common.inc b/core/includes/common.inc
index 1980f2fbe2af23f50bc7b2e92c28404ec90875b8..48db270314bed50b821d21581403c471814e9db0 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -3192,7 +3192,7 @@ function drupal_page_set_cache(Response $response, Request $request) {
 
      // Use the actual timestamp from an Expires header, if available.
     if ($date = $response->getExpires()) {
-      $date = new DrupalDateTime($date);
+      $date = DrupalDateTime::createFromDateTime($date);
       $cache->expire = $date->getTimestamp();
     }
 
diff --git a/core/lib/Drupal/Component/Datetime/DateTimePlus.php b/core/lib/Drupal/Component/Datetime/DateTimePlus.php
index b00124bbbd81d385520ddcaa14964885a09fc6e9..cda7f3eaf88929ced0ccfa24c7e9182a50b29f8d 100644
--- a/core/lib/Drupal/Component/Datetime/DateTimePlus.php
+++ b/core/lib/Drupal/Component/Datetime/DateTimePlus.php
@@ -106,21 +106,85 @@ class DateTimePlus extends \DateTime {
   protected $errors = array();
 
   /**
-   * Constructs a date object set to a requested date and timezone.
+   * A boolean to store whether or not the intl php extension is available.
+   */
+  static $intlExtentionExists = NULL;
+
+  /**
+   * Creates a date object from an input date object.
    *
-   * @param mixed $time
-   *   A DateTime object, a date/time string, a unix timestamp,
-   *   or an array of date parts, like ('year' => 2014, 'month => 4).
-   *   Defaults to 'now'.
+   * @param \DateTime $datetime
+   *   A DateTime object.
+   * @param array $settings
+   *   @see __construct()
+   */
+  public static function createFromDateTime(\DateTime $datetime, $settings = array()) {
+    return new static($datetime->format(static::FORMAT), $datetime->getTimezone(), $settings);
+  }
+
+  /**
+   * Creates a date object from an array of date parts.
+   *
+   * Converts the input value into an ISO date, forcing a full ISO
+   * date even if some values are missing.
+   *
+   * @param array $date_parts
+   *   An array of date parts, like ('year' => 2014, 'month => 4).
    * @param mixed $timezone
-   *   PHP DateTimeZone object, string or NULL allowed.
-   *   Defaults to NULL.
+   *   @see __construct()
+   * @param array $settings
+   *   @see __construct()
+   */
+  public static function createFromArray(array $date_parts, $timezone = NULL, $settings = array()) {
+    $date_parts = static::prepareArray($date_parts, TRUE);
+    if (static::checkArray($date_parts)) {
+      // Even with validation, we can end up with a value that the
+      // parent class won't handle, like a year outside the range
+      // of -9999 to 9999, which will pass checkdate() but
+      // fail to construct a date object.
+      $iso_date = static::arrayToISO($date_parts);
+      return new static($iso_date, $timezone, $settings);
+    }
+    else {
+      throw new \Exception('The array contains invalid values.');
+    }
+  }
+
+  /**
+   * Creates a date object from timestamp input.
+   *
+   * The timezone of a timestamp is always UTC. The timezone for a
+   * timestamp indicates the timezone used by the format() method.
+   *
+   * @param int $timestamp
+   *   A UNIX timestamp.
+   * @param mixed $timezone
+   *   @see __construct()
+   * @param array $settings
+   *   @see __construct()
+   */
+  public static function createFromTimestamp($timestamp, $timezone = NULL, $settings = array()) {
+    if (!is_numeric($timestamp)) {
+      throw new \Exception('The timestamp must be numeric.');
+    }
+    $datetime = new static('', $timezone, $settings);
+    $datetime->setTimestamp($timestamp);
+    return $datetime;
+  }
+
+  /**
+   * Creates a date object from an input format.
+   *
    * @param string $format
    *   PHP date() type format for parsing the input. This is recommended
-   *   for specialized input with a known format. If provided the
+   *   to use things like negative years, which php's parser fails on, or
+   *   any other specialized input with a known format. If provided the
    *   date will be created using the createFromFormat() method.
-   *   Defaults to NULL.
    *   @see http://us3.php.net/manual/en/datetime.createfromformat.php
+   * @param mixed $time
+   *   @see __construct()
+   * @param mixed $timezone
+   *   @see __construct()
    * @param array $settings
    *   - validate_format: (optional) Boolean choice to validate the
    *     created date using the input format. The format used in
@@ -129,6 +193,47 @@ class DateTimePlus extends \DateTime {
    *     possible to a validation step to confirm that the date created
    *     from a format string exactly matches the input. This option
    *     indicates the format can be used for validation. Defaults to TRUE.
+   *   @see __construct()
+   */
+  public static function createFromFormat($format, $time, $timezone = NULL, $settings = array()) {
+    if (!isset($settings['validate_format'])) {
+      $settings['validate_format'] = TRUE;
+    }
+
+    // Tries to create a date from the format and use it if possible.
+    // A regular try/catch won't work right here, if the value is
+    // invalid it doesn't return an exception.
+    $datetimeplus = new static('', $timezone, $settings);
+
+    $date = \DateTime::createFromFormat($format, $time, $datetimeplus->getTimezone());
+    if (!$date instanceOf \DateTime) {
+      throw new \Exception('The date cannot be created from a format.');
+    }
+    else {
+      $datetimeplus->setTimestamp($date->getTimestamp());
+      $datetimeplus->setTimezone($date->getTimezone());
+
+      // The createFromFormat function is forgiving, it might create a date that
+      // is not exactly a match for the provided value, so test for that. For
+      // instance, an input value of '11' using a format of Y (4 digits) gets
+      // created as '0011' instead of '2011'. Use the parent::format() because
+      // we do not want to use the IntlDateFormatter here.
+      if ($settings['validate_format'] && $date->format($format) != $time) {
+        throw new \Exception('The created date does not match the input value.');
+      }
+    }
+    return $datetimeplus;
+  }
+
+  /**
+   * Constructs a date object set to a requested date and timezone.
+   *
+   * @param string $time
+   *   A date/time string. Defaults to 'now'.
+   * @param mixed $timezone
+   *   PHP DateTimeZone object, string or NULL allowed.
+   *   Defaults to NULL.
+   * @param array $settings
    *   - langcode: (optional) String two letter language code to construct
    *     the locale string by the intlDateFormatter class. Used to control
    *     the result of the format() method if that class is available.
@@ -142,66 +247,36 @@ class DateTimePlus extends \DateTime {
    *   - debug: (optional) Boolean choice to leave debug values in the
    *     date object for debugging purposes. Defaults to FALSE.
    */
-  public function __construct($time = 'now', $timezone = NULL, $format = NULL, $settings = array()) {
+  public function __construct($time = 'now', $timezone = NULL, $settings = array()) {
 
     // Unpack settings.
-    $this->validateFormat = !empty($settings['validate_format']) ? $settings['validate_format'] : TRUE;
     $this->langcode = !empty($settings['langcode']) ? $settings['langcode'] : NULL;
     $this->country = !empty($settings['country']) ? $settings['country'] : NULL;
     $this->calendar = !empty($settings['calendar']) ? $settings['calendar'] : static::CALENDAR;
 
-    // Store the original input so it is available for validation.
-    $this->inputTimeRaw = $time;
-    $this->inputTimeZoneRaw = $timezone;
-    $this->inputFormatRaw = $format;
-
     // Massage the input values as necessary.
-    $this->prepareTime($time);
-    $this->prepareTimezone($timezone);
-    $this->prepareFormat($format);
-
-    // Create a date as a clone of an input DateTime object.
-    if ($this->inputIsObject()) {
-      $this->constructFromObject();
-    }
+    $prepared_time = $this->prepareTime($time);
+    $prepared_timezone = $this->prepareTimezone($timezone);
 
-    // Create date from array of date parts.
-    elseif ($this->inputIsArray()) {
-      $this->constructFromArray();
-    }
-
-    // Create a date from a Unix timestamp.
-    elseif ($this->inputIsTimestamp()) {
-      $this->constructFromTimestamp();
-    }
+    try {
+      if (!empty($prepared_time)) {
+        $test = date_parse($prepared_time);
+        if (!empty($test['errors'])) {
+          $this->errors[] = $test['errors'];
+        }
+      }
 
-    // Create a date from a time string and an expected format.
-    elseif ($this->inputIsFormat()) {
-      $this->constructFromFormat();
+      if (empty($this->errors)) {
+        parent::__construct($prepared_time, $prepared_timezone);
+      }
     }
-
-    // Create a date from any other input.
-    else {
-      $this->constructFallback();
+    catch (\Exception $e) {
+      $this->errors[] = $e->getMessage();
     }
 
     // Clean up the error messages.
     $this->checkErrors();
     $this->errors = array_unique($this->errors);
-
-    // Now that we've validated the input, clean up the extra values.
-    if (empty($settings['debug'])) {
-      unset(
-        $this->inputTimeRaw,
-        $this->inputTimeAdjusted,
-        $this->inputTimeZoneRaw,
-        $this->inputTimeZoneAdjusted,
-        $this->inputFormatRaw,
-        $this->inputFormatAdjusted,
-        $this->validateFormat
-      );
-    }
-
   }
 
   /**
@@ -228,7 +303,7 @@ public function __toString() {
    *   or an array of date parts.
    */
   protected function prepareTime($time) {
-    $this->inputTimeAdjusted = $time;
+    return $time;
   }
 
   /**
@@ -247,12 +322,6 @@ protected function prepareTimezone($timezone) {
       $timezone_adjusted = $timezone;
     }
 
-    // When the passed-in time is a DateTime object with its own
-    // timezone, try to use the date's timezone.
-    elseif (empty($timezone) && $this->inputTimeAdjusted instanceOf \DateTime) {
-      $timezone_adjusted = $this->inputTimeAdjusted->getTimezone();
-    }
-
     // Allow string timezone input, and create a timezone from it.
     elseif (!empty($timezone) && is_string($timezone)) {
       $timezone_adjusted = new \DateTimeZone($timezone);
@@ -267,7 +336,7 @@ protected function prepareTimezone($timezone) {
     }
 
     // We are finally certain that we have a usable timezone.
-    $this->inputTimeZoneAdjusted = $timezone_adjusted;
+    return $timezone_adjusted;
   }
 
   /**
@@ -280,179 +349,10 @@ protected function prepareTimezone($timezone) {
    *   A PHP format string.
    */
   protected function prepareFormat($format) {
-    $this->inputFormatAdjusted = $format;
-  }
-
-  /**
-   * Checks whether input is a DateTime object.
-   *
-   * @return boolean
-   *   TRUE if the input time is a DateTime object.
-   */
-  public function inputIsObject() {
-    return $this->inputTimeAdjusted instanceOf \DateTime;
-  }
-
-  /**
-   * Creates a date object from an input date object.
-   */
-  protected function constructFromObject() {
-    try {
-      $this->inputTimeAdjusted = $this->inputTimeAdjusted->format(static::FORMAT);
-      parent::__construct($this->inputTimeAdjusted, $this->inputTimeZoneAdjusted);
-    }
-    catch (\Exception $e) {
-      $this->errors[] = $e->getMessage();
-    }
+    return $format;
   }
 
-  /**
-   * Checks whether input time seems to be a timestamp.
-   *
-   * Providing an input format will prevent ISO values without separators
-   * from being mis-interpreted as timestamps. Providing a format can also
-   * avoid interpreting a value like '2010' with a format of 'Y' as a
-   * timestamp. The 'U' format indicates this is a timestamp.
-   *
-   * @return boolean
-   *   TRUE if the input time is a timestamp.
-   */
-  public function inputIsTimestamp() {
-    return is_numeric($this->inputTimeAdjusted) && (empty($this->inputFormatAdjusted) || $this->inputFormatAdjusted == 'U');
-  }
 
-  /**
-   * Creates a date object from timestamp input.
-   *
-   * The timezone of a timestamp is always UTC. The timezone for a
-   * timestamp indicates the timezone used by the format() method.
-   */
-  protected function constructFromTimestamp() {
-    try {
-      parent::__construct('', $this->inputTimeZoneAdjusted);
-      $this->setTimestamp($this->inputTimeAdjusted);
-    }
-    catch (\Exception $e) {
-      $this->errors[] = $e->getMessage();
-    }
-  }
-
-  /**
-   * Checks if input is an array of date parts.
-   *
-   * @return boolean
-   *   TRUE if the input time is a DateTime object.
-   */
-  public function inputIsArray() {
-    return is_array($this->inputTimeAdjusted);
-  }
-
-  /**
-   * Creates a date object from an array of date parts.
-   *
-   * Converts the input value into an ISO date, forcing a full ISO
-   * date even if some values are missing.
-   */
-  protected function constructFromArray() {
-    try {
-      parent::__construct('', $this->inputTimeZoneAdjusted);
-      $this->inputTimeAdjusted = static::prepareArray($this->inputTimeAdjusted, TRUE);
-      if (static::checkArray($this->inputTimeAdjusted)) {
-        // Even with validation, we can end up with a value that the
-        // parent class won't handle, like a year outside the range
-        // of -9999 to 9999, which will pass checkdate() but
-        // fail to construct a date object.
-        $this->inputTimeAdjusted = static::arrayToISO($this->inputTimeAdjusted);
-        parent::__construct($this->inputTimeAdjusted, $this->inputTimeZoneAdjusted);
-      }
-      else {
-        throw new \Exception('The array contains invalid values.');
-      }
-    }
-    catch (\Exception $e) {
-      $this->errors[] = $e->getMessage();
-    }
-  }
-
-  /**
-   * Checks if input is a string with an expected format.
-   *
-   * @return boolean
-   *   TRUE if the input time is a string with an expected format.
-   */
-  public function inputIsFormat() {
-    return is_string($this->inputTimeAdjusted) && !empty($this->inputFormatAdjusted);
-  }
-
-  /**
-   * Creates a date object from an input format.
-   */
-  protected function constructFromFormat() {
-    // Tries to create a date from the format and use it if possible.
-    // A regular try/catch won't work right here, if the value is
-    // invalid it doesn't return an exception.
-    try {
-      parent::__construct('', $this->inputTimeZoneAdjusted);
-      $date = parent::createFromFormat($this->inputFormatAdjusted, $this->inputTimeAdjusted, $this->inputTimeZoneAdjusted);
-      if (!$date instanceOf \DateTime) {
-        throw new \Exception('The date cannot be created from a format.');
-      }
-      else {
-        $this->setTimestamp($date->getTimestamp());
-        $this->setTimezone($date->getTimezone());
-
-        try {
-          // The createFromFormat function is forgiving, it might
-          // create a date that is not exactly a match for the provided
-          // value, so test for that. For instance, an input value of
-          // '11' using a format of Y (4 digits) gets created as
-          // '0011' instead of '2011'.
-          // Use the parent::format() because we do not want to use
-          // the IntlDateFormatter here.
-          if ($this->validateFormat && parent::format($this->inputFormatAdjusted) != $this->inputTimeRaw) {
-            throw new \Exception('The created date does not match the input value.');
-          }
-        }
-        catch (\Exception $e) {
-          $this->errors[] = $e->getMessage();
-        }
-      }
-    }
-    catch (\Exception $e) {
-      $this->errors[] = $e->getMessage();
-    }
-  }
-
-  /**
-   * Creates a date when none of the other methods are appropriate.
-   *
-   * Fallback construction for values that don't match any of the
-   * other patterns. Lets the parent dateTime attempt to turn this string
-   * into a valid date.
-   */
-  protected function constructFallback() {
-
-    try {
-      // One last test for invalid input before we try to construct
-      // a date. If the input contains totally bogus information
-      // it will blow up badly if we pass it to the constructor.
-      // The date_parse() function will tell us if the input
-      // makes sense.
-      if (!empty($this->inputTimeAdjusted)) {
-        $test = date_parse($this->inputTimeAdjusted);
-        if (!empty($test['errors'])) {
-          $this->errors[] = $test['errors'];
-        }
-      }
-
-      if (empty($this->errors)) {
-        parent::__construct($this->inputTimeAdjusted, $this->inputTimeZoneAdjusted);
-      }
-    }
-    catch (\Exception $e) {
-      $this->errors[] = $e->getMessage();
-    }
-  }
 
   /**
    * Examines getLastErrors() to see what errors to report.
@@ -655,7 +555,14 @@ public function canUseIntl($calendar = NULL, $langcode = NULL, $country = NULL)
     $country = !empty($country) ? $country : $this->country;
     $calendar = !empty($calendar) ? $calendar : $this->calendar;
 
-    return class_exists('IntlDateFormatter') && !empty($calendar) && !empty($langcode) && !empty($country);
+    return $this->intlDateFormatterExists() && !empty($calendar) && !empty($langcode) && !empty($country);
+  }
+
+  public static function intlDateFormatterExists() {
+    if (static::$intlExtentionExists === NULL) {
+      static::$intlExtentionExists = class_exists('IntlDateFormatter');
+    }
+    return static::$intlExtentionExists;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Datetime/Date.php b/core/lib/Drupal/Core/Datetime/Date.php
index 556733186bb594b918fc2cc8850386071d4e73b2..dbc237b6901d99d658c9d1a75368d8431d0f7174 100644
--- a/core/lib/Drupal/Core/Datetime/Date.php
+++ b/core/lib/Drupal/Core/Datetime/Date.php
@@ -39,6 +39,9 @@ class Date {
    */
   protected $languageManager;
 
+  protected $country = NULL;
+  protected $dateFormats = array();
+
   /**
    * Constructs a Date object.
    *
@@ -97,19 +100,23 @@ public function format($timestamp, $type = 'medium', $format = '', $timezone = N
     }
 
     // Create a DrupalDateTime object from the timestamp and timezone.
-    $date = new DrupalDateTime($timestamp, $this->timezones[$timezone]);
+    $create_settings = array(
+      'langcode' => $langcode,
+      'country' => $this->country(),
+    );
+    $date = DrupalDateTime::createFromTimestamp($timestamp, $this->timezones[$timezone], $create_settings);
 
     // Find the appropriate format type.
     $key = $date->canUseIntl() ? DrupalDateTime::INTL : DrupalDateTime::PHP;
 
     // If we have a non-custom date format use the provided date format pattern.
-    if ($date_format = $this->dateFormatStorage->load($type)) {
+    if ($date_format = $this->dateFormat($type)) {
       $format = $date_format->getPattern($key);
     }
 
     // Fall back to medium if a format was not found.
     if (empty($format)) {
-      $format = $this->dateFormatStorage->load('fallback')->getPattern($key);
+      $format = $this->dateFormat('fallback')->getPattern($key);
     }
 
     // Call $date->format().
@@ -120,4 +127,24 @@ public function format($timestamp, $type = 'medium', $format = '', $timezone = N
     return Xss::filter($date->format($format, $settings));
   }
 
+  protected function dateFormat($format) {
+    if (!isset($this->dateFormats[$format])) {
+      $this->dateFormats[$format] = $this->dateFormatStorage->load($format);
+    }
+    return $this->dateFormats[$format];
+  }
+
+  /**
+   * Returns the default country from config.
+   *
+   * @return string
+   *   The config setting for country.default.
+   */
+  protected function country() {
+    if ($this->country === NULL) {
+      $this->country = config('system.date')->get('country.default');
+    }
+    return $this->country;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Datetime/DrupalDateTime.php b/core/lib/Drupal/Core/Datetime/DrupalDateTime.php
index 0a283ac977f48c41f77b5b9d6777dbe15a9549e2..18545b4ff7263e5811116dd3d1c6d82212e03e51 100644
--- a/core/lib/Drupal/Core/Datetime/DrupalDateTime.php
+++ b/core/lib/Drupal/Core/Datetime/DrupalDateTime.php
@@ -29,13 +29,6 @@ class DrupalDateTime extends DateTimePlus {
    * @param mixed $timezone
    *   PHP DateTimeZone object, string or NULL allowed.
    *   Defaults to NULL.
-   * @param string $format
-   *   PHP date() type format for parsing the input. This is recommended
-   *   to use things like negative years, which php's parser fails on, or
-   *   any other specialized input with a known format. If provided the
-   *   date will be created using the createFromFormat() method.
-   *   Defaults to NULL.
-   *   @see http://us3.php.net/manual/en/datetime.createfromformat.php
    * @param array $settings
    *   - validate_format: (optional) Boolean choice to validate the
    *     created date using the input format. The format used in
@@ -57,14 +50,18 @@ class DrupalDateTime extends DateTimePlus {
    *   - debug: (optional) Boolean choice to leave debug values in the
    *     date object for debugging purposes. Defaults to FALSE.
    */
-  public function __construct($time = 'now', $timezone = NULL, $format = NULL, $settings = array()) {
-
+  public function __construct($time = 'now', $timezone = NULL, $settings = array()) {
     // We can set the langcode and country using Drupal values.
-    $settings['langcode'] = !empty($settings['langcode']) ? $settings['langcode'] : language(Language::TYPE_INTERFACE)->id;
-    $settings['country'] = !empty($settings['country']) ? $settings['country'] : config('system.date')->get('country.default');
+    if (!isset($settings['langcode'])) {
+      $settings['langcode'] = language(Language::TYPE_INTERFACE)->id;
+    }
+
+    if (!isset($settings['country'])) {
+      $settings['country'] = config('system.date')->get('country.default');
+    }
 
     // Instantiate the parent class.
-    parent::__construct($time, $timezone, $format, $settings);
+    parent::__construct($time, $timezone, $settings);
 
   }
 
@@ -79,7 +76,7 @@ protected function prepareTimezone($timezone) {
     if (empty($timezone) && !empty($user_timezone)) {
       $timezone = $user_timezone;
     }
-    parent::prepareTimezone($timezone);
+    return parent::prepareTimezone($timezone);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php
index 906b4eb5a80dd6dccc1f8259956d36fbd08ae191..629d675a951afc05c5d31ced5f3e98821da2a5b0 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php
@@ -29,7 +29,13 @@ class DateTimeIso8601 extends String implements DateTimeInterface {
    */
   public function getDateTime() {
     if ($this->value) {
-      return new DrupalDateTime($this->value);
+      if (is_array($this->value)) {
+        $datetime = DrupalDateTime::createFromArray($this->value);
+      }
+      else {
+        $datetime = new DrupalDateTime($this->value);
+      }
+      return $datetime;
     }
   }
 
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php
index c0cad0203448c30c2c6644a0526e1cff7cc1eddf..c817e251c8c45ec2c8964dd6b4cd459807a8dbf6 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php
@@ -34,7 +34,7 @@ class Timestamp extends Integer implements DateTimeInterface {
    */
   public function getDateTime() {
     if ($this->value) {
-      return new DrupalDateTime($this->value);
+      return DrupalDateTime::createFromTimestamp($this->value);
     }
   }
 
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index 7e20010778cab72536e552294a07d81c8015225b..6d7c39beba5162f653b7a06fa0d66543f0865b34 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -62,7 +62,7 @@ public function form(array $form, array &$form_state) {
     if ($is_admin) {
       $author = $comment->name->value;
       $status = (isset($comment->status->value) ? $comment->status->value : COMMENT_NOT_PUBLISHED);
-      $date = (!empty($comment->date) ? $comment->date : new DrupalDateTime($comment->created->value));
+      $date = (!empty($comment->date) ? $comment->date : DrupalDateTime::createFromTimestamp($comment->created->value));
     }
     else {
       if ($user->isAuthenticated()) {
diff --git a/core/modules/datetime/datetime.module b/core/modules/datetime/datetime.module
index ebbcdd8d6631e1c9aa0349d28b94c16d49c49be4..eafc616926d0f7293fdc0941bf23dd8cceaedc41 100644
--- a/core/modules/datetime/datetime.module
+++ b/core/modules/datetime/datetime.module
@@ -507,11 +507,16 @@ function form_type_datetime_value($element, $input = FALSE) {
       $time_input .= ':00';
     }
 
-    $date = new DrupalDateTime(trim($date_input . ' ' . $time_input), $timezone, trim($date_format . ' ' . $time_format));
+    try {
+      $date = DrupalDateTime::createFromFormat(trim($date_format . ' ' . $time_format), trim($date_input . ' ' . $time_input), $timezone);
+    }
+    catch (\Exception $e) {
+      $date = NULL;
+    }
     $input = array(
       'date'   => $date_input,
       'time'   => $time_input,
-      'object' => $date instanceOf DrupalDateTime && !$date->hasErrors() ? $date : NULL,
+      'object' => $date,
     );
   }
   else {
@@ -836,7 +841,7 @@ function form_type_datelist_value($element, $input = FALSE, &$form_state = array
       unset($input['ampm']);
     }
     $timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : NULL;
-    $date = new DrupalDateTime($input, $timezone);
+    $date = DrupalDateTime::createFromArray($input, $timezone);
     if ($date instanceOf DrupalDateTime && !$date->hasErrors()) {
       date_increment_round($date, $increment);
     }
@@ -1044,5 +1049,5 @@ function datetime_form_node_form_alter(&$form, &$form_state, $form_id) {
  */
 function datetime_node_prepare_form(NodeInterface $node, $form_display, $operation, array &$form_state) {
   // Prepare the 'Authored on' date to use datetime.
-  $node->date = new DrupalDateTime($node->created);
+  $node->date = DrupalDateTime::createFromTimestamp($node->created);
 }
diff --git a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/field_type/DateTimeItem.php b/core/modules/datetime/lib/Drupal/datetime/Plugin/field/field_type/DateTimeItem.php
index 0c51dd422a2e485d99860ba811b9530b81288f14..6f02eda9bacf4f5e55e6f623901222abb4447f5f 100644
--- a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/field_type/DateTimeItem.php
+++ b/core/modules/datetime/lib/Drupal/datetime/Plugin/field/field_type/DateTimeItem.php
@@ -122,9 +122,14 @@ public function prepareCache() {
     $value = $this->get('value')->getValue();
     if (!empty($value)) {
       $storage_format = $this->getFieldSetting('datetime_type') == 'date' ? DATETIME_DATE_STORAGE_FORMAT : DATETIME_DATETIME_STORAGE_FORMAT;
-      $date = new DrupalDateTime($value, DATETIME_STORAGE_TIMEZONE, $storage_format);
-      if ($date instanceOf DrupalDateTime && !$date->hasErrors()) {
-        $this->set('date', $date);
+      try {
+        $date = DrupalDateTime::createFromFormat($storage_format, $value, DATETIME_STORAGE_TIMEZONE);
+        if ($date instanceOf DrupalDateTime && !$date->hasErrors()) {
+          $this->set('date', $date);
+        }
+      }
+      catch (\Exception $e) {
+        // @todo Handle this.
       }
     }
   }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Datetime/DateTimePlusIntlTest.php b/core/modules/system/lib/Drupal/system/Tests/Datetime/DateTimePlusIntlTest.php
index 89466d4f727b91dcc276e8c8146de6845e0cc3c4..453cfbd2f2d9725f1277df1599cc8d1185ce0f19 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Datetime/DateTimePlusIntlTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Datetime/DateTimePlusIntlTest.php
@@ -70,8 +70,8 @@ function testDateTimestampIntl() {
       'langcode' => 'en',
     );
 
-    $intl_date = new DateTimePlus($input, $timezone, NULL, $intl_settings);
-    $php_date = new DateTimePlus($input, $timezone, NULL, $php_settings);
+    $intl_date = new DateTimePlus($input, $timezone, $intl_settings);
+    $php_date = new DateTimePlus($input, $timezone, $php_settings);
 
     $this->assertTrue($intl_date->canUseIntl(), 'DateTimePlus object can use intl when provided with country and langcode settings.');
     $this->assertFalse($php_date->canUseIntl(), 'DateTimePlus object will fallback to use PHP when not provided with country setting.');
diff --git a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
index 3558d20e4edefa315d9304d75c28e6dae21523a5..6b1f0c5afdb0be53d7317f9f07a9249344ac7ea4 100644
--- a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php
@@ -174,7 +174,7 @@ public function testGetAndSet() {
     // Check implementation of DateTimeInterface.
     $typed_data = $this->createTypedData(array('type' => 'timestamp'), REQUEST_TIME);
     $this->assertTrue($typed_data->getDateTime() instanceof DrupalDateTime);
-    $typed_data->setDateTime(new DrupalDateTime(REQUEST_TIME + 1));
+    $typed_data->setDateTime(DrupalDateTime::createFromTimestamp(REQUEST_TIME + 1));
     $this->assertEqual($typed_data->getValue(), REQUEST_TIME + 1);
     $typed_data->setValue(NULL);
     $this->assertNull($typed_data->getDateTime());
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/ArgumentDateTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/ArgumentDateTest.php
index 545b40a34e7b64d020e94116a8dc9f616c58e6f7..c5dac2ef167beec5570d37258c710cd580607a94 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/ArgumentDateTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/ArgumentDateTest.php
@@ -142,7 +142,7 @@ public function testMonthHandler() {
     $view->destroy();
 
     $view->setDisplay('embed_2');
-    $this->executeView($view, array('23'));
+    $this->executeView($view, array('12'));
     $expected = array();
     $this->assertIdenticalResultset($view, $expected, $this->columnMap);
   }
@@ -296,7 +296,7 @@ public function testYearMonthHandler() {
     $view->destroy();
 
     $view->setDisplay('embed_5');
-    $this->executeView($view, array('23'));
+    $this->executeView($view, array('201301'));
     $expected = array();
     $this->assertIdenticalResultset($view, $expected, $this->columnMap);
   }
diff --git a/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
index f7808770d59a5381324a203676486f483a49b7eb..ba62ae0ec5b725d85c2d1cc701d4b943110989de 100644
--- a/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
+++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
@@ -51,10 +51,32 @@ public function testDates($input, $timezone, $expected) {
   }
 
   /**
-   * Test creating dates from timestamps, and manipulating timezones.
+   * Test creating dates from string and array input.
    *
    * @param mixed $input
-   *   Input argument for DateTimePlus().
+   *   Input argument for DateTimePlus.
+   * @param string $timezone
+   *   Timezone argument for DateTimePlus.
+   * @param string $expected
+   *   Expected output from DateTimePlus::format().
+   *
+   * @dataProvider providerTestDateArrays
+   */
+  public function testDateArrays($input, $timezone, $expected) {
+    $date = DateTimePlus::createFromArray($input, $timezone);
+    $value = $date->format('c');
+
+    if (is_array($input)) {
+      $input = var_export($input, TRUE);
+    }
+    $this->assertEquals($expected, $value, sprintf("Test new DateTimePlus(%s, %s): should be %s, found %s.", $input, $timezone, $expected, $value));
+  }
+
+  /**
+   * Test creating dates from timestamps, and manipulating timezones.
+   *
+   * @param int $input
+   *   Input argument for DateTimePlus::createFromTimestamp().
    * @param array $initial
    *   An array containing:
    *   - 'timezone_initial' - Timezone argument for DateTimePlus.
@@ -76,12 +98,46 @@ public function testDates($input, $timezone, $expected) {
    *   - 'expected_transform_offset' - Expected output from
    *      DateTimePlus::getOffset(), after timezone transform.
    *
+   * @dataProvider providerTestTimestamp
+   */
+  public function testTimestamp($input, array $initial, array $transform) {
+    // Initialize a new date object.
+    $date = DateTimePlus::createFromTimestamp($input, $initial['timezone']);
+    $this->assertDateTimestamp($date, $input, $initial, $transform);
+  }
+
+  /**
+   * Test creating dates from datetime strings.
+   *
+   * @param string $input
+   *   Input argument for DateTimePlus().
+   * @param array $initial
+   *   @see testTimestamp()
+   * @param array $transform
+   *   @see testTimestamp()
+   *
    * @dataProvider providerTestDateTimestamp
    */
   public function testDateTimestamp($input, array $initial, array $transform) {
     // Initialize a new date object.
     $date = new DateTimePlus($input, $initial['timezone']);
+    $this->assertDateTimestamp($date, $input, $initial, $transform);
+  }
 
+  /**
+   * Assertion helper for testTimestamp and testDateTimestamp since they need
+   * different dataProviders.
+   *
+   * @param DateTimePlus $date
+   *   DateTimePlus to test.
+   * @input mixed $input
+   *   The original input passed to the test method.
+   * @param array $initial
+   *   @see testTimestamp()
+   * @param array $transform
+   *   @see testTimestamp()
+   */
+  public function assertDateTimestamp($date, $input, $initial, $transform) {
     // Check format.
     $value = $date->format($initial['format']);
     $this->assertEquals($initial['expected_date'], $value, sprintf("Test new DateTimePlus(%s, %s): should be %s, found %s.", $input, $initial['timezone'], $initial['expected_date'], $value));
@@ -108,7 +164,6 @@ public function testDateTimestamp($input, array $initial, array $transform) {
     // Check transformed offset.
     $value = $date->getOffset();
     $this->assertEquals($transform['expected_offset'], $value, sprintf("The current offset should be %s, found %s.", $transform['expected_offset'], $value));
-
   }
 
   /**
@@ -126,7 +181,7 @@ public function testDateTimestamp($input, array $initial, array $transform) {
    * @dataProvider providerTestDateFormat
    */
   public function testDateFormat($input, $timezone, $format, $format_date, $expected) {
-    $date = new DateTimePlus($input, $timezone, $format);
+    $date = DateTimePlus::createFromFormat($format, $input, $timezone);
     $value = $date->format($format_date);
     $this->assertEquals($expected, $value, sprintf("Test new DateTimePlus(%s, %s, %s): should be %s, found %s.", $input, $timezone, $format, $expected, $value));
   }
@@ -144,14 +199,14 @@ public function testDateFormat($input, $timezone, $format, $format_date, $expect
    *   Message to print if no errors are thrown by the invalid dates.
    *
    * @dataProvider providerTestInvalidDates
+   * @expectedException \Exception
    */
   public function testInvalidDates($input, $timezone, $format, $message) {
-    $date = new DateTimePlus($input, $timezone, $format);
-    $this->assertNotEquals(count($date->getErrors()), 0, $message);
+    $date = DateTimePlus::createFromFormat($format, $input, $timezone);
   }
 
   /**
-   * Test that DrupalDateTime can detect the right timezone to use.
+   * Tests that DrupalDateTime can detect the right timezone to use.
    * When specified or not.
    *
    * @param mixed $input
@@ -172,7 +227,23 @@ public function testDateTimezone($input, $timezone, $expected_timezone, $message
   }
 
   /**
-   * Provide data for date tests.
+   * Test that DrupalDateTime can detect the right timezone to use when
+   * constructed from a datetime object.
+   */
+  public function testDateTimezoneWithDateTimeObject() {
+    // Create a date object with another date object.
+    $input = new DateTimePlus('now', 'Pacific/Midway');
+    $timezone = NULL;
+    $expected_timezone = 'Pacific/Midway';
+    $message = 'DateTimePlus uses the specified timezone if provided.';
+
+    $date = DateTimePlus::createFromDateTime($input, $timezone);
+    $timezone = $date->getTimezone()->getName();
+    $this->assertEquals($timezone, $expected_timezone, $message);
+  }
+
+  /**
+   * Provides data for date tests.
    *
    * @return array
    *   An array of arrays, each containing the input parameters for
@@ -195,7 +266,20 @@ public function providerTestDates() {
       array('2009-03-07 10:30', 'Australia/Canberra', '2009-03-07T10:30:00+11:00'),
       // Same during daylight savings time.
       array('2009-06-07 10:30', 'Australia/Canberra', '2009-06-07T10:30:00+10:00'),
+    );
+  }
 
+  /**
+   * Provides data for date tests.
+   *
+   * @return array
+   *   An array of arrays, each containing the input parameters for
+   *   DateTimePlusTest::testDates().
+   *
+   * @see DateTimePlusTest::testDates().
+   */
+  public function providerTestDateArrays() {
+    return array(
       // Array input.
       // Create date object from date array, date only.
       array(array('year' => 2010, 'month' => 2, 'day' => 28), 'America/Chicago', '2010-02-28T00:00:00-06:00'),
@@ -209,7 +293,7 @@ public function providerTestDates() {
   }
 
   /**
-   * Provide data for testDateFormats.
+   * Provides data for testDateFormats.
    *
    * @return array
    *   An array of arrays, each containing:
@@ -235,7 +319,7 @@ public function providerTestDateFormat() {
   }
 
   /**
-   * Provide data for testInvalidDates.
+   * Provides data for testInvalidDates.
    *
    * @return array
    *   An array of arrays, each containing:
@@ -259,6 +343,24 @@ public function providerTestInvalidDates() {
       array('0000-75-00T15:30:00', NULL, 'Y-m-d\TH:i:s', "0000-75-00T15:30:00 contains an invalid month and did not produce errors."),
       // Test for invalid year.
       array('11-08-01T15:30:00', NULL, 'Y-m-d\TH:i:s', "11-08-01T15:30:00 contains an invalid year and did not produce errors."),
+
+    );
+  }
+
+  /**
+   * Provides data for testInvalidDates.
+   *
+   * @return array
+   *   An array of arrays, each containing:
+   *   - 'input' - Input for DateTimePlus.
+   *   - 'timezone' - Timezone for DateTimePlus.
+   *   - 'format' - Format for DateTimePlus.
+   *   - 'message' - Message to display on failure.
+   *
+   * @see testInvalidDateArrays
+   */
+  public function providerTestInvalidDateArrays() {
+    return array(
       // Test for invalid year from date array. 10000 as a year will
       // create an exception error in the PHP DateTime object.
       array(array('year' => 10000, 'month' => 7, 'day' => 8, 'hour' => 8, 'minute' => 0, 'second' => 0), 'America/Chicago', NULL, "array('year' => 10000, 'month' => 7, 'day' => 8, 'hour' => 8, 'minute' => 0, 'second' => 0) contains an invalid year and did not produce errors."),
@@ -272,7 +374,7 @@ public function providerTestInvalidDates() {
   }
 
   /**
-   * Provide data for testDateTimezone.
+   * Provides data for testDateTimezone.
    *
    * @return array
    *   An array of arrays, each containing:
@@ -304,15 +406,15 @@ public function providerTestDateTimezone() {
   }
 
   /**
-   * Provide data for testDateTimestamp.
+   * Provides data for testTimestamp.
    *
    * @return array
    *   An array of arrays, each containing the arguments required for
-   *   self::testDateTimestamp().
+   *   self::testTimestamp().
    *
-   * @see testDateTimestamp()
+   * @see testTimestamp()
    */
-  public function providerTestDateTimestamp() {
+  public function providerTestTimestamp() {
     return array(
       // Create date object from a unix timestamp and display it in
       // local time.
@@ -352,6 +454,20 @@ public function providerTestDateTimestamp() {
           'expected_offset' => 0,
         ),
       ),
+    );
+  }
+
+  /**
+   * Provides data for testDateTimestamp.
+   *
+   * @return array
+   *   An array of arrays, each containing the arguments required for
+   *   self::testDateTimestamp().
+   *
+   * @see testDateTimestamp()
+   */
+  public function providerTestDateTimestamp() {
+    return array(
       // Create date object from datetime string in UTC, and convert
       // it to a local date.
       array(