[TASK] Rebuild the calcAge functionality 31/31231/2
authorAlexander Opitz <opitz.alexander@googlemail.com>
Sat, 12 Oct 2013 14:36:25 +0000 (16:36 +0200)
committerMarkus Klein <klein.t3@mfc-linz.at>
Sun, 29 Jun 2014 15:52:20 +0000 (17:52 +0200)
We have two calcAge functions with same functionality and same issues.
So this is moved to a new DateTimeUtility class and deprecated in the
the original classes. Also time functions from GeneralUtility are moved
to the new class.

Following issues are resolved:
* Age calculation does not respect leap years.
* Age calculation may round up so something seams older than it is.
* Between days and years there are months missing, so we get now 2 months
  instead of 60 days.

Resolves: #20016
Releases: 6.3, 6.2
Change-Id: Ie323f30b1fb97b68f89d43605ccda67f219a965a
Reviewed-on: https://review.typo3.org/31231
Reviewed-by: Markus Klein
Tested-by: Markus Klein
25 files changed:
typo3/sysext/backend/Classes/Controller/EditDocumentController.php
typo3/sysext/backend/Classes/Controller/PageLayoutController.php
typo3/sysext/backend/Classes/Controller/Wizard/RteController.php
typo3/sysext/backend/Classes/Form/FormEngine.php
typo3/sysext/backend/Classes/History/RecordHistory.php
typo3/sysext/backend/Classes/Template/DocumentTemplate.php
typo3/sysext/backend/Classes/Utility/BackendUtility.php
typo3/sysext/backend/Classes/View/PageLayoutView.php
typo3/sysext/backend/Tests/Unit/Utility/BackendUtilityTest.php
typo3/sysext/core/Classes/Core/SystemEnvironmentBuilder.php
typo3/sysext/core/Classes/Utility/DateTimeUtility.php [new file with mode: 0644]
typo3/sysext/core/Classes/Utility/GeneralUtility.php
typo3/sysext/core/Tests/Unit/Utility/DateTimeUtilityTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Utility/Fixtures/DateTimeUtilityFixture.php [new file with mode: 0644]
typo3/sysext/dbal/Classes/Database/DatabaseConnection.php
typo3/sysext/extensionmanager/Classes/ViewHelpers/TimeSinceLastUpdateViewHelper.php
typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
typo3/sysext/frontend/Classes/Controller/PageInformationController.php
typo3/sysext/indexed_search/Classes/Controller/SearchController.php
typo3/sysext/indexed_search/Classes/Controller/SearchFormController.php
typo3/sysext/indexed_search/Classes/Indexer.php
typo3/sysext/install/Classes/Controller/Action/Tool/TestSetup.php
typo3/sysext/lang/locallang_core.xlf
typo3/sysext/lowlevel/Classes/CleanerCommand.php
typo3/sysext/lowlevel/Classes/OrphanRecordsCommand.php

index 062999a..482ef54 100644 (file)
@@ -998,7 +998,15 @@ class EditDocumentController {
                                                                )
                                                        )
                                                ) . '; return false;';
-                                       $buttons['undo'] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '"' . ' title="' . htmlspecialchars(sprintf($GLOBALS['LANG']->getLL('undoLastChange'), BackendUtility::calcAge(($GLOBALS['EXEC_TIME'] - $undoButtonR['tstamp']), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')))) . '">' . IconUtility::getSpriteIcon('actions-edit-undo') . '</a>';
+                                       // Undo button
+                                       $buttons['undo'] = '<a href="#"
+                                               onclick="' . htmlspecialchars($aOnClick) . '"
+                                               title="' . htmlspecialchars(
+                                                       sprintf(
+                                                               $GLOBALS['LANG']->getLL('undoLastChange'),
+                                                               \TYPO3\CMS\Core\Utility\DateTimeUtility::getAgeStringUnix($undoButtonR['tstamp'])
+                                                       )
+                                               ) . '">' . IconUtility::getSpriteIcon('actions-edit-undo') . '</a>';
                                }
                                if ($this->getNewIconMode($this->firstEl['table'], 'showHistory')) {
                                        $aOnClick = 'window.location.href=' .
index d72366a..01dba88 100644 (file)
@@ -845,7 +845,6 @@ class PageLayoutController {
                $dblist->setLMargin = 0;
                $dblist->doEdit = $this->EDIT_CONTENT;
                $dblist->ext_CALC_PERMS = $this->CALC_PERMS;
-               $dblist->agePrefixes = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears');
                $dblist->id = $this->id;
                $dblist->nextThree = MathUtility::forceIntegerInRange($this->modTSconfig['properties']['editFieldsAtATime'], 0, 10);
                $dblist->option_showBigButtons = $this->modTSconfig['properties']['disableBigButtons'] === '0';
@@ -1110,7 +1109,12 @@ class PageLayoutController {
                                                                        )
                                                                )
                                                        ) . '; return false;') . '"
-                                               title="' . htmlspecialchars(sprintf($GLOBALS['LANG']->getLL('undoLastChange'), BackendUtility::calcAge(($GLOBALS['EXEC_TIME'] - $this->undoButtonR['tstamp']), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')))) . '">' . IconUtility::getSpriteIcon('actions-edit-undo') . '</a>';
+                                               title="' . htmlspecialchars(
+                                                       sprintf(
+                                                               $GLOBALS['LANG']->getLL('undoLastChange'),
+                                                               \TYPO3\CMS\Core\Utility\DateTimeUtility::getAgeStringUnix($this->undoButtonR['tstamp'])
+                                                       )
+                                               ) . '">' . IconUtility::getSpriteIcon('actions-edit-undo') . '</a>';
                                        // History button
                                        $buttons['history_record'] = '<a href="#"
                                                onclick="' . htmlspecialchars('jumpToUrl(' .
index 4e85266..4cd4e04 100644 (file)
@@ -243,7 +243,15 @@ class RteController {
                                                                'returnUrl' => $this->R_URI,
                                                        )
                                                )
-                                       ) . '; return false;') . '">' . '<img' . IconUtility::skinImg($this->doc->backPath, 'gfx/undo.gif') . ' class="c-inputButton" title="' . htmlspecialchars(sprintf($GLOBALS['LANG']->getLL('rte_undoLastChange'), BackendUtility::calcAge(($GLOBALS['EXEC_TIME'] - $undoButtonR['tstamp']), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')))) . '" alt="" />' . '</a>';
+                                       ) . '; return false;') . '">' . 
+                                       '<img' . IconUtility::skinImg($this->doc->backPath, 'gfx/undo.gif') .
+                                       ' class="c-inputButton" title="' .
+                                       htmlspecialchars(
+                                               sprintf(
+                                                       $GLOBALS['LANG']->getLL('rte_undoLastChange'),
+                                                       \TYPO3\CMS\Core\Utility\DateTimeUtility::getAgeStringUnix($undoButtonR['tstamp'])
+                                               )
+                                       ) . '" alt="" /></a>';
                        }
                        // Shortcut
                        if ($GLOBALS['BE_USER']->mayMakeShortcut()) {
index 512d02c..d57188a 100644 (file)
@@ -3249,7 +3249,7 @@ TBE_EDITOR.customEvalFunctions[\'' . $evalData . '\'] = function(value) {
                                        $value = '';
                                }
                                if ($config['format.']['appendAge']) {
-                                       $value .= ' (' . BackendUtility::calcAge(($GLOBALS['EXEC_TIME'] - $itemValue), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')) . ')';
+                                       $value .= ' (' . \TYPO3\CMS\Core\Utility\DateTimeUtility::getAgeStringUnix($itemValue) . ')';
                                }
                                $itemValue = $value;
                                break;
index 97c5994..5183473 100644 (file)
@@ -407,7 +407,7 @@ class RecordHistory {
                        // remove first link
                        $singleLine[] = htmlspecialchars(BackendUtility::datetime($entry['tstamp']));
                        // add time
-                       $singleLine[] = htmlspecialchars(BackendUtility::calcAge($GLOBALS['EXEC_TIME'] - $entry['tstamp'], $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')));
+                       $singleLine[] = htmlspecialchars(\TYPO3\CMS\Core\Utility\DateTimeUtility::getAgeStringUnix($entry['tstamp']));
                        // add age
                        $singleLine[] = htmlspecialchars($userName);
                        // add user name
index 02b9175..fc71ca3 100644 (file)
@@ -726,9 +726,12 @@ function jumpToUrl(URL) {
         */
        public function parseTime() {
                if ($this->parseTimeFlag && $GLOBALS['BE_USER']->isAdmin()) {
-                       return '<p>(ParseTime: ' . (GeneralUtility::milliseconds() - $GLOBALS['PARSETIME_START']) . ' ms</p>
-                                       <p>REQUEST_URI-length: ' . strlen(GeneralUtility::getIndpEnv('REQUEST_URI')) . ')</p>';
+                       return '<p>(ParseTime: ' .
+                               (\TYPO3\CMS\Core\Utility\DateTimeUtility::milliseconds() - $GLOBALS['PARSETIME_START']) . ' ms</p>' .
+                               '<p>REQUEST_URI-length: ' . strlen(GeneralUtility::getIndpEnv('REQUEST_URI')) . ')</p>';
                }
+
+               return '';
        }
 
        /**
index 7843c64..8796085 100644 (file)
@@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Versioning\VersionState;
 use TYPO3\CMS\Frontend\Page\PageRepository;
+use TYPO3\CMS\Core\Utility\DateTimeUtility;
 
 /**
  * Standard functions available for the TYPO3 backend.
@@ -1416,27 +1417,16 @@ class BackendUtility {
         * Returns the "age" in minutes / hours / days / years of the number of $seconds inputted.
         *
         * @param integer $seconds Seconds could be the difference of a certain timestamp and time()
-        * @param string $labels Labels should be something like ' min| hrs| days| yrs| min| hour| day| year'. This value is typically delivered by this function call: $GLOBALS["LANG"]->sL("LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears")
+        * @param string $labels Labels should be something like ' min| hrs| days| yrs| min| hour| day| year'.
+        *  This value is typically delivered by this function call: $GLOBALS["LANG"]->sL("LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears")
+        *
         * @return string Formatted time
+        * @deprecated since 6.2, will be removed two versions later, use \TYPO3\CMS\Core\Utility\DateTimeUtility::getAgeStringUnix
+        *  or \TYPO3\CMS\Core\Utility\DateTimeUtility::getSimpleAgeString
         */
        static public function calcAge($seconds, $labels = ' min| hrs| days| yrs| min| hour| day| year') {
-               $labelArr = explode('|', $labels);
-               $absSeconds = abs($seconds);
-               $sign = $seconds < 0 ? -1 : 1;
-               if ($absSeconds < 3600) {
-                       $val = round($absSeconds / 60);
-                       $seconds = $sign * $val . ($val == 1 ? $labelArr[4] : $labelArr[0]);
-               } elseif ($absSeconds < 24 * 3600) {
-                       $val = round($absSeconds / 3600);
-                       $seconds = $sign * $val . ($val == 1 ? $labelArr[5] : $labelArr[1]);
-               } elseif ($absSeconds < 365 * 24 * 3600) {
-                       $val = round($absSeconds / (24 * 3600));
-                       $seconds = $sign * $val . ($val == 1 ? $labelArr[6] : $labelArr[2]);
-               } else {
-                       $val = round($absSeconds / (365 * 24 * 3600));
-                       $seconds = $sign * $val . ($val == 1 ? $labelArr[7] : $labelArr[3]);
-               }
-               return $seconds;
+               GeneralUtility::logDeprecatedFunction();
+               return DateTimeUtility::getSimpleAgeString($seconds, $labels);
        }
 
        /**
@@ -1449,7 +1439,16 @@ class BackendUtility {
         * @return string
         */
        static public function dateTimeAge($tstamp, $prefix = 1, $date = '') {
-               return $tstamp ? ($date == 'date' ? self::date($tstamp) : self::datetime($tstamp)) . ' (' . self::calcAge($prefix * ($GLOBALS['EXEC_TIME'] - $tstamp), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')) . ')' : '';
+               if (!$tstamp) {
+                       return '';
+               }
+               $date = $date == 'date'
+                       ? self::date($tstamp)
+                       : self::datetime($tstamp);
+               $age = $prefix === 1
+                       ? DateTimeUtility::getTimeDiffStringUnix($GLOBALS['EXEC_TIME'], $tstamp)
+                       : DateTimeUtility::getTimeDiffStringUnix($tstamp, $GLOBALS['EXEC_TIME']);
+               return $date . ' (' . $age . ')';
        }
 
        /**
@@ -2144,7 +2143,7 @@ class BackendUtility {
                                                                $value = $value !== $emptyValue ? strtotime($value) : 0;
                                                        }
                                                        if (!empty($value)) {
-                                                               $l = self::date($value) . ' (' . ($GLOBALS['EXEC_TIME'] - $value > 0 ? '-' : '') . self::calcAge(abs(($GLOBALS['EXEC_TIME'] - $value)), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')) . ')';
+                                                               $l = static::dateTimeAge($value, -1, 'date');
                                                        }
                                                } elseif (GeneralUtility::inList($theColConf['eval'], 'time')) {
                                                        if (!empty($value)) {
@@ -3134,9 +3133,19 @@ class BackendUtility {
                                        $userName = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.unknownUser');
                                }
                                $GLOBALS['LOCKED_RECORDS'][$row['record_table'] . ':' . $row['record_uid']] = $row;
-                               $GLOBALS['LOCKED_RECORDS'][$row['record_table'] . ':' . $row['record_uid']]['msg'] = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.lockedRecordUser'), $userType, $userName, self::calcAge($GLOBALS['EXEC_TIME'] - $row['tstamp'], $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')));
+                               $GLOBALS['LOCKED_RECORDS'][$row['record_table'] . ':' . $row['record_uid']]['msg'] = sprintf(
+                                       $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.lockedRecordUser'),
+                                       $userType,
+                                       $userName,
+                                       DateTimeUtility::getAgeStringUnix($row['tstamp'])
+                               );
                                if ($row['record_pid'] && !isset($GLOBALS['LOCKED_RECORDS'][($row['record_table'] . ':' . $row['record_pid'])])) {
-                                       $GLOBALS['LOCKED_RECORDS']['pages:' . $row['record_pid']]['msg'] = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.lockedRecordUser_content'), $userType, $userName, self::calcAge($GLOBALS['EXEC_TIME'] - $row['tstamp'], $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')));
+                                       $GLOBALS['LOCKED_RECORDS']['pages:' . $row['record_pid']]['msg'] = sprintf(
+                                               $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.lockedRecordUser_content'),
+                                               $userType,
+                                               $userName,
+                                               DateTimeUtility::getAgeStringUnix($row['tstamp'])
+                                       );
                                }
                        }
                        $GLOBALS['TYPO3_DB']->sql_free_result($res);
index 2a1e602..e92a7cd 100644 (file)
@@ -75,12 +75,6 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
         */
        public $doEdit = 1;
 
-       // Age prefixes for displaying times. May be set externally to localized values.
-       /**
-        * @todo Define visibility
-        */
-       public $agePrefixes = ' min| hrs| days| yrs| min| hour| day| year';
-
        // Array of tables to be listed by the Web > Page module in addition to the default tables.
        /**
         * @todo Define visibility
@@ -2100,6 +2094,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
         *
         *****************************************/
 
+
        /**
         * Creates a menu of the tables that can be listed by this function
         * Only tables which has records on the page will be included.
index ce8e676..c39dbc3 100644 (file)
@@ -24,95 +24,6 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 class BackendUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
 
        ///////////////////////////////////////
-       // Tests concerning calcAge
-       ///////////////////////////////////////
-       /**
-        * Data provider for calcAge function
-        *
-        * @return array
-        */
-       public function calcAgeDataProvider() {
-               return array(
-                       'Single year' => array(
-                               'seconds' => 60 * 60 * 24 * 365,
-                               'expectedLabel' => '1 year'
-                       ),
-                       'Plural years' => array(
-                               'seconds' => 60 * 60 * 24 * 365 * 2,
-                               'expectedLabel' => '2 yrs'
-                       ),
-                       'Single negative year' => array(
-                               'seconds' => 60 * 60 * 24 * 365 * -1,
-                               'expectedLabel' => '-1 year'
-                       ),
-                       'Plural negative years' => array(
-                               'seconds' => 60 * 60 * 24 * 365 * 2 * -1,
-                               'expectedLabel' => '-2 yrs'
-                       ),
-                       'Single day' => array(
-                               'seconds' => 60 * 60 * 24,
-                               'expectedLabel' => '1 day'
-                       ),
-                       'Plural days' => array(
-                               'seconds' => 60 * 60 * 24 * 2,
-                               'expectedLabel' => '2 days'
-                       ),
-                       'Single negative day' => array(
-                               'seconds' => 60 * 60 * 24 * -1,
-                               'expectedLabel' => '-1 day'
-                       ),
-                       'Plural negative days' => array(
-                               'seconds' => 60 * 60 * 24 * 2 * -1,
-                               'expectedLabel' => '-2 days'
-                       ),
-                       'Single hour' => array(
-                               'seconds' => 60 * 60,
-                               'expectedLabel' => '1 hour'
-                       ),
-                       'Plural hours' => array(
-                               'seconds' => 60 * 60 * 2,
-                               'expectedLabel' => '2 hrs'
-                       ),
-                       'Single negative hour' => array(
-                               'seconds' => 60 * 60 * -1,
-                               'expectedLabel' => '-1 hour'
-                       ),
-                       'Plural negative hours' => array(
-                               'seconds' => 60 * 60 * 2 * -1,
-                               'expectedLabel' => '-2 hrs'
-                       ),
-                       'Single minute' => array(
-                               'seconds' => 60,
-                               'expectedLabel' => '1 min'
-                       ),
-                       'Plural minutes' => array(
-                               'seconds' => 60 * 2,
-                               'expectedLabel' => '2 min'
-                       ),
-                       'Single negative minute' => array(
-                               'seconds' => 60 * -1,
-                               'expectedLabel' => '-1 min'
-                       ),
-                       'Plural negative minutes' => array(
-                               'seconds' => 60 * 2 * -1,
-                               'expectedLabel' => '-2 min'
-                       ),
-                       'Zero seconds' => array(
-                               'seconds' => 0,
-                               'expectedLabel' => '0 min'
-                       )
-               );
-       }
-
-       /**
-        * @test
-        * @dataProvider calcAgeDataProvider
-        */
-       public function calcAgeReturnsExpectedValues($seconds, $expectedLabel) {
-               $this->assertSame($expectedLabel, BackendUtility::calcAge($seconds));
-       }
-
-       ///////////////////////////////////////
        // Tests concerning getProcessedValue
        ///////////////////////////////////////
        /**
index cf02ea3..713af60 100644 (file)
@@ -193,6 +193,7 @@ class SystemEnvironmentBuilder {
         */
        static protected function requireBaseClasses() {
                require_once __DIR__ . '/../Utility/GeneralUtility.php';
+               require_once __DIR__ . '/../Utility/DateTimeUtility.php';
                require_once __DIR__ . '/../Utility/ArrayUtility.php';
                require_once __DIR__ . '/../Utility/PathUtility.php';
                require_once __DIR__ . '/../SingletonInterface.php';
@@ -267,7 +268,7 @@ class SystemEnvironmentBuilder {
         */
        static protected function initializeGlobalTimeTrackingVariables() {
                // Set PARSETIME_START to the system time in milliseconds.
-               $GLOBALS['PARSETIME_START'] = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
+               $GLOBALS['PARSETIME_START'] = \TYPO3\CMS\Core\Utility\DateTimeUtility::milliseconds();
                // Microtime of (nearly) script start
                $GLOBALS['TYPO3_MISC']['microtime_start'] = microtime(TRUE);
                // EXEC_TIME is set so that the rest of the script has a common value for the script execution time
diff --git a/typo3/sysext/core/Classes/Utility/DateTimeUtility.php b/typo3/sysext/core/Classes/Utility/DateTimeUtility.php
new file mode 100644 (file)
index 0000000..3fe2ff8
--- /dev/null
@@ -0,0 +1,315 @@
+<?php
+namespace TYPO3\CMS\Core\Utility;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2014 Alexander Opitz <opitz.alexander@googlemail.com>
+ *  (c) 2014 Markus Klein <klein.t3@mfc-linz.at>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+use TYPO3\CMS\Lang\LanguageService;
+
+/**
+ * This class has functions for handling date and time. Especially differences between two dates as readable string.
+ *
+ * @author Alexander Opitz <opitz@pluspol.info>
+ * @author Markus Klein <klein.t3@mfc-linz.at>
+ */
+class DateTimeUtility {
+
+       /**
+        * @var int for usage with the getSimpleAgeString or round function
+        */
+       const CEIL = 10;
+
+       /**
+        * @var int for usage with the getSimpleAgeString or round function
+        */
+       const FLOOR = 11;
+
+       /**
+        * Returns the given microtime as milliseconds.
+        *
+        * @param string $microtime Microtime as "msec sec" string given by php function microtime
+        * @return int Microtime input string converted to an int (milliseconds)
+        */
+       static public function convertMicrotime($microtime) {
+               $parts = explode(' ', $microtime);
+               return (int)round(($parts[0] + $parts[1]) * 1000);
+       }
+
+       /**
+        * Gets the unixtime as milliseconds.
+        *
+        * @return int The unixtime as milliseconds
+        */
+       static public function milliseconds() {
+               return (int)round(microtime(TRUE) * 1000);
+       }
+
+       /**
+        * Returns a string representation of the difference between timestamps in minutes / hours / days / months / years
+        * with a given label.
+        *
+        * @param int $startTime Unix timestamp for calculating difference of
+        * @param int $endTime Unix timestamp for calculating difference to
+        * @param string|array|NULL $labels Labels should be something like ' mins| hrs| days| months| yrs| min| hour| day| month| year'
+        *  This value is typically delivered by this function call:
+        *  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysMonthsYears')
+        *  Or using the array returned by splitTimeUnitsFromLabel()
+        * @return string Formatted time difference
+        */
+       static public function getTimeDiffStringUnix($startTime, $endTime, $labels = NULL) {
+               return static::getTimeDiffString(
+                       new \DateTime('@' . $startTime),
+                       new \DateTime('@' . $endTime),
+                       $labels
+               );
+       }
+
+       /**
+        * Returns a string representation of the difference between DateTimes in minutes / hours / days / months / years
+        * with a given label.
+        *
+        * @param \DateTime $startDateTime Unix timestamp for calculating difference of
+        * @param \DateTime $endDateTime Unix timestamp for calculating difference to
+        * @param string|array|NULL $labels Labels should be something like ' mins| hrs| days| months| yrs| min| hour| day| month| year'
+        *  This value is typically delivered by this function call:
+        *  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysMonthsYears')
+        *  Or using the array returned by splitTimeUnitsFromLabel()
+        * @return string Formatted time difference
+        */
+       static public function getTimeDiffString(\DateTime $startDateTime, \DateTime $endDateTime, $labels = NULL) {
+               if (!is_array($labels) || empty($labels)) {
+                       $labels = static::splitTimeUnitsFromLabel($labels);
+               }
+
+               $dateDiff = $startDateTime->diff($endDateTime);
+
+               if ($dateDiff->y > 0) {
+                       $value = $dateDiff->y;
+                       $label =  'year';
+               } elseif ($dateDiff->m > 0 && isset($labels['months'])) {
+                       $value = $dateDiff->m;
+                       $label =  'month';
+               } elseif ($dateDiff->days > 0) {
+                       $value = $dateDiff->days;
+                       $label =  'day';
+               } elseif ($dateDiff->h > 0) {
+                       $value = $dateDiff->h;
+                       $label =  'hour';
+               } else {
+                       $value = $dateDiff->i;
+                       $label =  'min';
+               }
+
+               // Get real label depending on singular/plural
+               $label = $labels[$label . ($value === 1 ? '' : 's')];
+
+               if ($dateDiff->invert === 1) {
+                       $value *= -1;
+               }
+
+               return $value . $label;
+       }
+
+       /**
+        * Converts the old plural, old singular/plural and the new singular/plural pipe split string
+        * into an array with known unit names as keys.
+        *
+        * @param string|NULL $labels Labels should be something like ' min| hrs| days| months| yrs| min| hour| day| month| year'
+        *  This value is typically delivered by this function call:
+        *  $GLOBALS['LANG']->sL("LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysMonthsYears")
+        * @return array String split array
+        */
+       static public function splitTimeUnitsFromLabel($labels = NULL) {
+               if (NULL === $labels) {
+                       $lang = self::getLanguageService();
+                       $tsfe = self::getTypoScriptFrontendController();
+                       if ($lang) {
+                               $labels = $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysMonthsYears');
+                       } elseif ($tsfe) {
+                               $labels = $tsfe->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysMonthsYears');
+                       }
+                       // Couldn't determine from local config so take default value.
+                       if (empty($labels)) {
+                               $labels = ' min| hrs| days| months| yrs| min| hour| day| month| year';
+                       }
+               } else {
+                       $labels = str_replace('"', '', $labels);
+               }
+
+               $labelArr = explode('|', $labels);
+               $resultArr = array();
+
+               if (count($labelArr) === 4) {
+                       // Old plural labels string, add plural as singular
+                       $labelArr = array_merge($labelArr, $labelArr);
+               }
+
+               switch (count($labelArr)) {
+                       case 8:
+                               // Old singular and plural labels string
+                               $resultArr['min'] = $labelArr[4];
+                               $resultArr['mins'] = $labelArr[0];
+                               $resultArr['hour'] = $labelArr[5];
+                               $resultArr['hours'] = $labelArr[1];
+                               $resultArr['day'] = $labelArr[6];
+                               $resultArr['days'] = $labelArr[2];
+                               $resultArr['year'] = $labelArr[7];
+                               $resultArr['years'] = $labelArr[3];
+                               break;
+                       case 10:
+                               // New singular and plural labels string (with month)
+                               $resultArr['min'] = $labelArr[5];
+                               $resultArr['mins'] = $labelArr[0];
+                               $resultArr['hour'] = $labelArr[6];
+                               $resultArr['hours'] = $labelArr[1];
+                               $resultArr['day'] = $labelArr[7];
+                               $resultArr['days'] = $labelArr[2];
+                               $resultArr['month'] = $labelArr[8];
+                               $resultArr['months'] = $labelArr[3];
+                               $resultArr['year'] = $labelArr[9];
+                               $resultArr['years'] = $labelArr[4];
+                               break;
+                       default:
+                               static::splitTimeUnitsFromLabel(NULL);
+               }
+
+               return $resultArr;
+       }
+
+       /**
+        * Returns the "age" in minutes / hours / days / months / years depending of the number of $seconds inputted.
+        *
+        * @param int $seconds Seconds could be the difference of a certain timestamp and time()
+        * @param string|array|NULL $labels Labels should be something like ' min| hrs| days| months| yrs| min| hour| day| month| year'
+        *  This value is typically delivered by this function call:
+        *  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysMonthsYears')
+        *  Or using the array returned by splitTimeUnitsFromLabel()
+        * @param int $method Method to use to round the result (PHP_ROUND_HALF_UP, PHP_ROUND_HALF_DOWN,
+        *  PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD - round, 10 - ceil, 11 - floor)
+        * @return string Formatted time
+        */
+       static public function getSimpleAgeString($seconds, $labels = NULL, $method = PHP_ROUND_HALF_UP) {
+               if (!is_array($labels) || empty($labels)) {
+                       $labels = static::splitTimeUnitsFromLabel($labels);
+               }
+
+               $sign = $seconds < 0 ? -1 : 1;
+               $seconds = abs($seconds);
+               if ($seconds < 3600) {
+                       $roundedResult = static::round($seconds / 60, $method);
+                       $seconds = $sign * $roundedResult . ($roundedResult == 1 ? $labels['mins'] : $labels['min']);
+               } elseif ($seconds < 24 * 3600) {
+                       $roundedResult = static::round($seconds / 3600, $method);
+                       $seconds = $sign * $roundedResult . ($roundedResult == 1 ? $labels['hour'] : $labels['hours']);
+               } elseif ($seconds < 30 * 24 * 3600 || (!isset($labels['month']) && $seconds < 365 * 24 * 3600)) {
+                       $roundedResult = static::round($seconds / (24 * 3600), $method);
+                       $seconds = $sign * $roundedResult . ($roundedResult == 1 ? $labels['day'] : $labels['days']);
+               } elseif (isset($labels['month']) && $seconds < 365 * 24 * 3600) {
+                       $roundedResult = static::round($seconds / (30 * 24 * 3600), $method);
+                       $seconds = $sign * $roundedResult . ($roundedResult == 1 ? $labels['month'] : $labels['months']);
+               } else {
+                       $roundedResult = static::round($seconds / (365 * 24 * 3600), $method);
+                       $seconds = $sign * $roundedResult . ($roundedResult == 1 ? $labels['year'] : $labels['years']);
+               }
+
+               return $seconds;
+       }
+
+       /**
+        * Returns a string representation of the age of a timestamps in minutes / hours / days / months / years
+        * with a given label. $GLOBALS['EXEC_TIME'] is taken as "now".
+        *
+        * @param int $time Unix timestamp for calculating age of
+        * @param string|array|NULL $labels Labels should be something like ' min| hrs| days| months| yrs| min| hour| day| month| year'
+        *  This value is typically delivered by this function call:
+        *  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysMonthsYears')
+     *  Or using the array returned by splitTimeUnitsFromLabel()
+        * @return string Formatted time age
+        */
+       static public function getAgeStringUnix($time, $labels = NULL) {
+               return static::getTimeDiffStringUnix($time, $GLOBALS['EXEC_TIME'], $labels);
+       }
+
+       /**
+        * Returns a string representation of the age of a DateTime in minutes / hours / days / months / years
+        * with a given label. $GLOBALS['EXEC_TIME'] is taken as "now".
+        *
+        * @param \DateTime|$time DateTime for calculating age of
+        * @param string|array|NULL $labels Labels should be something like ' min| hrs| days| months| yrs| min| hour| day| month| year'
+        *  This value is typically delivered by this function call:
+        *  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysMonthsYears')
+        *  Or using the array returned by splitTimeUnitsFromLabel()
+        * @return string Formatted time age
+        */
+       static public function getAgeString(\DateTime $time, $labels = NULL) {
+               return static::getTimeDiffString(
+                       $time,
+                       new \DateTime('@' . $GLOBALS['EXEC_TIME']),
+                       $labels
+               );
+       }
+
+       /**
+        * Rounds the $value in the mathematical way of the choosen method.
+        *
+        * @param mixed $value The value to round
+        * @param int $method Method to use to round the result (PHP_ROUND_HALF_UP, PHP_ROUND_HALF_DOWN,
+        *  PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD, DateTimeUtility::CEIL, DateTimeUtility::FLOOR)
+        * @return int
+        */
+       static public function round($value, $method = PHP_ROUND_HALF_UP) {
+               switch ($method) {
+                       case DateTimeUtility::CEIL:
+                               $value = ceil($value);
+                               break;
+
+                       case DateTimeUtility::FLOOR:
+                               $value = floor($value);
+                               break;
+
+                       default:
+                               $value = round($value, 0, $method);
+               }
+
+               return (int)$value;
+       }
+
+       /**
+        * @return LanguageService|NULL
+        */
+       static protected function getLanguageService() {
+               return isset($GLOBALS['LANG']) ? $GLOBALS['LANG'] : NULL;
+       }
+
+       /**
+        * @return TypoScriptFrontendController|NULL
+        */
+       static protected function getTypoScriptFrontendController() {
+               return isset($GLOBALS['TSFE']) ? $GLOBALS['TSFE'] : NULL;
+       }
+}
index 7f0567f..857f954 100644 (file)
@@ -24,7 +24,7 @@ namespace TYPO3\CMS\Core\Utility;
  * USE:
  * The class is intended to be used without creating an instance of it.
  * So: Don't instantiate - call functions with "\TYPO3\CMS\Core\Utility\GeneralUtility::" prefixed the function name.
- * So use \TYPO3\CMS\Core\Utility\GeneralUtility::[method-name] to refer to the functions, eg. '\TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds()'
+ * So use \TYPO3\CMS\Core\Utility\GeneralUtility::[method-name] to refer to the functions, eg. '\TYPO3\CMS\Core\Utility\GeneralUtility::_GP()'
  *
  * @author Kasper Skårhøj <kasperYYYY@typo3.com>
  */
@@ -995,10 +995,11 @@ class GeneralUtility {
         *
         * @param string $microtime Microtime
         * @return integer Microtime input string converted to an integer (milliseconds)
+        * @deprecated since 6.2, will be removed two versions later, use DateTimeUtility::convertMicrotime
         */
        static public function convertMicrotime($microtime) {
-               $parts = explode(' ', $microtime);
-               return round(($parts[0] + $parts[1]) * 1000);
+               static::logDeprecatedFunction();
+               return DateTimeUtility::convertMicrotime($microtime);
        }
 
        /**
@@ -3597,9 +3598,11 @@ Connection: close
         * Gets the unixtime as milliseconds.
         *
         * @return integer The unixtime as milliseconds
+        * @deprecated since 6.2, will be removed two versions later, use DateTimeUtility::milliseconds
         */
        static public function milliseconds() {
-               return round(microtime(TRUE) * 1000);
+               static::logDeprecatedFunction();
+               return DateTimeUtility::milliseconds();
        }
 
        /**
diff --git a/typo3/sysext/core/Tests/Unit/Utility/DateTimeUtilityTest.php b/typo3/sysext/core/Tests/Unit/Utility/DateTimeUtilityTest.php
new file mode 100644 (file)
index 0000000..8b330cc
--- /dev/null
@@ -0,0 +1,523 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Utility;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Alexander Opitz <opitz.alexander@googlemail.com>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+use TYPO3\CMS\Core\Tests\Unit\Utility\Fixtures\DateTimeUtilityFixture;
+use TYPO3\CMS\Core\Utility\DateTimeUtility;
+
+/**
+ * Test case
+ *
+ * @author Alexander Opitz <opitz@pluspol.info>
+ */
+class DateTimeUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
+
+       /**
+        * Test the converting the string output of microtime into an float/double
+        * @test
+        */
+       public function convertMicrotimeProperlyConvertsAMicrotime() {
+               $this->assertSame(
+                       1381567522451,
+                       DateTimeUtility::convertMicrotime('0.45148500 1381567522')
+               );
+       }
+
+       /**
+        * Test the converting the string output of microtime into an float/double
+        * @test
+        */
+       public function getTimeDiffStringUnixCreatesCorrectStringResult() {
+               DateTimeUtilityFixture::$mockGetTimeDiffString = '1 foo';
+
+               $this->assertSame(
+                         '1 foo',
+                       DateTimeUtilityFixture::getTimeDiffStringUnix(500, time(), 'foo|bar')
+               );
+               DateTimeUtilityFixture::$mockGetTimeDiffString = '';
+       }
+
+       ///////////////////////////////////////
+       // Tests concerning getTimeDiffString
+       ///////////////////////////////////////
+       /**
+        * Data provider for getTimeDiffString function
+        *
+        * @return array
+        */
+       public function getTimeDiffStringProvider() {
+               $baseTime = new \DateTime();
+               return array(
+                       'Single year' => array(
+                               'time1' => new \DateTime('-1year'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '1 testYear'
+                       ),
+                       'Plural years' => array(
+                               'time1' => new \DateTime('-2years'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '2 testYears'
+                       ),
+                       'Single negative year' => array(
+                               'time1' => new \DateTime('+1year'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-1 testYear'
+                       ),
+                       'Plural negative years' => array(
+                               'time1' => new \DateTime('+2years'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-2 testYears'
+                       ),
+                       'Single month' => array(
+                               'time1' => new \DateTime('-1month'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '1 testMonth'
+                       ),
+                       'Plural months' => array(
+                               'time1' => new \DateTime('-2months'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '2 testMonths'
+                       ),
+                       'Single negative month' => array(
+                               'time1' => new \DateTime('+1month'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-1 testMonth'
+                       ),
+                       'Plural negative months' => array(
+                               'time1' => new \DateTime('+2months'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-2 testMonths'
+                       ),
+                       'Single day' => array(
+                               'time1' => new \DateTime('-1day'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '1 testDay'
+                       ),
+                       'Plural days' => array(
+                               'time1' => new \DateTime('-2days'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '2 testDays'
+                       ),
+                       'Single negative day' => array(
+                               'time1' => new \DateTime('+1day'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-1 testDay'
+                       ),
+                       'Plural negative days' => array(
+                               'time1' => new \DateTime('+2days'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-2 testDays'
+                       ),
+                       'Single hour' => array(
+                               'time1' => new \DateTime('-1hour'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '1 testHour'
+                       ),
+                       'Plural hours' => array(
+                               'time1' => new \DateTime('-2hours'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '2 testHours'
+                       ),
+                       'Single negative hour' => array(
+                               'time1' => new \DateTime('+1hour'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-1 testHour'
+                       ),
+                       'Plural negative hours' => array(
+                               'time1' => new \DateTime('+2hours'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-2 testHours'
+                       ),
+                       'Single minute' => array(
+                               'time1' => new \DateTime('-1min'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '1 testMinute'
+                       ),
+                       'Plural minutes' => array(
+                               'time1' => new \DateTime('-2min'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '2 testMinutes'
+                       ),
+                       'Single negative minute' => array(
+                               'time1' => new \DateTime('+1min'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-1 testMinute'
+                       ),
+                       'Plural negative minutes' => array(
+                               'time1' => new \DateTime('+2min'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-2 testMinutes'
+                       ),
+                       'Zero seconds' => array(
+                               'time1' => new \DateTime(),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '0 testMinutes'
+                       )
+               );
+       }
+
+       /**
+        * Test the converting the string output of microtime into an float/double
+        * @test
+        * @dataProvider getTimeDiffStringProvider
+        */
+       public function getTimeDiffStringCreatesCorrectStringResult($time1, $time2, $result) {
+               $this->assertSame(
+                         $result,
+                         DateTimeUtility::getTimeDiffString(
+                               $time1,
+                               $time2,
+                               array(
+                                       'min' => ' testMinute',
+                                       'mins' => ' testMinutes',
+                                       'hour' => ' testHour',
+                                       'hours' => ' testHours',
+                                       'day' => ' testDay',
+                                       'days' => ' testDays',
+                                       'month' => ' testMonth',
+                                       'months' => ' testMonths',
+                                       'year' => ' testYear',
+                                       'years' => ' testYears',
+                               )
+                       )
+               );
+       }
+
+       /**
+        * Data provider for getTimeDiffString function
+        * For the backward compatible version without month
+        *
+        * @return array
+        */
+       public function getTimeDiffStringWithoutMonthProvider() {
+               $baseTime = new \DateTime();
+               return array(
+                       'Single year' => array(
+                               'time1' => new \DateTime('-1year'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '1 testYear'
+                       ),
+                       'Single negative year' => array(
+                               'time1' => new \DateTime('+1year'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-1 testYear'
+                       ),
+                       'Single month' => array(
+                               'time1' => new \DateTime('-30days'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '30 testDays'
+                       ),
+                       'Plural months' => array(
+                               'time1' => new \DateTime('-90days'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '90 testDays'
+                       ),
+                       'Single negative month' => array(
+                               'time1' => new \DateTime('+30days'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-30 testDays'
+                       ),
+                       'Plural negative months' => array(
+                               'time1' => new \DateTime('+90days'),
+                               'time2' => $baseTime,
+                               'expectedLabel' => '-90 testDays'
+                       ),
+               );
+       }
+
+       /**
+        * Test the converting the string output of microtime into an float/double
+        * @test
+        * @dataProvider getTimeDiffStringWithoutMonthProvider
+        */
+       public function getTimeDiffStringWithoutMonthCreatesCorrectStringResult($time1, $time2, $result) {
+               $this->assertSame(
+                       $result,
+                       DateTimeUtility::getTimeDiffString(
+                               $time1,
+                               $time2,
+                               array(
+                                       'min' => ' testMinute',
+                                       'mins' => ' testMinutes',
+                                       'hour' => ' testHour',
+                                       'hours' => ' testHours',
+                                       'day' => ' testDay',
+                                       'days' => ' testDays',
+                                       'year' => ' testYear',
+                                       'years' => ' testYears',
+                               )
+                       )
+               );
+       }
+
+       ///////////////////////////////////////
+       // Tests concerning splitTimeUnitsFromLabel
+       ///////////////////////////////////////
+       /**
+        * Test the converting of the pipe split time units into an array
+        * @test
+        */
+       public function splitTimeUnitsFromLabelOldPlural() {
+               $this->assertSame(
+                         array(
+                               'min' => ' mins',
+                               'mins' => ' mins',
+                               'hour' => ' hrs',
+                               'hours' => ' hrs',
+                               'day' => ' days',
+                               'days' => ' days',
+                               'year' => ' yrs',
+                               'years' => ' yrs',
+                         ),
+                         DateTimeUtility::splitTimeUnitsFromLabel('" mins| hrs| days| yrs"')
+               );
+       }
+
+       /**
+        * Test the converting of the pipe split time units into an array
+        * @test
+        */
+       public function splitTimeUnitsFromLabelOldSingularPlural() {
+               $this->assertSame(
+                         array(
+                               'min' => ' min',
+                               'mins' => ' min',
+                               'hour' => ' hour',
+                               'hours' => ' hrs',
+                               'day' => ' day',
+                               'days' => ' days',
+                               'year' => ' year',
+                               'years' => ' yrs',
+                         ),
+                         DateTimeUtility::splitTimeUnitsFromLabel(' min| hrs|" days"| yrs| min| hour| day| year')
+               );
+       }
+
+       /**
+        * Test the converting of the pipe split time units into an array
+        * @test
+        */
+       public function splitTimeUnitsFromLabelNewSingularPlural() {
+               $this->assertSame(
+                         array(
+                               'min' => ' min',
+                               'mins' => ' mins',
+                               'hour' => ' hour',
+                               'hours' => ' hours',
+                               'day' => ' day',
+                               'days' => ' days',
+                               'month' => ' month',
+                               'months' => ' months',
+                               'year' => ' year',
+                               'years' => ' years',
+                         ),
+                         DateTimeUtility::splitTimeUnitsFromLabel(' mins| hours| days| months| years| min| hour| day| month| year')
+               );
+       }
+
+       /**
+        * Test the converting of the pipe split time units into an array
+        * @test
+        */
+       public function splitTimeUnitsFromLabelDefaultLabels() {
+               $this->assertSame(
+                         array(
+                               'min' => ' min',
+                               'mins' => ' min',
+                               'hour' => ' hour',
+                               'hours' => ' hrs',
+                               'day' => ' day',
+                               'days' => ' days',
+                               'month' => ' month',
+                               'months' => ' months',
+                               'year' => ' year',
+                               'years' => ' yrs',
+                         ),
+                         DateTimeUtility::splitTimeUnitsFromLabel()
+               );
+       }
+
+       /**
+        * Data provider for getSimpleAgeStringReturnsExpectedValues
+        * Adding one day to the years to not collide with leap years. (366)
+        *
+        * @return array
+        */
+       public function getSimpleAgeStringReturnsExpectedValuesDataProvider() {
+               return array(
+                       'Single year' => array(
+                               'seconds' => 60 * 60 * 24 * 366,
+                               'expectedLabel' => '1 year'
+                       ),
+                       'Plural years' => array(
+                               'seconds' => 60 * 60 * 24 * 366 * 2,
+                               'expectedLabel' => '2 yrs'
+                       ),
+                       'Single negative year' => array(
+                               'seconds' => 60 * 60 * 24 * 366 * -1,
+                               'expectedLabel' => '-1 year'
+                       ),
+                       'Plural negative years' => array(
+                               'seconds' => 60 * 60 * 24 * 366 * 2 * -1,
+                               'expectedLabel' => '-2 yrs'
+                       ),
+                       'Single month' => array(
+                               'seconds' => 60 * 60 * 24 * 31,
+                               'expectedLabel' => '1 month'
+                       ),
+                       'Plural months' => array(
+                               'seconds' => 60 * 60 * 24 * 31 * 2,
+                               'expectedLabel' => '2 months'
+                       ),
+                       'Single negative month' => array(
+                               'seconds' => 60 * 60 * 24 * 31 * -1,
+                               'expectedLabel' => '-1 month'
+                       ),
+                       'Plural negative months' => array(
+                               'seconds' => 60 * 60 * 24 * 31 * 2 * -1,
+                               'expectedLabel' => '-2 months'
+                       ),
+                       'Single day' => array(
+                               'seconds' => 60 * 60 * 24,
+                               'expectedLabel' => '1 day'
+                       ),
+                       'Plural days' => array(
+                               'seconds' => 60 * 60 * 24 * 2,
+                               'expectedLabel' => '2 days'
+                       ),
+                       'Single negative day' => array(
+                               'seconds' => 60 * 60 * 24 * -1,
+                               'expectedLabel' => '-1 day'
+                       ),
+                       'Plural negative days' => array(
+                               'seconds' => 60 * 60 * 24 * 2 * -1,
+                               'expectedLabel' => '-2 days'
+                       ),
+                       'Single hour' => array(
+                               'seconds' => 60 * 60,
+                               'expectedLabel' => '1 hour'
+                       ),
+                       'Plural hours' => array(
+                               'seconds' => 60 * 60 * 2,
+                               'expectedLabel' => '2 hrs'
+                       ),
+                       'Single negative hour' => array(
+                               'seconds' => 60 * 60 * -1,
+                               'expectedLabel' => '-1 hour'
+                       ),
+                       'Plural negative hours' => array(
+                               'seconds' => 60 * 60 * 2 * -1,
+                               'expectedLabel' => '-2 hrs'
+                       ),
+                       'Single minute' => array(
+                               'seconds' => 60,
+                               'expectedLabel' => '1 min'
+                       ),
+                       'Plural minutes' => array(
+                               'seconds' => 60 * 2,
+                               'expectedLabel' => '2 min'
+                       ),
+                       'Single negative minute' => array(
+                               'seconds' => 60 * -1,
+                               'expectedLabel' => '-1 min'
+                       ),
+                       'Plural negative minutes' => array(
+                               'seconds' => 60 * 2 * -1,
+                               'expectedLabel' => '-2 min'
+                       ),
+                       'Zero seconds' => array(
+                               'seconds' => 0,
+                               'expectedLabel' => '0 min'
+                       )
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider getSimpleAgeStringReturnsExpectedValuesDataProvider
+        */
+       public function getSimpleAgeStringReturnsExpectedValues($seconds, $expectedLabel) {
+               $this->assertSame($expectedLabel, DateTimeUtility::getSimpleAgeString($seconds));
+       }
+
+       /**
+        * Data provider for getSimpleAgeStringReturnsExpectedValues
+        * Adding one day to the years to not collide with leap years. (366)
+        * For the backward compatible version without month
+        *
+        * @return array
+        */
+       public function getSimpleAgeStringWithoutMonthReturnsExpectedValuesDataProvider() {
+               return array(
+                       'Single year' => array(
+                               'seconds' => 60 * 60 * 24 * 366,
+                               'expectedLabel' => '1 testYear'
+                       ),
+                       'Single negative year' => array(
+                               'seconds' => 60 * 60 * 24 * 366 * -1,
+                               'expectedLabel' => '-1 testYear'
+                       ),
+                       'Single month' => array(
+                               'seconds' => 60 * 60 * 24 * 31,
+                               'expectedLabel' => '31 testDays'
+                       ),
+                       'Plural months' => array(
+                               'seconds' => 60 * 60 * 24 * 31 * 2,
+                               'expectedLabel' => '62 testDays'
+                       ),
+                       'Single negative month' => array(
+                               'seconds' => 60 * 60 * 24 * 31 * -1,
+                               'expectedLabel' => '-31 testDays'
+                       ),
+                       'Plural negative months' => array(
+                               'seconds' => 60 * 60 * 24 * 31 * 2 * -1,
+                               'expectedLabel' => '-62 testDays'
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider getSimpleAgeStringWithoutMonthReturnsExpectedValuesDataProvider
+        */
+       public function getSimpleAgeStringWithoutMonthReturnsExpectedValues($seconds, $expectedLabel) {
+               $this->assertSame(
+                       $expectedLabel,
+                       DateTimeUtility::getSimpleAgeString(
+                               $seconds,
+                               array(
+                                       'min' => ' testMinute',
+                                       'mins' => ' testMinutes',
+                                       'hour' => ' testHour',
+                                       'hours' => ' testHours',
+                                       'day' => ' testDay',
+                                       'days' => ' testDays',
+                                       'year' => ' testYear',
+                                       'years' => ' testYears',
+                               )
+                       )
+               );
+       }
+}
diff --git a/typo3/sysext/core/Tests/Unit/Utility/Fixtures/DateTimeUtilityFixture.php b/typo3/sysext/core/Tests/Unit/Utility/Fixtures/DateTimeUtilityFixture.php
new file mode 100644 (file)
index 0000000..a29eb30
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Utility\Fixtures;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2014 Markus Klein <klein.t3@mfc-linz.at>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the text file GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\DateTimeUtility;
+
+/**
+ * Fixture to be able to mock protected static functions
+ *
+ * @author Markus Klein <klein.t3@mfc-linz.at>
+ */
+class DateTimeUtilityFixture extends DateTimeUtility {
+
+       /**
+        * @var string
+        */
+       static public $mockGetTimeDiffString = '';
+
+       /**
+        * @param \DateTime $startDateTime
+        * @param \DateTime $endDateTime
+        * @param null $labels
+        * @return string
+        */
+       static public function getTimeDiffString(\DateTime $startDateTime, \DateTime $endDateTime, $labels = NULL) {
+               if (self::$mockGetTimeDiffString) {
+                       return self::$mockGetTimeDiffString;
+               }
+               return parent::getTimeDiffString($startDateTime, $endDateTime, $labels);
+       }
+}
\ No newline at end of file
index f0ac436..b7ad3e3 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Dbal\Database;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\DateTimeUtility;
 
 /**
  * TYPO3 database abstraction layer
@@ -445,7 +446,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @throws \RuntimeException
         */
        public function exec_INSERTquery($table, $fields_values, $no_quote_fields = FALSE) {
-               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
+               $pt = $this->debug ? DateTimeUtility::milliseconds() : 0;
                // Do field mapping if needed:
                $ORIG_tableName = $table;
                if ($tableArray = $this->map_needMapping($table)) {
@@ -559,7 +560,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        debug(array($this->lastQuery, $this->sql_error()));
                }
                if ($this->debug) {
-                       $this->debugHandler('exec_INSERTquery', GeneralUtility::milliseconds() - $pt, array(
+                       $this->debugHandler('exec_INSERTquery', DateTimeUtility::milliseconds() - $pt, array(
                                'handlerType' => $hType,
                                'args' => array($table, $fields_values),
                                'ORIG_tablename' => $ORIG_tableName
@@ -612,7 +613,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @return boolean|\mysqli_result|object MySQLi result object / DBAL object
         */
        public function exec_UPDATEquery($table, $where, $fields_values, $no_quote_fields = FALSE) {
-               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
+               $pt = $this->debug ? DateTimeUtility::milliseconds() : 0;
                // Do table/field mapping:
                $ORIG_tableName = $table;
                if ($tableArray = $this->map_needMapping($table)) {
@@ -674,7 +675,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        debug(array($this->lastQuery, $this->sql_error()));
                }
                if ($this->debug) {
-                       $this->debugHandler('exec_UPDATEquery', GeneralUtility::milliseconds() - $pt, array(
+                       $this->debugHandler('exec_UPDATEquery', DateTimeUtility::milliseconds() - $pt, array(
                                'handlerType' => $hType,
                                'args' => array($table, $where, $fields_values),
                                'ORIG_from_table' => $ORIG_tableName
@@ -695,7 +696,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @return boolean|\mysqli_result|object MySQLi result object / DBAL object
         */
        public function exec_DELETEquery($table, $where) {
-               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
+               $pt = $this->debug ? DateTimeUtility::milliseconds() : 0;
                // Do table/field mapping:
                $ORIG_tableName = $table;
                if ($tableArray = $this->map_needMapping($table)) {
@@ -729,7 +730,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        debug(array($this->lastQuery, $this->sql_error()));
                }
                if ($this->debug) {
-                       $this->debugHandler('exec_DELETEquery', GeneralUtility::milliseconds() - $pt, array(
+                       $this->debugHandler('exec_DELETEquery', DateTimeUtility::milliseconds() - $pt, array(
                                'handlerType' => $hType,
                                'args' => array($table, $where),
                                'ORIG_from_table' => $ORIG_tableName
@@ -755,7 +756,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @return boolean|\mysqli_result|object MySQLi result object / DBAL object
         */
        public function exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
-               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
+               $pt = $this->debug ? DateTimeUtility::milliseconds() : 0;
                // Map table / field names if needed:
                $ORIG_tableName = $from_table;
                // Saving table names in $ORIG_from_table since $from_table is transformed beneath:
@@ -838,7 +839,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        if ($this->conf['debugOptions']['numberRows']) {
                                $data['numberRows'] = $this->sql_num_rows($sqlResult);
                        }
-                       $this->debugHandler('exec_SELECTquery', GeneralUtility::milliseconds() - $pt, $data);
+                       $this->debugHandler('exec_SELECTquery', DateTimeUtility::milliseconds() - $pt, $data);
                }
                // Return handler.
                return $sqlResult;
@@ -851,7 +852,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @return mixed Result from handler
         */
        public function exec_TRUNCATEquery($table) {
-               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
+               $pt = $this->debug ? DateTimeUtility::milliseconds() : 0;
                // Do table/field mapping:
                $ORIG_tableName = $table;
                if ($tableArray = $this->map_needMapping($table)) {
@@ -881,7 +882,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                        debug(array($this->lastQuery, $this->sql_error()));
                }
                if ($this->debug) {
-                       $this->debugHandler('exec_TRUNCATEquery', GeneralUtility::milliseconds() - $pt, array(
+                       $this->debugHandler('exec_TRUNCATEquery', DateTimeUtility::milliseconds() - $pt, array(
                                'handlerType' => $hType,
                                'args' => array($table),
                                'ORIG_from_table' => $ORIG_tableName
@@ -1308,7 +1309,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @return \TYPO3\CMS\Core\Database\PreparedStatement Prepared statement
         */
        public function prepare_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', array $input_parameters = array()) {
-               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
+               $pt = $this->debug ? DateTimeUtility::milliseconds() : 0;
                $precompiledParts = array();
                if ($this->queryCache) {
                        $cacheKey = 'prepare_SELECTquery-' . \TYPO3\CMS\Dbal\QueryCache::getCacheKey(array(
@@ -1326,7 +1327,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                                'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters),
                                                'precompiledParts' => $precompiledParts
                                        );
-                                       $this->debugHandler('prepare_SELECTquery (cache hit)', GeneralUtility::milliseconds() - $pt, $data);
+                                       $this->debugHandler('prepare_SELECTquery (cache hit)', DateTimeUtility::milliseconds() - $pt, $data);
                                }
                        }
                }
@@ -1380,7 +1381,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                'args' => array($from_table, $select_fields, $where_clause, $groupBy, $orderBy, $limit, $input_parameters),
                                'ORIG_from_table' => $ORIG_tableName
                        );
-                       $this->debugHandler('prepare_SELECTquery', GeneralUtility::milliseconds() - $pt, $data);
+                       $this->debugHandler('prepare_SELECTquery', DateTimeUtility::milliseconds() - $pt, $data);
                }
                // Return prepared statement
                return $preparedStatement;
@@ -1499,7 +1500,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
         * @internal This method may only be called by \TYPO3\CMS\Core\Database\PreparedStatement
         */
        public function prepare_PREPAREDquery($query, array $queryComponents) {
-               $pt = $this->debug ? GeneralUtility::milliseconds() : 0;
+               $pt = $this->debug ? DateTimeUtility::milliseconds() : 0;
                // Get handler key and select API:
                $preparedStatement = NULL;
                switch ($queryComponents['handler']) {
@@ -1537,7 +1538,7 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                                'args' => $queryComponents,
                                'ORIG_from_table' => $queryComponents['ORIG_tableName']
                        );
-                       $this->debugHandler('prepare_PREPAREDquery', GeneralUtility::milliseconds() - $pt, $data);
+                       $this->debugHandler('prepare_PREPAREDquery', DateTimeUtility::milliseconds() - $pt, $data);
                }
                // Return result handler.
                return $preparedStatement;
index 9f9796a..f14654a 100644 (file)
@@ -32,9 +32,6 @@ class TimeSinceLastUpdateViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\Abs
                                'LLL:EXT:extensionmanager/Resources/Private/Language/locallang.xlf:extensionList.updateFromTer.never'
                        );
                }
-               return \TYPO3\CMS\Backend\Utility\BackendUtility::calcAge(
-                       time() - $lastUpdateTime->format('U'),
-                       $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')
-               );
+               return \TYPO3\CMS\Core\Utility\DateTimeUtility::getAgeString($lastUpdateTime);
        }
 }
index 2334f68..83cf30f 100644 (file)
@@ -2752,7 +2752,12 @@ class ContentObjectRenderer {
         * @return string The processed input value
         */
        public function stdWrap_age($content = '', $conf = array()) {
-               return $this->calcAge($GLOBALS['EXEC_TIME'] - $content, $conf['age']);
+               $ageLabels = NULL;
+               // When config option "age" is set to "1" retrieve labels from default locallang settings by passing NULL
+               if (isset($conf['age']) && !\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($conf['age'])) {
+                       $ageLabels = $conf['age'];
+               }
+               return \TYPO3\CMS\Core\Utility\DateTimeUtility::getAgeStringUnix($content, $ageLabels);
        }
 
        /**
@@ -6691,35 +6696,14 @@ class ContentObjectRenderer {
         *
         * @param integer $seconds Seconds to return age for. Example: "70" => "1 min", "3601" => "1 hrs
         * @param string $labels The labels of the individual units. Defaults to : ' min| hrs| days| yrs'
+        *
         * @return string The formatted string
-        * @todo Define visibility
+        * @deprecated since 6.2, will be removed two versions later, use \TYPO3\CMS\Core\Utility\DateTimeUtility::getAgeStringUnix
+        *  or \TYPO3\CMS\Core\Utility\DateTimeUtility::getSimpleAgeString
         */
        public function calcAge($seconds, $labels) {
-               if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($labels)) {
-                       $labels = ' min| hrs| days| yrs| min| hour| day| year';
-               } else {
-                       $labels = str_replace('"', '', $labels);
-               }
-               $labelArr = explode('|', $labels);
-               if (count($labelArr) == 4) {
-                       $labelArr = array_merge($labelArr, $labelArr);
-               }
-               $absSeconds = abs($seconds);
-               $sign = $seconds > 0 ? 1 : -1;
-               if ($absSeconds < 3600) {
-                       $val = round($absSeconds / 60);
-                       $seconds = $sign * $val . ($val == 1 ? $labelArr[4] : $labelArr[0]);
-               } elseif ($absSeconds < 24 * 3600) {
-                       $val = round($absSeconds / 3600);
-                       $seconds = $sign * $val . ($val == 1 ? $labelArr[5] : $labelArr[1]);
-               } elseif ($absSeconds < 365 * 24 * 3600) {
-                       $val = round($absSeconds / (24 * 3600));
-                       $seconds = $sign * $val . ($val == 1 ? $labelArr[6] : $labelArr[2]);
-               } else {
-                       $val = round($absSeconds / (365 * 24 * 3600));
-                       $seconds = $sign * $val . ($val == 1 ? $labelArr[7] : $labelArr[3]);
-               }
-               return $seconds;
+               GeneralUtility::logDeprecatedFunction();
+               return \TYPO3\CMS\Core\Utility\DateTimeUtility::getSimpleAgeString($seconds, $labels);
        }
 
        /**
index c8c4dc3..5480de8 100644 (file)
@@ -67,7 +67,6 @@ class PageInformationController extends \TYPO3\CMS\Backend\Module\AbstractFuncti
                $dblist->script = BackendUtility::getModuleUrl('web_info');
                $dblist->showIcon = 0;
                $dblist->setLMargin = 0;
-               $dblist->agePrefixes = $LANG->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears');
                $dblist->pI_showUser = 1;
                // PAGES:
                $this->pObj->MOD_SETTINGS['pages_levels'] = $this->pObj->MOD_SETTINGS['depth'];
index 27d6e0e..85a8e82 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\IndexedSearch\Controller;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\DateTimeUtility;
 
 /**
  * Index search frontend
@@ -159,20 +160,20 @@ class SearchController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControlle
                $resultsets = array();
                foreach ($indexCfgs as $freeIndexUid) {
                        // Get result rows
-                       $tstamp1 = GeneralUtility::milliseconds();
+                       $tstamp1 = DateTimeUtility::milliseconds();
                        if ($hookObj = $this->hookRequest('getResultRows')) {
                                $resultData = $hookObj->getResultRows($this->searchWords, $freeIndexUid);
                        } else {
                                $resultData = $this->searchRepository->doSearch($this->searchWords, $freeIndexUid);
                        }
                        // Display search results
-                       $tstamp2 = GeneralUtility::milliseconds();
+                       $tstamp2 = DateTimeUtility::milliseconds();
                        if ($hookObj = $this->hookRequest('getDisplayResults')) {
                                $resultsets[$freeIndexUid] = $hookObj->getDisplayResults($this->searchWords, $resultData, $freeIndexUid);
                        } else {
                                $resultsets[$freeIndexUid] = $this->getDisplayResults($this->searchWords, $resultData, $freeIndexUid);
                        }
-                       $tstamp3 = GeneralUtility::milliseconds();
+                       $tstamp3 = DateTimeUtility::milliseconds();
                        // Create header if we are searching more than one indexing configuration
                        if (count($indexCfgs) > 1) {
                                if ($freeIndexUid > 0) {
@@ -466,14 +467,15 @@ class SearchController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControlle
                                return ceil(log($total) / log($max) * 100) . '%';
                                break;
                        case 'crdate':
-                               return $this->cObj->calcAge($GLOBALS['EXEC_TIME'] - $row['item_crdate'], 0);
+                               return DateTimeUtility::getSimpleAgeString($row['item_crdate']);
                                break;
                        case 'mtime':
-                               return $this->cObj->calcAge($GLOBALS['EXEC_TIME'] - $row['item_mtime'], 0);
+                               return DateTimeUtility::getSimpleAgeString($row['item_mtime']);
                                break;
                        default:
                                return ' ';
                }
+               return '';
        }
 
        /**
index 69d01fc..1ff310c 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\IndexedSearch\Controller;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\DateTimeUtility;
 
 /**
  * Index search frontend
@@ -491,20 +492,20 @@ class SearchFormController extends \TYPO3\CMS\Frontend\Plugin\AbstractPlugin {
                $accumulatedContent = '';
                foreach ($indexCfgs as $freeIndexUid) {
                        // Get result rows:
-                       $pt1 = GeneralUtility::milliseconds();
+                       $pt1 = DateTimeUtility::milliseconds();
                        if ($hookObj = $this->hookRequest('getResultRows')) {
                                $resData = $hookObj->getResultRows($sWArr, $freeIndexUid);
                        } else {
                                $resData = $this->getResultRows($sWArr, $freeIndexUid);
                        }
                        // Display search results:
-                       $pt2 = GeneralUtility::milliseconds();
+                       $pt2 = DateTimeUtility::milliseconds();
                        if ($hookObj = $this->hookRequest('getDisplayResults')) {
                                $content = $hookObj->getDisplayResults($sWArr, $resData, $freeIndexUid);
                        } else {
                                $content = $this->getDisplayResults($sWArr, $resData, $freeIndexUid);
                        }
-                       $pt3 = GeneralUtility::milliseconds();
+                       $pt3 = DateTimeUtility::milliseconds();
                        // Create header if we are searching more than one indexing configuration:
                        if (count($indexCfgs) > 1) {
                                if ($freeIndexUid > 0) {
@@ -1872,16 +1873,17 @@ class SearchFormController extends \TYPO3\CMS\Frontend\Plugin\AbstractPlugin {
                                break;
                        case 'crdate':
                                // Based on creation date
-                               return $this->cObj->calcAge($GLOBALS['EXEC_TIME'] - $row['item_crdate'], 0);
+                               return DateTimeUtility::getSimpleAgeString($row['item_crdate']);
                                break;
                        case 'mtime':
                                // Based on modification time
-                               return $this->cObj->calcAge($GLOBALS['EXEC_TIME'] - $row['item_mtime'], 0);
+                               return DateTimeUtility::getSimpleAgeString($row['item_mtime']);
                                break;
                        default:
                                // fx. title
                                return '&nbsp;';
                }
+               return '';
        }
 
        /**
index 0623160..d89d3ed 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\IndexedSearch;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\DateTimeUtility;
 
 /**
  * This class is a search indexer for TYPO3
@@ -538,7 +539,7 @@ class Indexer {
                        // This will also prevent pages from being indexed if a fe_users has logged in and it turns out that the page content is not changed anyway. fe_users logged in should always search with hash_gr_list = "0,-1" OR "[their_group_list]". This situation will be prevented only if the page has been indexed with no user login on before hand. Else the page will be indexed by users until that event. However that does not present a serious problem.
                        $checkCHash = $this->checkContentHash();
                        if (!is_array($checkCHash) || $check === 1) {
-                               $Pstart = GeneralUtility::milliseconds();
+                               $Pstart = DateTimeUtility::milliseconds();
                                $this->log_push('Converting charset of content (' . $this->conf['metaCharset'] . ') to utf-8', '');
                                $this->charsetEntity2utf8($this->contentParts, $this->conf['metaCharset']);
                                $this->log_pull();
@@ -562,7 +563,7 @@ class Indexer {
                                }
                                $this->log_pull();
                                // Set parsetime
-                               $this->updateParsetime($this->hash['phash'], GeneralUtility::milliseconds() - $Pstart);
+                               $this->updateParsetime($this->hash['phash'], DateTimeUtility::milliseconds() - $Pstart);
                                // Checking external files if configured for.
                                $this->log_push('Checking external files', '');
                                if ($this->conf['index_externals']) {
@@ -1120,7 +1121,7 @@ class Indexer {
                                foreach ($cParts as $cPKey) {
                                        $this->internal_log = array();
                                        $this->log_push('Index: ' . str_replace('.', '_', basename($file)) . ($cPKey ? '#' . $cPKey : ''), '');
-                                       $Pstart = GeneralUtility::milliseconds();
+                                       $Pstart = DateTimeUtility::milliseconds();
                                        $subinfo = array('key' => $cPKey);
                                        // Setting page range. This is "0" (zero) when no division is made, otherwise a range like "1-3"
                                        $phash_arr = ($this->file_phash_arr = $this->setExtHashes($file, $subinfo));
@@ -1164,7 +1165,7 @@ class Indexer {
                                                                        }
                                                                        $this->log_pull();
                                                                        // Set parsetime
-                                                                       $this->updateParsetime($phash_arr['phash'], GeneralUtility::milliseconds() - $Pstart);
+                                                                       $this->updateParsetime($phash_arr['phash'], DateTimeUtility::milliseconds() - $Pstart);
                                                                } else {
                                                                        // Update the timestamp
                                                                        $this->updateTstamp($phash_arr['phash'], $fileInfo['mtime']);
index 1fbda08..21c4600 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Install\Controller\Action\Tool;
 
 use TYPO3\CMS\Install\Controller\Action;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\DateTimeUtility;
 
 /**
  * Test various system setup settings
@@ -143,7 +144,7 @@ class TestSetup extends Action\AbstractAction {
         * @return \TYPO3\CMS\Install\Status\StatusInterface
         */
        protected function createTrueTypeFontDpiTestImage() {
-               $parseTimeStart = GeneralUtility::milliseconds();
+               $parseTimeStart = DateTimeUtility::milliseconds();
 
                $image = @imagecreate(200, 50);
                imagecolorallocate($image, 255, 255, 55);
@@ -176,7 +177,7 @@ class TestSetup extends Action\AbstractAction {
                $testResults['ttf']['referenceFile'] = $this->imageBasePath . 'TestReference/Font.gif';
 
                $this->view->assign('testResults', $testResults);
-               return $this->imageTestDoneMessage(GeneralUtility::milliseconds() - $parseTimeStart);
+               return $this->imageTestDoneMessage(DateTimeUtility::milliseconds() - $parseTimeStart);
        }
 
        /**
@@ -187,7 +188,7 @@ class TestSetup extends Action\AbstractAction {
        protected function convertImageFormatsToJpg() {
                $this->setUpDatabaseConnectionMock();
                $imageProcessor = $this->initializeImageProcessor();
-               $parseTimeStart = GeneralUtility::milliseconds();
+               $parseTimeStart = DateTimeUtility::milliseconds();
 
                $inputFormatsToTest = array('jpg', 'gif', 'png', 'tif', 'bmp', 'pcx', 'tga', 'pdf', 'ai');
 
@@ -219,7 +220,7 @@ class TestSetup extends Action\AbstractAction {
                }
 
                $this->view->assign('testResults', $testResults);
-               return $this->imageTestDoneMessage(GeneralUtility::milliseconds() - $parseTimeStart);
+               return $this->imageTestDoneMessage(DateTimeUtility::milliseconds() - $parseTimeStart);
        }
 
        /**
@@ -230,7 +231,7 @@ class TestSetup extends Action\AbstractAction {
        protected function writeGifAndPng() {
                $this->setUpDatabaseConnectionMock();
                $imageProcessor = $this->initializeImageProcessor();
-               $parseTimeStart = GeneralUtility::milliseconds();
+               $parseTimeStart = DateTimeUtility::milliseconds();
 
                $testResults = array(
                        'gif' => array(),
@@ -284,7 +285,7 @@ class TestSetup extends Action\AbstractAction {
                }
 
                $this->view->assign('testResults', $testResults);
-               return $this->imageTestDoneMessage(GeneralUtility::milliseconds() - $parseTimeStart);
+               return $this->imageTestDoneMessage(DateTimeUtility::milliseconds() - $parseTimeStart);
        }
 
        /**
@@ -295,7 +296,7 @@ class TestSetup extends Action\AbstractAction {
        protected function scaleImages() {
                $this->setUpDatabaseConnectionMock();
                $imageProcessor = $this->initializeImageProcessor();
-               $parseTimeStart = GeneralUtility::milliseconds();
+               $parseTimeStart = DateTimeUtility::milliseconds();
 
                $testResults = array(
                        'gif-to-gif' => array(),
@@ -343,7 +344,7 @@ class TestSetup extends Action\AbstractAction {
                }
 
                $this->view->assign('testResults', $testResults);
-               return $this->imageTestDoneMessage(GeneralUtility::milliseconds() - $parseTimeStart);
+               return $this->imageTestDoneMessage(DateTimeUtility::milliseconds() - $parseTimeStart);
        }
 
        /**
@@ -354,7 +355,7 @@ class TestSetup extends Action\AbstractAction {
        protected function combineImages() {
                $this->setUpDatabaseConnectionMock();
                $imageProcessor = $this->initializeImageProcessor();
-               $parseTimeStart = GeneralUtility::milliseconds();
+               $parseTimeStart = DateTimeUtility::milliseconds();
 
                $testResults = array(
                        'combine1' => array(),
@@ -395,7 +396,7 @@ class TestSetup extends Action\AbstractAction {
                }
 
                $this->view->assign('testResults', $testResults);
-               return $this->imageTestDoneMessage(GeneralUtility::milliseconds() - $parseTimeStart);
+               return $this->imageTestDoneMessage(DateTimeUtility::milliseconds() - $parseTimeStart);
        }
 
        /**
@@ -406,7 +407,7 @@ class TestSetup extends Action\AbstractAction {
        protected function gdlib() {
                $this->setUpDatabaseConnectionMock();
                $imageProcessor = $this->initializeImageProcessor();
-               $parseTimeStart = GeneralUtility::milliseconds();
+               $parseTimeStart = DateTimeUtility::milliseconds();
                $gifOrPng = $imageProcessor->gifExtension;
                $testResults = array();
 
@@ -537,7 +538,7 @@ class TestSetup extends Action\AbstractAction {
                }
 
                $this->view->assign('testResults', $testResults);
-               return $this->imageTestDoneMessage(GeneralUtility::milliseconds() - $parseTimeStart);
+               return $this->imageTestDoneMessage(DateTimeUtility::milliseconds() - $parseTimeStart);
        }
 
        /**
index d45aed0..2eca68d 100644 (file)
@@ -139,6 +139,9 @@ Do you want to continue WITHOUT saving?</source>
                        <trans-unit id="labels.minutesHoursDaysYears" xml:space="preserve">
                                <source> min| hrs| days| yrs| min| hour| day| year</source>
                        </trans-unit>
+                       <trans-unit id="labels.minutesHoursDaysMonthsYears" xml:space="preserve">
+                               <source> min| hrs| days| months| yrs| min| hour| day| month| year</source>
+                       </trans-unit>
                        <trans-unit id="labels.menu" xml:space="preserve">
                                <source>Menu:</source>
                        </trans-unit>
index af25031..7ca01ac 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Lowlevel;
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\DateTimeUtility;
 
 /**
  * Core functions for cleaning and analysing
@@ -294,7 +295,7 @@ NOW Running --AUTOFIX on result. OK?' . ($this->cli_isArg('--dryrun') ? ' (--dry
         * @todo Define visibility
         */
        public function genTree($rootID, $depth = 1000, $echoLevel = 0, $callBack = '') {
-               $pt = GeneralUtility::milliseconds();
+               $pt = DateTimeUtility::milliseconds();
                $this->performanceStatistics['genTree()'] = '';
                // Initialize:
                if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('workspaces')) {
@@ -324,11 +325,11 @@ NOW Running --AUTOFIX on result. OK?' . ($this->cli_isArg('--dryrun') ? ' (--dry
                        'misplaced_inside_tree' => array()
                );
                // Start traversal:
-               $pt2 = GeneralUtility::milliseconds();
+               $pt2 = DateTimeUtility::milliseconds();
                $this->performanceStatistics['genTree_traverse()'] = '';
                $this->performanceStatistics['genTree_traverse():TraverseTables'] = '';
                $this->genTree_traverse($rootID, $depth, $echoLevel, $callBack);
-               $this->performanceStatistics['genTree_traverse()'] = GeneralUtility::milliseconds() - $pt2;
+               $this->performanceStatistics['genTree_traverse()'] = DateTimeUtility::milliseconds() - $pt2;
                // Sort recStats (for diff'able displays)
                foreach ($this->recStats as $kk => $vv) {
                        foreach ($this->recStats[$kk] as $tables => $recArrays) {
@@ -340,7 +341,7 @@ NOW Running --AUTOFIX on result. OK?' . ($this->cli_isArg('--dryrun') ? ' (--dry
                        echo LF . LF;
                }
                // Processing performance statistics:
-               $this->performanceStatistics['genTree()'] = GeneralUtility::milliseconds() - $pt;
+               $this->performanceStatistics['genTree()'] = DateTimeUtility::milliseconds() - $pt;
                // Count records:
                foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
                        // Select all records belonging to page:
@@ -412,16 +413,16 @@ NOW Running --AUTOFIX on result. OK?' . ($this->cli_isArg('--dryrun') ? ' (--dry
                if ($callBack) {
                        $this->{$callBack}('pages', $rootID, $echoLevel, $versionSwapmode, $rootIsVersion);
                }
-               $pt3 = GeneralUtility::milliseconds();
+               $pt3 = DateTimeUtility::milliseconds();
                // Traverse tables of records that belongs to page:
                foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
                        if ($tableName != 'pages') {
                                // Select all records belonging to page:
-                               $pt4 = GeneralUtility::milliseconds();
+                               $pt4 = DateTimeUtility::milliseconds();
                                $resSub = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid' . ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] ? ',' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] : ''), $tableName, 'pid=' . (int)$rootID . ($this->genTree_traverseDeleted ? '' : BackendUtility::deleteClause($tableName)));
-                               $this->performanceStatistics['genTree_traverse():TraverseTables:']['MySQL']['(ALL)'] += GeneralUtility::milliseconds() - $pt4;
-                               $this->performanceStatistics['genTree_traverse():TraverseTables:']['MySQL'][$tableName] += GeneralUtility::milliseconds() - $pt4;
-                               $pt5 = GeneralUtility::milliseconds();
+                               $this->performanceStatistics['genTree_traverse():TraverseTables:']['MySQL']['(ALL)'] += DateTimeUtility::milliseconds() - $pt4;
+                               $this->performanceStatistics['genTree_traverse():TraverseTables:']['MySQL'][$tableName] += DateTimeUtility::milliseconds() - $pt4;
+                               $pt5 = DateTimeUtility::milliseconds();
                                $count = $GLOBALS['TYPO3_DB']->sql_num_rows($resSub);
                                if ($count) {
                                        if ($echoLevel == 2) {
@@ -518,13 +519,13 @@ NOW Running --AUTOFIX on result. OK?' . ($this->cli_isArg('--dryrun') ? ' (--dry
                                                }
                                        }
                                }
-                               $this->performanceStatistics['genTree_traverse():TraverseTables:']['Proc']['(ALL)'] += GeneralUtility::milliseconds() - $pt5;
-                               $this->performanceStatistics['genTree_traverse():TraverseTables:']['Proc'][$tableName] += GeneralUtility::milliseconds() - $pt5;
+                               $this->performanceStatistics['genTree_traverse():TraverseTables:']['Proc']['(ALL)'] += DateTimeUtility::milliseconds() - $pt5;
+                               $this->performanceStatistics['genTree_traverse():TraverseTables:']['Proc'][$tableName] += DateTimeUtility::milliseconds() - $pt5;
                        }
                }
                unset($resSub);
                unset($rowSub);
-               $this->performanceStatistics['genTree_traverse():TraverseTables'] += GeneralUtility::milliseconds() - $pt3;
+               $this->performanceStatistics['genTree_traverse():TraverseTables'] += DateTimeUtility::milliseconds() - $pt3;
                // Find subpages to root ID and traverse (only when rootID is not a version or is a branch-version):
                if (!$versionSwapmode || $versionSwapmode == 'SWAPMODE:1') {
                        if ($depth > 0) {
index d83f307..d94be4c 100644 (file)
@@ -78,7 +78,7 @@ Will report orphan uids from TCA tables.';
                );
                // zero = tree root, must use tree root if you wish to reverse selection to find orphans!
                $startingPoint = 0;
-               $pt = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
+               $pt = \TYPO3\CMS\Core\Utility\DateTimeUtility::milliseconds();
                $this->genTree($startingPoint, 1000, (int)$this->cli_argValue('--echotree'));
                $resultArray['misplaced_at_rootlevel'] = $this->recStats['misplaced_at_rootlevel'];
                $resultArray['misplaced_inside_tree'] = $this->recStats['misplaced_inside_tree'];