diff --git a/core/lib/Drupal/Core/Datetime/DateFormatter.php b/core/lib/Drupal/Core/Datetime/DateFormatter.php index 0b4f817..ff62e7e 100644 --- a/core/lib/Drupal/Core/Datetime/DateFormatter.php +++ b/core/lib/Drupal/Core/Datetime/DateFormatter.php @@ -169,11 +169,17 @@ public function format($timestamp, $type = 'medium', $format = '', $timezone = N * (optional) How many different units to display in the string (2 by * default). * @param string $langcode - * (optional) Language code to translate to a language other than what is - * used to display the page. Defaults to NULL. + * (optional) Language code, to translate to a language other than what is + * used to display the page. * * @return string - * A translated string representation of the interval. + * A translated string representation of the interval. Note that for + * intervals over 30 days, the output is approximate: a "month" is always + * exactly 30 days, and a "year" is always 365 days. It is not possible to + * make a more exact representation, given that there is only one input in + * seconds. + * + * @see \Drupal\Core\Datetime\DateFormatter::formatDiff() */ public function formatInterval($interval, $granularity = 2, $langcode = NULL) { $output = ''; @@ -193,6 +199,109 @@ public function formatInterval($interval, $granularity = 2, $langcode = NULL) { } /** + * Formats a time interval between two timestamps. + * + * @param int $timestamp1 + * A UNIX timestamp, defining the from date and time. + * @param int $timestamp2 + * (optional) A UNIX timestamp, defining the to date and time. If NULL is + * passed, the current request time is assumed. Defaults to NULL. + * @param array $options + * (optional) An associative array with additional options. The following + * keys can be used: + * - granularity: An integer value that signals how many different units to + * display in the string. Defaults to 2. + * - langcode: A string representing a language code. It is used to + * translate to a language other than what is used to display the page. + * Defaults to NULL, which results in the current user language being used. + * - prefix: A string that is prepended to the output. + * - suffix: A string that is appended to the output. + * + * @return string + * A translated string representation of the interval. + * + * @see \Drupal\Core\Datetime\DateFormatter::formatInterval() + */ + public function formatDiff($timestamp1, $timestamp2 = NULL, $options = array()) { + + if(is_null($timestamp2)) { + $timestamp2 = $_SERVER['REQUEST_TIME']; + } + + $options += array( + 'granularity' => 2, + 'langcode' => NULL, + 'prefix' => '', + 'suffix' => '', + ); + + $date_time1 = new \DateTime(); + $date_time1->setTimestamp($timestamp1); + + $date_time2 = new \DateTime(); + $date_time2->setTimestamp($timestamp2); + + $interval = $date_time2->diff($date_time1); + + $granularity = $options['granularity']; + $output = ''; + foreach (array('y', 'm', 'd', 'h', 'i', 's') as $value) { + if ($interval->$value > 0) { + // Switch over the keys to call formatPlural() explicitly with literal + // strings for all different possibilities. + switch ($value) { + case 'y': + $thisoutput = $this->formatPlural($interval->y, '1 year', '@count years', array(), array('langcode' => $options['langcode'])); + break; + + case 'm': + $thisoutput = $this->formatPlural($interval->m, '1 month', '@count months', array(), array('langcode' => $options['langcode'])); + break; + + case 'd': + $thisoutput = $this->formatPlural($interval->d, '1 day', '@count days', array(), array('langcode' => $options['langcode'])); + break; + + case 'h': + $thisoutput = $this->formatPlural($interval->h, '1 hour', '@count hours', array(), array('langcode' => $options['langcode'])); + break; + + case 'i': + $thisoutput = $this->formatPlural($interval->i, '1 minute', '@count minutes', array(), array('langcode' => $options['langcode'])); + break; + + case 's': + $thisoutput = $this->formatPlural($interval->s, '1 second', '@count seconds', array(), array('langcode' => $options['langcode'])); + break; + + default: + break; + } + $output .= ($output ? ' ' : '') . $thisoutput; + $granularity--; + } + + if ($granularity == 0) { + break; + } + } + + if(empty($output)) { + $output = $this->t('0 seconds'); + } + + if($options['prefix'] != '') { + $output = $options['prefix'] . ' ' . $output; + } + + if($options['suffix'] != '') { + $output .= ' ' . $options['suffix']; + } + + return $output; + } + + /** * Loads the given format pattern for the given langcode. * * @param string $format diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampAgoFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampAgoFormatter.php index 04f96fa..b5f5600 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampAgoFormatter.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampAgoFormatter.php @@ -87,7 +87,7 @@ public function viewElements(FieldItemListInterface $items) { foreach ($items as $delta => $item) { if ($item->value) { - $updated = $this->t('@time ago', array('@time' => $this->dateFormatter->formatInterval(REQUEST_TIME - $item->value))); + $updated = $this->dateFormatter->formatDiff($_SERVER['REQUEST_TIME'] - $item->value, $_SERVER['REQUEST_TIME'], array('suffix' => 'ago')); } else { $updated = $this->t('never'); diff --git a/core/modules/aggregator/src/Controller/AggregatorController.php b/core/modules/aggregator/src/Controller/AggregatorController.php index 303b43c..e849218 100644 --- a/core/modules/aggregator/src/Controller/AggregatorController.php +++ b/core/modules/aggregator/src/Controller/AggregatorController.php @@ -127,8 +127,8 @@ public function adminOverview() { $row[] = $this->formatPlural($entity_manager->getStorage('aggregator_item')->getItemCount($feed), '1 item', '@count items'); $last_checked = $feed->getLastCheckedTime(); $refresh_rate = $feed->getRefreshRate(); - $row[] = ($last_checked ? $this->t('@time ago', array('@time' => $this->dateFormatter->formatInterval(REQUEST_TIME - $last_checked))) : $this->t('never')); - $row[] = ($last_checked && $refresh_rate ? $this->t('%time left', array('%time' => $this->dateFormatter->formatInterval($last_checked + $refresh_rate - REQUEST_TIME))) : $this->t('never')); + $row[] = ($last_checked ? $this->dateFormatter->formatDiff($_SERVER['REQUEST_TIME'] - $last_checked, $_SERVER['REQUEST_TIME'], array('suffix' => 'ago')) : $this->t('never')); + $row[] = ($last_checked && $refresh_rate ? $this->dateFormatter->formatDiff($last_checked + $refresh_rate - $_SERVER['REQUEST_TIME'], $_SERVER['REQUEST_TIME'], array('suffix' => 'left')) : $this->t('never')); $links['edit'] = [ 'title' => $this->t('Edit'), 'url' => Url::fromRoute('entity.aggregator_feed.edit_form', ['aggregator_feed' => $feed->id()]), diff --git a/core/modules/contact/src/MessageForm.php b/core/modules/contact/src/MessageForm.php index 78de6dd..cad1942 100644 --- a/core/modules/contact/src/MessageForm.php +++ b/core/modules/contact/src/MessageForm.php @@ -200,7 +200,7 @@ public function validate(array $form, FormStateInterface $form_state) { if (!$this->flood->isAllowed('contact', $limit, $interval)) { $form_state->setErrorByName('', $this->t('You cannot send more than %limit messages in @interval. Try again later.', array( '%limit' => $limit, - '@interval' => $this->dateFormatter->formatInterval($interval), + '@interval' => $this->dateFormatter->formatDiff($_SERVER['REQUEST_TIME'] + $interval), ))); } } diff --git a/core/modules/contact/src/Tests/ContactSitewideTest.php b/core/modules/contact/src/Tests/ContactSitewideTest.php index df2816e..058ee62 100644 --- a/core/modules/contact/src/Tests/ContactSitewideTest.php +++ b/core/modules/contact/src/Tests/ContactSitewideTest.php @@ -231,7 +231,7 @@ function testSiteWideContact() { } // Submit contact form one over limit. $this->submitContact($this->randomMachineName(16), $recipients[0], $this->randomMachineName(16), $id, $this->randomMachineName(64)); - $this->assertRaw(t('You cannot send more than %number messages in @interval. Try again later.', array('%number' => $this->config('contact.settings')->get('flood.limit'), '@interval' => \Drupal::service('date.formatter')->formatInterval(600)))); + $this->assertRaw(t('You cannot send more than %number messages in @interval. Try again later.', array('%number' => $this->config('contact.settings')->get('flood.limit'), '@interval' => \Drupal::service('date.formatter')->formatDiff($_SERVER['REQUEST_TIME'] - 600)))); // Test listing controller. $this->drupalLogin($admin_user); diff --git a/core/modules/system/src/Form/CronForm.php b/core/modules/system/src/Form/CronForm.php index f906c70..5591618 100644 --- a/core/modules/system/src/Form/CronForm.php +++ b/core/modules/system/src/Form/CronForm.php @@ -101,8 +101,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#value' => t('Run cron'), '#submit' => array('::submitCron'), ); - - $status = '

' . t('Last run: %cron-last ago.', array('%cron-last' => $this->dateFormatter->formatInterval(REQUEST_TIME - $this->state->get('system.cron_last')))) . '

'; + $status = '

' . $this->dateFormatter->formatDiff($this->state->get('system.cron_last'), $_SERVER['REQUEST_TIME'], array('prefix' => 'Last run:', 'suffix' => 'ago')) . '

'; $form['status'] = array( '#markup' => $status, ); diff --git a/core/modules/user/src/UserListBuilder.php b/core/modules/user/src/UserListBuilder.php index e6ae82d..d36d5fb 100644 --- a/core/modules/user/src/UserListBuilder.php +++ b/core/modules/user/src/UserListBuilder.php @@ -151,10 +151,8 @@ public function buildRow(EntityInterface $entity) { '#theme' => 'item_list', '#items' => $users_roles, ); - $row['member_for'] = $this->dateFormatter->formatInterval(REQUEST_TIME - $entity->getCreatedTime()); - $row['access'] = $entity->access ? $this->t('@time ago', array( - '@time' => $this->dateFormatter->formatInterval(REQUEST_TIME - $entity->getLastAccessedTime()), - )) : t('never'); + $row['member_for'] = $this->dateFormatter->formatDiff($entity->getCreatedTime()); + $row['access'] = $entity->access ? $this->dateFormatter->formatDiff($entity->getLastAccessedTime(), REQUEST_TIME, array('suffix' => 'ago')) : t('never'); return $row + parent::buildRow($entity); } diff --git a/core/modules/views/src/Plugin/views/cache/Time.php b/core/modules/views/src/Plugin/views/cache/Time.php index cd576c1..62f40a3 100644 --- a/core/modules/views/src/Plugin/views/cache/Time.php +++ b/core/modules/views/src/Plugin/views/cache/Time.php @@ -141,7 +141,7 @@ public function validateOptionsForm(&$form, FormStateInterface $form_state) { public function summaryTitle() { $results_lifespan = $this->getLifespan('results'); $output_lifespan = $this->getLifespan('output'); - return $this->dateFormatter->formatInterval($results_lifespan, 1) . '/' . $this->dateFormatter->formatInterval($output_lifespan, 1); + return $this->dateFormatter->formatDiff($results_lifespan, 1) . '/' . $this->dateFormatter->formatDiff($output_lifespan, 1); } protected function getLifespan($type) { diff --git a/core/modules/views/src/Plugin/views/field/Date.php b/core/modules/views/src/Plugin/views/field/Date.php index 8857c1a..6cce138 100644 --- a/core/modules/views/src/Plugin/views/field/Date.php +++ b/core/modules/views/src/Plugin/views/field/Date.php @@ -148,27 +148,48 @@ public function render(ResultRow $values) { if ($value) { $timezone = !empty($this->options['timezone']) ? $this->options['timezone'] : NULL; - $time_diff = REQUEST_TIME - $value; // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence) + $time_diff = $_SERVER['REQUEST_TIME'] - $value; // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence) switch ($format) { case 'raw time ago': - return $this->dateFormatter->formatInterval($time_diff, is_numeric($custom_format) ? $custom_format : 2); + return $this->dateFormatter->formatDiff($value, $_SERVER['REQUEST_TIME'], array('granularity' => is_numeric($custom_format) ? $custom_format : 2)); + case 'time ago': - return $this->t('%time ago', array('%time' => $this->dateFormatter->formatInterval($time_diff, is_numeric($custom_format) ? $custom_format : 2))); + $options = array( + 'granularity' => isset($this->options['granularity']) ? $this->options['granularity'] : 2 + ); + return $this->t('%time ago', array('%time' => $this->dateFormatter->formatDiff($value, $_SERVER['REQUEST_TIME'], $options))); + case 'raw time hence': - return $this->dateFormatter->formatInterval(-$time_diff, is_numeric($custom_format) ? $custom_format : 2); + return $this->dateFormatter->formatDiff($value, $_SERVER['REQUEST_TIME'], array('granularity' => is_numeric($custom_format) ? $custom_format : 2)); + case 'time hence': - return $this->t('%time hence', array('%time' => $this->dateFormatter->formatInterval(-$time_diff, is_numeric($custom_format) ? $custom_format : 2))); + return $this->t('%time hence', array('%time' => $this->dateFormatter->formatDiff($value, $_SERVER['REQUEST_TIME'], array('granularity' => is_numeric($custom_format) ? $custom_format : 2)))); + case 'raw time span': - return ($time_diff < 0 ? '-' : '') . $this->dateFormatter->formatInterval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2); + $options = array( + 'granularity' => is_numeric($custom_format) ? $custom_format : 2, + 'prefix' => ($time_diff < 0 ? '-' : ''), + ); + return $this->dateFormatter->formatDiff(abs($time_diff), $_SERVER['REQUEST_TIME'], $options); case 'inverse time span': - return ($time_diff > 0 ? '-' : '') . $this->dateFormatter->formatInterval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2); + $options = array( + 'granularity' => is_numeric($custom_format) ? $custom_format : 2, + 'prefix' => ($time_diff < 0 ? '-' : ''), + ); + return $this->dateFormatter->formatDiff(abs($time_diff), $_SERVER['REQUEST_TIME'], $options); case 'time span': - return $this->t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => $this->dateFormatter->formatInterval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2))); + $options = array( + 'granularity' => is_numeric($custom_format) ? $custom_format : 2, + 'suffix' => ($time_diff < 0 ? 'hence' : 'ago'), + ); + return $this->dateFormatter->formatDiff(abs($time_diff), $_SERVER['REQUEST_TIME'], $options); + case 'custom': if ($custom_format == 'r') { return format_date($value, $format, $custom_format, $timezone, 'en'); } return format_date($value, $format, $custom_format, $timezone); + default: return format_date($value, $format, '', $timezone); } diff --git a/core/modules/views/src/Plugin/views/field/TimeInterval.php b/core/modules/views/src/Plugin/views/field/TimeInterval.php index faf5fd6..9a538fd 100644 --- a/core/modules/views/src/Plugin/views/field/TimeInterval.php +++ b/core/modules/views/src/Plugin/views/field/TimeInterval.php @@ -87,7 +87,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { */ public function render(ResultRow $values) { $value = $values->{$this->field_alias}; - return $this->dateFormatter->formatInterval($value, isset($this->options['granularity']) ? $this->options['granularity'] : 2); + return $this->dateFormatter->formatDiff($value, $_SERVER['REQUEST_TIME'], array('granularity' => isset($this->options['granularity']) ? $this->options['granularity'] : 2)); } } diff --git a/core/modules/views_ui/src/ViewEditForm.php b/core/modules/views_ui/src/ViewEditForm.php index 2fc7fc4..382e14b 100644 --- a/core/modules/views_ui/src/ViewEditForm.php +++ b/core/modules/views_ui/src/ViewEditForm.php @@ -147,7 +147,7 @@ public function form(array $form, FormStateInterface $form_state) { ); $lock_message_substitutions = array( '!user' => drupal_render($username), - '!age' => $this->dateFormatter->formatInterval(REQUEST_TIME - $view->lock->updated), + '!age' => $this->dateFormatter->formatDiff($view->lock->updated), '@url' => $view->url('break-lock-form'), ); $form['locked'] = array( diff --git a/core/tests/Drupal/Tests/Core/Datetime/DateTest.php b/core/tests/Drupal/Tests/Core/Datetime/DateTest.php index da9ebaa..a247248 100644 --- a/core/tests/Drupal/Tests/Core/Datetime/DateTest.php +++ b/core/tests/Drupal/Tests/Core/Datetime/DateTest.php @@ -128,4 +128,155 @@ public function testFormatIntervalZeroSecond() { $this->assertEquals('0 sec', $result); } + /** + * Tests the formatDiff method. + * + * @dataProvider providerTestFormatDiff + * + * @covers ::formatDiff + */ + public function testformatDiff($expected, $timestamp1, $timestamp2 = NULL, $options = array()) { + + // A formatted diff of two timestamps is dependent on the start and end + // date, so we set the request time fixed to 2013-12-11 10-09-08. + if ($timestamp2 == $_SERVER['REQUEST_TIME'] || is_null($timestamp2)) { + $timestamp2 = $this->createTimestamp('2013-12-11 10:09:08'); + } + + // Mocks a simple formatPlural implementation. + $this->stringTranslation->expects($this->any()) + ->method('formatPlural') + ->with($this->anything(), $this->anything(), $this->anything(), array(), array('langcode' => isset($options['langcode']) ? $options['langcode'] : NULL)) + ->will($this->returnCallback(function($count, $one, $multiple) { + return $count == 1 ? $one : str_replace('@count', $count, $multiple); + })); + + // Mocks a simple translate implementation. + $this->stringTranslation->expects($this->any()) + ->method('translate') + ->with($this->anything()) + ->will($this->returnCallback(function($string, $args, $options) { + return $string; + })); + + $this->assertEquals($expected, $this->dateFormatter->formatDiff($timestamp1, $timestamp2, $options), 'The method returned in the expected formatted diff string.'); + } + + /** + * Data provider for testformatDiff(). + */ + public function providerTestFormatDiff() { + // This is the fixed request time in the test. + $request_time = $this->createTimestamp('2013-12-11 10:09:08'); + + $granularity_3 = array('granularity' => 3); + $granularity_4 = array('granularity' => 4); + + $langcode_en = array('langcode' => 'en'); + $langcode_lolspeak = array('langcode' => 'xxx-lolspeak'); + + $prefix_abc = array('prefix' => 'abc'); + $suffix_xyz = array('suffix' => 'xyz'); + + $data = array( + // Checks for equal timestamps. + array('0 seconds', $request_time, $request_time), + + // Checks for seconds only. + array('1 second', $this->createTimestamp('2013-12-11 10:09:07')), + array('1 second', $this->createTimestamp('2013-12-11 10:09:07'), $request_time), + array('abc 1 second', $this->createTimestamp('2013-12-11 10:09:07'), $request_time, $prefix_abc), + array('1 second xyz', $this->createTimestamp('2013-12-11 10:09:07'), $request_time, $suffix_xyz), + array('1 second', $this->createTimestamp('2013-12-11 10:09:07'), $request_time, $granularity_3 + $langcode_en), + array('1 second', $this->createTimestamp('2013-12-11 10:09:07'), $request_time, $granularity_4 + $langcode_lolspeak), + array('2 seconds', $this->createTimestamp('2013-12-11 10:09:06'), $request_time), + array('59 seconds', $this->createTimestamp('2013-12-11 10:08:09')), + array('59 seconds', $this->createTimestamp('2013-12-11 10:08:09'), $request_time), + + // Checks for minutes and possibly seconds. + array('1 minute', $this->createTimestamp('2013-12-11 10:08:08')), + array('1 minute', $this->createTimestamp('2013-12-11 10:08:08'), $request_time), + array('1 minute 1 second', $this->createTimestamp('2013-12-11 10:08:07'), $request_time), + array('1 minute 59 seconds', $this->createTimestamp('2013-12-11 10:07:09'), $request_time), + array('2 minutes', $this->createTimestamp('2013-12-11 10:07:08'), $request_time), + array('2 minutes 1 second', $this->createTimestamp('2013-12-11 10:07:07'), $request_time), + array('2 minutes 2 seconds', $this->createTimestamp('2013-12-11 10:07:06'), $request_time), + array('2 minutes 2 seconds', $this->createTimestamp('2013-12-11 10:07:06'), $request_time, $granularity_3), + array('2 minutes 2 seconds', $this->createTimestamp('2013-12-11 10:07:06'), $request_time, $granularity_4), + array('30 minutes', $this->createTimestamp('2013-12-11 09:39:08'), $request_time), + array('59 minutes 59 seconds', $this->createTimestamp('2013-12-11 09:09:09'), $request_time), + array('59 minutes 59 seconds', $this->createTimestamp('2013-12-11 09:09:09')), + + // Checks for hours and possibly minutes or seconds. + array('1 hour', $this->createTimestamp('2013-12-11 09:09:08')), + array('1 hour', $this->createTimestamp('2013-12-11 09:09:08'), $request_time), + array('1 hour 1 second', $this->createTimestamp('2013-12-11 09:09:07')), + array('1 hour 2 seconds', $this->createTimestamp('2013-12-11 09:09:06')), + array('1 hour 1 minute', $this->createTimestamp('2013-12-11 09:08:08')), + array('1 hour 1 minute 1 second', $this->createTimestamp('2013-12-11 09:08:07'), $request_time, $granularity_3), + array('1 hour 1 minute 2 seconds', $this->createTimestamp('2013-12-11 09:08:06'), $request_time, $granularity_4), + array('1 hour 30 minutes', $this->createTimestamp('2013-12-11 08:39:08')), + array('2 hours', $this->createTimestamp('2013-12-11 08:09:08')), + array('23 hours 59 minutes', $this->createTimestamp('2013-12-10 10:10:08')), + + // Checks for days and possibly hours, minutes or seconds. + array('1 day', $this->createTimestamp('2013-12-10 10:09:08')), + array('1 day 1 second', $this->createTimestamp('2013-12-10 10:09:07')), + array('1 day 1 hour', $this->createTimestamp('2013-12-10 09:09:08')), + array('1 day 1 hour 1 minute', $this->createTimestamp('2013-12-10 09:08:07'), $request_time, $granularity_3 + $langcode_en), + array('1 day 1 hour 1 minute 1 second', $this->createTimestamp('2013-12-10 09:08:07'), $request_time, $granularity_4 + $langcode_lolspeak), + array('1 day 2 hours 2 minutes 2 seconds', $this->createTimestamp('2013-12-10 08:07:06'), $request_time, $granularity_4), + array('2 days', $this->createTimestamp('2013-12-09 10:09:08')), + array('2 days 2 minutes', $this->createTimestamp('2013-12-09 10:07:08')), + array('2 days 2 hours', $this->createTimestamp('2013-12-09 08:09:08')), + array('2 days 2 hours 2 minutes', $this->createTimestamp('2013-12-09 08:07:06'), $request_time, $granularity_3 + $langcode_en), + array('2 days 2 hours 2 minutes 2 seconds', $this->createTimestamp('2013-12-09 08:07:06'), $request_time, $granularity_4 + $langcode_lolspeak), + array('29 days', $this->createTimestamp('2013-11-12 10:09:08')), + + // Checks for months and possibly days, hours, minutes or seconds. + array('1 month', $this->createTimestamp('2013-11-11 10:09:08')), + array('1 month 1 second', $this->createTimestamp('2013-11-11 10:09:07')), + array('1 month 1 hour', $this->createTimestamp('2013-11-11 09:09:08')), + array('1 month 1 hour 1 minute', $this->createTimestamp('2013-11-11 09:08:07'), $request_time, $granularity_3), + array('1 month 1 hour 1 minute 1 second', $this->createTimestamp('2013-11-11 09:08:07'), $request_time, $granularity_4), + array('1 month 29 days', $this->createTimestamp('2013-10-13 10:09:08')), + array('1 month 30 days', $this->createTimestamp('2013-10-12 10:09:08')), + array('2 months', $this->createTimestamp('2013-10-11 10:09:08')), + array('abc 2 months 1 day xyz', $this->createTimestamp('2013-10-10 10:09:08'), $request_time, $prefix_abc + $suffix_xyz), + array('2 months 2 days', $this->createTimestamp('2013-10-09 08:07:06')), + array('2 months 2 days 2 hours', $this->createTimestamp('2013-10-09 08:07:06'), $request_time, $granularity_3), + array('2 months 2 days 2 hours 2 minutes', $this->createTimestamp('2013-10-09 08:07:06'), $request_time, $granularity_4), + array('6 months 2 days', $this->createTimestamp('2013-06-09 10:09:08')), + array('11 months 3 hours', $this->createTimestamp('2013-01-11 07:09:08')), + array('11 months 30 days', $this->createTimestamp('2012-12-12 10:09:08')), + + // Checks for years and possibly months, days, hours, minutes or seconds. + array('1 year', $this->createTimestamp('2012-12-11 10:09:08')), + array('abc 1 year 1 minute', $this->createTimestamp('2012-12-11 10:08:08'), $request_time, $prefix_abc), + array('1 year 1 day xyz', $this->createTimestamp('2012-12-10 10:09:08'), $request_time, $suffix_xyz), + array('2 years', $this->createTimestamp('2011-12-11 10:09:08')), + array('2 years 2 minutes', $this->createTimestamp('2011-12-11 10:07:08')), + array('2 years 2 days', $this->createTimestamp('2011-12-09 10:09:08')), + array('2 years 2 months 2 days', $this->createTimestamp('2011-10-09 08:07:06'), $request_time, $granularity_3), + array('2 years 2 months 2 days 2 hours', $this->createTimestamp('2011-10-09 08:07:06'), $request_time, $granularity_4), + array('10 years', $this->createTimestamp('2003-12-11 10:09:08')), + array('100 years', $this->createTimestamp('1913-12-11 10:09:08')), + ); + + return $data; + } + + /** + * Creates a UNIX timestamp given a date and time string in the format + * year-month-day hour:minute:seconds (e.g. 2013-12-11 10:09:08). + * + * @param string $dateTimeString + * The formatted date and time string. + * + * @return int + * The UNIX timestamp. + */ + private function createTimestamp($dateTimeString) { + return \DateTime::createFromFormat('Y-m-d G:i:s', $dateTimeString)->getTimestamp(); + } }