summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2013-08-10 08:00:02 +0100
committerNathaniel Catchpole2013-08-10 08:00:02 +0100
commite2a81db3c6922f144cd0e583d887588077ddbf91 (patch)
tree71bff94ec0e856457cc50e934823bdcfe9906734
parent18a03b1f133d7d8f307789ead50ea6087f97851f (diff)
Issue #1844956 by msonnabaum, beejeebus: Fixed Optimize date formatting performance.
-rw-r--r--core/includes/common.inc2
-rw-r--r--core/lib/Drupal/Component/Datetime/DateTimePlus.php373
-rw-r--r--core/lib/Drupal/Core/Datetime/Date.php33
-rw-r--r--core/lib/Drupal/Core/Datetime/DrupalDateTime.php23
-rw-r--r--core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php8
-rw-r--r--core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php2
-rw-r--r--core/modules/comment/lib/Drupal/comment/CommentFormController.php2
-rw-r--r--core/modules/datetime/datetime.module13
-rw-r--r--core/modules/datetime/lib/Drupal/datetime/Plugin/field/field_type/DateTimeItem.php11
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Datetime/DateTimePlusIntlTest.php4
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php2
-rw-r--r--core/modules/views/lib/Drupal/views/Tests/Handler/ArgumentDateTest.php4
-rw-r--r--core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php146
13 files changed, 343 insertions, 280 deletions
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 1980f2f..48db270 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 b00124b..cda7f3e 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 @@ class DateTimePlus extends \DateTime {
* or an array of date parts.
*/
protected function prepareTime($time) {
- $this->inputTimeAdjusted = $time;
+ return $time;
}
/**
@@ -247,12 +322,6 @@ class DateTimePlus extends \DateTime {
$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 @@ class DateTimePlus extends \DateTime {
}
// We are finally certain that we have a usable timezone.
- $this->inputTimeZoneAdjusted = $timezone_adjusted;
+ return $timezone_adjusted;
}
/**
@@ -280,179 +349,10 @@ class DateTimePlus extends \DateTime {
* 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 @@ class DateTimePlus extends \DateTime {
$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 5567331..dbc237b 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 @@ class Date {
}
// 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 @@ class Date {
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 0a283ac..18545b4 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 @@ class DrupalDateTime extends DateTimePlus {
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 906b4eb..629d675 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 c0cad02..c817e25 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 7e20010..6d7c39b 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -62,7 +62,7 @@ class CommentFormController extends EntityFormControllerNG {
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 ebbcdd8..eafc616 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 0c51dd4..6f02eda 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 @@ class DateTimeItem extends ConfigFieldItemBase implements PrepareCacheInterface
$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 89466d4..453cfbd 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 @@ class DateTimePlusIntlTest extends DrupalUnitTestBase {
'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 3558d20..6b1f0c5 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 @@ class TypedDataTest extends DrupalUnitTestBase {
// 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 545b40a..c5dac2e 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 @@ class ArgumentDateTest extends ViewUnitTestBase {
$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 @@ class ArgumentDateTest extends ViewUnitTestBase {
$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 f780877..ba62ae0 100644
--- a/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
+++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
@@ -51,10 +51,32 @@ class DateTimePlusTest extends UnitTestCase {
}
/**
- * 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 @@ class DateTimePlusTest extends UnitTestCase {
* - '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 @@ class DateTimePlusTest extends UnitTestCase {
// 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 @@ class DateTimePlusTest extends UnitTestCase {
* @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 @@ class DateTimePlusTest extends UnitTestCase {
* 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 @@ class DateTimePlusTest extends UnitTestCase {
}
/**
- * 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 @@ class DateTimePlusTest extends UnitTestCase {
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 @@ class DateTimePlusTest extends UnitTestCase {
}
/**
- * Provide data for testDateFormats.
+ * Provides data for testDateFormats.
*
* @return array
* An array of arrays, each containing:
@@ -235,7 +319,7 @@ class DateTimePlusTest extends UnitTestCase {
}
/**
- * Provide data for testInvalidDates.
+ * Provides data for testInvalidDates.
*
* @return array
* An array of arrays, each containing:
@@ -259,6 +343,24 @@ class DateTimePlusTest extends UnitTestCase {
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 @@ class DateTimePlusTest extends UnitTestCase {
}
/**
- * Provide data for testDateTimezone.
+ * Provides data for testDateTimezone.
*
* @return array
* An array of arrays, each containing:
@@ -304,15 +406,15 @@ class DateTimePlusTest extends UnitTestCase {
}
/**
- * 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 @@ class DateTimePlusTest extends UnitTestCase {
'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(