diff options
-rw-r--r-- | lib/private/datetimeformatter.php | 269 | ||||
-rw-r--r-- | lib/private/l10n.php | 8 | ||||
-rw-r--r-- | lib/private/server.php | 31 | ||||
-rw-r--r-- | lib/private/template/functions.php | 32 | ||||
-rw-r--r-- | lib/private/util.php | 29 | ||||
-rw-r--r-- | lib/public/idatetimeformatter.php | 121 | ||||
-rw-r--r-- | lib/public/template.php | 13 | ||||
-rw-r--r-- | lib/public/util.php | 2 | ||||
-rw-r--r-- | tests/lib/datetimeformatter.php | 177 | ||||
-rw-r--r-- | tests/lib/template.php | 20 | ||||
-rw-r--r-- | tests/lib/util.php | 16 |
11 files changed, 655 insertions, 63 deletions
diff --git a/lib/private/datetimeformatter.php b/lib/private/datetimeformatter.php new file mode 100644 index 00000000000..127e694bd88 --- /dev/null +++ b/lib/private/datetimeformatter.php @@ -0,0 +1,269 @@ +<?php +/** + * ownCloud + * + * @author Joas Schilling + * @copyright 2014 Joas Schilling nickvergessen@owncloud.com + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +class DateTimeFormatter implements \OCP\IDateTimeFormatter { + /** @var \DateTimeZone */ + protected $defaultTimeZone; + + /** @var \OCP\IL10N */ + protected $defaultL10N; + + /** + * Constructor + * + * @param \DateTimeZone $defaultTimeZone Set the timezone for the format + * @param \OCP\IL10N $defaultL10N Set the language for the format + */ + public function __construct(\DateTimeZone $defaultTimeZone, \OCP\IL10N $defaultL10N) { + $this->defaultTimeZone = $defaultTimeZone; + $this->defaultL10N = $defaultL10N; + } + + /** + * Get TimeZone to use + * + * @param \DateTimeZone $timeZone The timezone to use + * @return \DateTimeZone The timezone to use, falling back to the current user's timezone + */ + protected function getTimeZone($timeZone = null) { + if ($timeZone === null) { + $timeZone = $this->defaultTimeZone; + } + + return $timeZone; + } + + /** + * Get \OCP\IL10N to use + * + * @param \OCP\IL10N $l The locale to use + * @return \OCP\IL10N The locale to use, falling back to the current user's locale + */ + protected function getLocale($l = null) { + if ($l === null) { + $l = $this->defaultL10N; + } + + return $l; + } + + /** + * Generates a DateTime object with the given timestamp and TimeZone + * + * @param mixed $timestamp + * @param \DateTimeZone $timeZone The timezone to use + * @return \DateTime + */ + protected function getDateTime($timestamp, \DateTimeZone $timeZone = null) { + if ($timestamp === null) { + return new \DateTime('now', $timeZone); + } else if (!$timestamp instanceof \DateTime) { + $dateTime = new \DateTime('now', $timeZone); + $dateTime->setTimestamp($timestamp); + return $dateTime; + } + if ($timeZone) { + $timestamp->setTimezone($timeZone); + } + return $timestamp; + } + + /** + * Formats the date of the given timestamp + * + * @param int|\DateTime $timestamp Either a Unix timestamp or DateTime object + * @param string $format Either 'full', 'long', 'medium' or 'short' + * full: e.g. 'EEEE, MMMM d, y' => 'Wednesday, August 20, 2014' + * long: e.g. 'MMMM d, y' => 'August 20, 2014' + * medium: e.g. 'MMM d, y' => 'Aug 20, 2014' + * short: e.g. 'M/d/yy' => '8/20/14' + * The exact format is dependent on the language + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted date string + */ + public function formatDate($timestamp, $format = 'long', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null) { + return $this->format($timestamp, 'date', $format, $timeZone, $l); + } + + /** + * Formats the date of the given timestamp + * + * @param int|\DateTime $timestamp Either a Unix timestamp or DateTime object + * @param string $format Either 'full', 'long', 'medium' or 'short' + * full: e.g. 'EEEE, MMMM d, y' => 'Wednesday, August 20, 2014' + * long: e.g. 'MMMM d, y' => 'August 20, 2014' + * medium: e.g. 'MMM d, y' => 'Aug 20, 2014' + * short: e.g. 'M/d/yy' => '8/20/14' + * The exact format is dependent on the language + * Uses 'Today', 'Yesterday' and 'Tomorrow' when applicable + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted relative date string + */ + public function formatDateRelativeDay($timestamp, $format = 'long', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null) { + if (substr($format, -1) !== '*' && substr($format, -1) !== '*') { + $format .= '^'; + } + + return $this->format($timestamp, 'date', $format, $timeZone, $l); + } + + /** + * Gives the relative date of the timestamp + * Only works for past dates + * + * @param int|\DateTime $timestamp Either a Unix timestamp or DateTime object + * @param int|\DateTime $baseTimestamp Timestamp to compare $timestamp against, defaults to current time + * @return string Dates returned are: + * < 1 month => Today, Yesterday, n days ago + * < 13 month => last month, n months ago + * >= 13 month => last year, n years ago + * @param \OCP\IL10N $l The locale to use + * @return string Formatted date span + */ + public function formatDateSpan($timestamp, $baseTimestamp = null, \OCP\IL10N $l = null) { + $l = $this->getLocale($l); + $timestamp = $this->getDateTime($timestamp); + $timestamp->setTime(0, 0, 0); + if ($baseTimestamp === null) { + $baseTimestamp = time(); + } + $baseTimestamp = $this->getDateTime($baseTimestamp); + $baseTimestamp->setTime(0, 0, 0); + $dateInterval = $timestamp->diff($baseTimestamp); + + if ($dateInterval->y == 0 && $dateInterval->m == 0 && $dateInterval->d == 0) { + return (string) $l->t('today'); + } else if ($dateInterval->y == 0 && $dateInterval->m == 0 && $dateInterval->d == 1) { + return (string) $l->t('yesterday'); + } else if ($dateInterval->y == 0 && $dateInterval->m == 0) { + return (string) $l->n('%n day ago', '%n days ago', $dateInterval->d); + } else if ($dateInterval->y == 0 && $dateInterval->m == 1) { + return (string) $l->t('last month'); + } else if ($dateInterval->y == 0) { + return (string) $l->n('%n month ago', '%n months ago', $dateInterval->m); + } else if ($dateInterval->y == 1) { + return (string) $l->t('last year'); + } + return (string) $l->n('%n year go', '%n years ago', $dateInterval->y); + } + + /** + * Formats the time of the given timestamp + * + * @param int|\DateTime $timestamp Either a Unix timestamp or DateTime object + * @param string $format Either 'full', 'long', 'medium' or 'short' + * full: e.g. 'h:mm:ss a zzzz' => '11:42:13 AM GMT+0:00' + * long: e.g. 'h:mm:ss a z' => '11:42:13 AM GMT' + * medium: e.g. 'h:mm:ss a' => '11:42:13 AM' + * short: e.g. 'h:mm a' => '11:42 AM' + * The exact format is dependent on the language + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted time string + */ + public function formatTime($timestamp, $format = 'medium', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null) { + return $this->format($timestamp, 'time', $format, $timeZone, $l); + } + + /** + * Gives the relative past time of the timestamp + * + * @param int|\DateTime $timestamp Either a Unix timestamp or DateTime object + * @param int|\DateTime $baseTimestamp Timestamp to compare $timestamp against, defaults to current time + * @return string Dates returned are: + * < 60 sec => seconds ago + * < 1 hour => n minutes ago + * < 1 day => n hours ago + * < 1 month => Yesterday, n days ago + * < 13 month => last month, n months ago + * >= 13 month => last year, n years ago + * @param \OCP\IL10N $l The locale to use + * @return string Formatted time span + */ + public function formatTimeSpan($timestamp, $baseTimestamp = null, \OCP\IL10N $l = null) { + $l = $this->getLocale($l); + $timestamp = $this->getDateTime($timestamp); + if ($baseTimestamp === null) { + $baseTimestamp = time(); + } + $baseTimestamp = $this->getDateTime($baseTimestamp); + + $diff = $timestamp->diff($baseTimestamp); + if ($diff->y > 0 || $diff->m > 0 || $diff->d > 0) { + return (string) $this->formatDateSpan($timestamp, $baseTimestamp); + } + + if ($diff->h > 0) { + return (string) $l->n('%n hour ago', '%n hours ago', $diff->h); + } else if ($diff->i > 0) { + return (string) $l->n('%n minute ago', '%n minutes ago', $diff->i); + } + return (string) $l->t('seconds ago'); + } + + /** + * Formats the date and time of the given timestamp + * + * @param int|\DateTime $timestamp Either a Unix timestamp or DateTime object + * @param string $formatDate See formatDate() for description + * @param string $formatTime See formatTime() for description + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted date and time string + */ + public function formatDateTime($timestamp, $formatDate = 'long', $formatTime = 'medium', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null) { + return $this->format($timestamp, 'datetime', $formatDate . '|' . $formatTime, $timeZone, $l); + } + + /** + * Formats the date and time of the given timestamp + * + * @param int|\DateTime $timestamp Either a Unix timestamp or DateTime object + * @param string $formatDate See formatDate() for description + * Uses 'Today', 'Yesterday' and 'Tomorrow' when applicable + * @param string $formatTime See formatTime() for description + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted relative date and time string + */ + public function formatDateTimeRelativeDay($timestamp, $formatDate = 'long', $formatTime = 'medium', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null) { + if (substr($formatDate, -1) !== '^' && substr($formatDate, -1) !== '*') { + $formatDate .= '^'; + } + + return $this->format($timestamp, 'datetime', $formatDate . '|' . $formatTime, $timeZone, $l); + } + + /** + * Formats the date and time of the given timestamp + * + * @param int|\DateTime $timestamp Either a Unix timestamp or DateTime object + * @param string $type One of 'date', 'datetime' or 'time' + * @param string $format Format string + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted date and time string + */ + protected function format($timestamp, $type, $format, \DateTimeZone $timeZone = null, \OCP\IL10N $l = null) { + $l = $this->getLocale($l); + $timeZone = $this->getTimeZone($timeZone); + $timestamp = $this->getDateTime($timestamp, $timeZone); + + return (string) $l->l($type, $timestamp, array( + 'width' => $format, + )); + } +} diff --git a/lib/private/l10n.php b/lib/private/l10n.php index bc4e53e975c..3c759a9e3a2 100644 --- a/lib/private/l10n.php +++ b/lib/private/l10n.php @@ -311,7 +311,13 @@ class OC_L10N implements \OCP\IL10N { } else { $value->setTimestamp($data); } - $locale = self::findLanguage(); + + // Use the language of the instance, before falling back to the current user's language + $locale = $this->lang; + if ($locale === null) { + $locale = self::findLanguage(); + } + $options = array_merge(array('width' => 'long'), $options); $width = $options['width']; switch($type) { diff --git a/lib/private/server.php b/lib/private/server.php index ce21980c532..e0105506970 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -275,6 +275,12 @@ class Server extends SimpleContainer implements IServerContainer { $groupManager = $c->getGroupManager(); return new \OC\App\AppManager($userSession, $appConfig, $groupManager); }); + $this->registerService('DateTimeFormatter', function(Server $c) { + $timeZone = $c->getTimeZone(); + $language = $c->getConfig()->getUserValue($c->getSession()->get('user_id'), 'core', 'lang', null); + + return new \OC\DateTimeFormatter($timeZone, $c->getL10N('lib', $language)); + }); $this->registerService('MountConfigManager', function () { $loader = \OC\Files\Filesystem::getLoader(); return new \OC\Files\Config\MountProviderCollection($loader); @@ -687,6 +693,31 @@ class Server extends SimpleContainer implements IServerContainer { } /** + * Get the timezone of the current user, based on his session information and config data + * + * @return \DateTimeZone + */ + public function getTimeZone() { + $timeZone = $this->getConfig()->getUserValue($this->getSession()->get('user_id'), 'core', 'timezone', null); + if ($timeZone === null) { + if ($this->getSession()->exists('timezone')) { + $offsetHours = $this->getSession()->get('timezone'); + // Note: the timeZone name is the inverse to the offset, + // so a positive offset means negative timeZone + // and the other way around. + if ($offsetHours > 0) { + return new \DateTimeZone('Etc/GMT-' . $offsetHours); + } else { + return new \DateTimeZone('Etc/GMT+' . abs($offsetHours)); + } + } else { + return new \DateTimeZone('UTC'); + } + } + return new \DateTimeZone($timeZone); + } + + /** * @return \OCP\Files\Config\IMountProviderCollection */ function getMountProviderCollection(){ diff --git a/lib/private/template/functions.php b/lib/private/template/functions.php index 4172d47ba61..288b7838ca2 100644 --- a/lib/private/template/functions.php +++ b/lib/private/template/functions.php @@ -205,36 +205,16 @@ function strip_time($timestamp){ * @param int $timestamp timestamp to format * @param int $fromTime timestamp to compare from, defaults to current time * @param bool $dateOnly whether to strip time information - * @return OC_L10N_String timestamp + * @return string timestamp */ function relative_modified_date($timestamp, $fromTime = null, $dateOnly = false) { - $l = \OC::$server->getL10N('lib'); - if (!isset($fromTime) || $fromTime === null){ - $fromTime = time(); - } + /** @var \OC\DateTimeFormatter $formatter */ + $formatter = \OC::$server->query('DateTimeFormatter'); + if ($dateOnly){ - $fromTime = strip_time($fromTime); - $timestamp = strip_time($timestamp); + return $formatter->formatDateSpan($timestamp, $fromTime); } - $timediff = $fromTime - $timestamp; - $diffminutes = round($timediff/60); - $diffhours = round($diffminutes/60); - $diffdays = round($diffhours/24); - $diffmonths = round($diffdays/31); - - if(!$dateOnly && $timediff < 60) { return $l->t('seconds ago'); } - else if(!$dateOnly && $timediff < 3600) { return $l->n('%n minute ago', '%n minutes ago', $diffminutes); } - else if(!$dateOnly && $timediff < 86400) { return $l->n('%n hour ago', '%n hours ago', $diffhours); } - else if((date('G', $fromTime)-$diffhours) >= 0) { return $l->t('today'); } - else if((date('G', $fromTime)-$diffhours) >= -24) { return $l->t('yesterday'); } - // 86400 * 31 days = 2678400 - else if($timediff < 2678400) { return $l->n('%n day go', '%n days ago', $diffdays); } - // 86400 * 60 days = 518400 - else if($timediff < 5184000) { return $l->t('last month'); } - else if((date('n', $fromTime)-$diffmonths) > 0) { return $l->n('%n month ago', '%n months ago', $diffmonths); } - // 86400 * 365.25 days * 2 = 63113852 - else if($timediff < 63113852) { return $l->t('last year'); } - else { return $l->t('years ago'); } + return $formatter->formatTimeSpan($timestamp, $fromTime); } function html_select_options($options, $selected, $params=array()) { diff --git a/lib/private/util.php b/lib/private/util.php index d28fa80160c..6ccb9dba087 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -435,27 +435,20 @@ class OC_Util { * @param bool $dateOnly option to omit time from the result * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to * @return string timestamp - * @description adjust to clients timezone if we know it + * + * @deprecated Use \OC::$server->query('DateTimeFormatter') instead */ public static function formatDate($timestamp, $dateOnly = false, $timeZone = null) { - if (is_null($timeZone)) { - if (\OC::$server->getSession()->exists('timezone')) { - $systemTimeZone = intval(date('O')); - $systemTimeZone = (round($systemTimeZone / 100, 0) * 60) + ($systemTimeZone % 100); - $clientTimeZone = \OC::$server->getSession()->get('timezone') * 60; - $offset = $clientTimeZone - $systemTimeZone; - $timestamp = $timestamp + $offset * 60; - } - } else { - if (!$timeZone instanceof DateTimeZone) { - $timeZone = new DateTimeZone($timeZone); - } - $dt = new DateTime("@$timestamp"); - $offset = $timeZone->getOffset($dt); - $timestamp += $offset; + if ($timeZone !== null && !$timeZone instanceof \DateTimeZone) { + $timeZone = new \DateTimeZone($timeZone); } - $l = \OC::$server->getL10N('lib'); - return $l->l($dateOnly ? 'date' : 'datetime', $timestamp); + + /** @var \OC\DateTimeFormatter $formatter */ + $formatter = \OC::$server->query('DateTimeFormatter'); + if ($dateOnly) { + return $formatter->formatDate($timestamp, 'long', $timeZone); + } + return $formatter->formatDateTime($timestamp, 'long', 'long', $timeZone); } /** diff --git a/lib/public/idatetimeformatter.php b/lib/public/idatetimeformatter.php new file mode 100644 index 00000000000..b72638ad6cd --- /dev/null +++ b/lib/public/idatetimeformatter.php @@ -0,0 +1,121 @@ +<?php +/** + * ownCloud + * + * @author Joas Schilling + * @copyright 2014 Joas Schilling nickvergessen@owncloud.com + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP; + +interface IDateTimeFormatter { + /** + * Formats the date of the given timestamp + * + * @param int|\DateTime $timestamp + * @param string $format Either 'full', 'long', 'medium' or 'short' + * full: e.g. 'EEEE, MMMM d, y' => 'Wednesday, August 20, 2014' + * long: e.g. 'MMMM d, y' => 'August 20, 2014' + * medium: e.g. 'MMM d, y' => 'Aug 20, 2014' + * short: e.g. 'M/d/yy' => '8/20/14' + * The exact format is dependent on the language + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted date string + */ + public function formatDate($timestamp, $format = 'long', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null); + + /** + * Formats the date of the given timestamp + * + * @param int|\DateTime $timestamp + * @param string $format Either 'full', 'long', 'medium' or 'short' + * full: e.g. 'EEEE, MMMM d, y' => 'Wednesday, August 20, 2014' + * long: e.g. 'MMMM d, y' => 'August 20, 2014' + * medium: e.g. 'MMM d, y' => 'Aug 20, 2014' + * short: e.g. 'M/d/yy' => '8/20/14' + * The exact format is dependent on the language + * Uses 'Today', 'Yesterday' and 'Tomorrow' when applicable + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted relative date string + */ + public function formatDateRelativeDay($timestamp, $format = 'long', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null); + + /** + * Gives the relative date of the timestamp + * Only works for past dates + * + * @param int|\DateTime $timestamp + * @param int|\DateTime $baseTimestamp Timestamp to compare $timestamp against, defaults to current time + * @return string Dates returned are: + * < 1 month => Today, Yesterday, n days ago + * < 13 month => last month, n months ago + * >= 13 month => last year, n years ago + * @param \OCP\IL10N $l The locale to use + * @return string Formatted date span + */ + public function formatDateSpan($timestamp, $baseTimestamp = null, \OCP\IL10N $l = null); + + /** + * Formats the time of the given timestamp + * + * @param int|\DateTime $timestamp + * @param string $format Either 'full', 'long', 'medium' or 'short' + * full: e.g. 'h:mm:ss a zzzz' => '11:42:13 AM GMT+0:00' + * long: e.g. 'h:mm:ss a z' => '11:42:13 AM GMT' + * medium: e.g. 'h:mm:ss a' => '11:42:13 AM' + * short: e.g. 'h:mm a' => '11:42 AM' + * The exact format is dependent on the language + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted time string + */ + public function formatTime($timestamp, $format = 'medium', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null); + + /** + * Gives the relative past time of the timestamp + * + * @param int|\DateTime $timestamp + * @param int|\DateTime $baseTimestamp Timestamp to compare $timestamp against, defaults to current time + * @return string Dates returned are: + * < 60 sec => seconds ago + * < 1 hour => n minutes ago + * < 1 day => n hours ago + * < 1 month => Yesterday, n days ago + * < 13 month => last month, n months ago + * >= 13 month => last year, n years ago + * @param \OCP\IL10N $l The locale to use + * @return string Formatted time span + */ + public function formatTimeSpan($timestamp, $baseTimestamp = null, \OCP\IL10N $l = null); + + /** + * Formats the date and time of the given timestamp + * + * @param int|\DateTime $timestamp + * @param string $formatDate See formatDate() for description + * @param string $formatTime See formatTime() for description + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted date and time string + */ + public function formatDateTime($timestamp, $formatDate = 'long', $formatTime = 'medium', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null); + + /** + * Formats the date and time of the given timestamp + * + * @param int|\DateTime $timestamp + * @param string $formatDate See formatDate() for description + * Uses 'Today', 'Yesterday' and 'Tomorrow' when applicable + * @param string $formatTime See formatTime() for description + * @param \DateTimeZone $timeZone The timezone to use + * @param \OCP\IL10N $l The locale to use + * @return string Formatted relative date and time string + */ + public function formatDateTimeRelativeDay($timestamp, $formatDate = 'long', $formatTime = 'medium', \DateTimeZone $timeZone = null, \OCP\IL10N $l = null); +} diff --git a/lib/public/template.php b/lib/public/template.php index 93af794ba62..89934a842ed 100644 --- a/lib/public/template.php +++ b/lib/public/template.php @@ -94,6 +94,7 @@ function human_file_size( $bytes ) { * @param int $timestamp unix timestamp * @param boolean $dateOnly * @return \OC_L10N_String human readable interpretation of the timestamp + * * @deprecated Use \OCP\Template::relative_modified_date() instead */ function relative_modified_date( $timestamp, $dateOnly = false ) { @@ -188,12 +189,12 @@ class Template extends \OC_Template { } /** - * Return the relative date in relation to today. Returns something like "last hour" or "two month ago" - * - * @param int $timestamp unix timestamp - * @param boolean $dateOnly - * @return \OC_L10N_String human readable interpretation of the timestamp - */ + * Return the relative date in relation to today. Returns something like "last hour" or "two month ago" + * + * @param int $timestamp unix timestamp + * @param boolean $dateOnly + * @return string human readable interpretation of the timestamp + */ public static function relative_modified_date($timestamp, $dateOnly = false) { return \relative_modified_date($timestamp, null, $dateOnly); } diff --git a/lib/public/util.php b/lib/public/util.php index 793a16c4d84..7f1974a421d 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -163,6 +163,8 @@ class Util { * @param bool $dateOnly option to omit time from the result * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to * @return string timestamp + * + * @deprecated Use \OC::$server->query('DateTimeFormatter') instead */ public static function formatDate($timestamp, $dateOnly=false, $timeZone = null) { return(\OC_Util::formatDate($timestamp, $dateOnly, $timeZone)); diff --git a/tests/lib/datetimeformatter.php b/tests/lib/datetimeformatter.php new file mode 100644 index 00000000000..4b91c3a1cc7 --- /dev/null +++ b/tests/lib/datetimeformatter.php @@ -0,0 +1,177 @@ +<?php +/** + * Copyright (c) 2014 Joas Schilling nickvergessen@owncloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test; + +class DateTimeFormatter extends TestCase { + /** @var \OC\DateTimeFormatter */ + protected $formatter; + static protected $oneMinute = 60; + static protected $oneHour = 3600; + static protected $oneDay; + static protected $oneYear; + + static protected $defaultTimeZone; + + public static function setUpBeforeClass() { + parent::setUpBeforeClass(); + self::$defaultTimeZone = date_default_timezone_get(); + date_default_timezone_set('UTC'); + + self::$oneDay = self::$oneHour * 24; + self::$oneYear = self::$oneDay * 365; + } + + public static function tearDownAfterClass() { + date_default_timezone_set(self::$defaultTimeZone); + parent::tearDownAfterClass(); + } + + protected function setUp() { + parent::setUp(); + $this->formatter = new \OC\DateTimeFormatter(new \DateTimeZone('UTC'), new \OC_L10N('lib', 'en')); + } + + protected function getTimestampAgo($time, $seconds = 0, $minutes = 0, $hours = 0, $days = 0, $years = 0) { + return $time - $seconds - $minutes * 60 - $hours * 3600 - $days * 24*3600 - $years * 365*24*3600; + } + + public function formatTimeSpanData() { + // use the same time all the time, so the tests are reliable when time would switch + $time = time(); + $deL10N = new \OC_L10N('lib', 'de'); + return array( + array('seconds ago', $time, $time), + array('1 minute ago', $this->getTimestampAgo($time, 30, 1), $time), + array('15 minutes ago', $this->getTimestampAgo($time, 30, 15), $time), + array('1 hour ago', $this->getTimestampAgo($time, 30, 15, 1), $time), + array('3 hours ago', $this->getTimestampAgo($time, 30, 15, 3), $time), + array('4 days ago', $this->getTimestampAgo($time, 30, 15, 3, 4), $time), + + array('seconds ago', new \DateTime('Wed, 02 Oct 2013 23:59:58 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('seconds ago', new \DateTime('Wed, 02 Oct 2013 23:59:00 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('1 minute ago', new \DateTime('Wed, 02 Oct 2013 23:58:30 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('3 minutes ago', new \DateTime('Wed, 02 Oct 2013 23:56:30 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('59 minutes ago', new \DateTime('Wed, 02 Oct 2013 23:00:00 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('1 hour ago', new \DateTime('Wed, 02 Oct 2013 22:59:59 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('3 hours ago', new \DateTime('Wed, 02 Oct 2013 20:39:59 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('yesterday', new \DateTime('Tue, 01 Oct 2013 20:39:59 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('2 days ago', new \DateTime('Mon, 30 Sep 2013 20:39:59 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + + array($deL10N->t('seconds ago'), new \DateTime('Wed, 02 Oct 2013 23:59:58 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000'), $deL10N), + array($deL10N->n('%n minute ago', '%n minutes ago', 1), new \DateTime('Wed, 02 Oct 2013 23:58:30 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000'), $deL10N), + array($deL10N->n('%n minute ago', '%n minutes ago', 3), new \DateTime('Wed, 02 Oct 2013 23:56:30 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000'), $deL10N), + array($deL10N->n('%n hour ago', '%n hours ago', 1), new \DateTime('Wed, 02 Oct 2013 22:59:59 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000'), $deL10N), + array($deL10N->n('%n hour ago', '%n hours ago', 3), new \DateTime('Wed, 02 Oct 2013 20:39:59 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000'), $deL10N), + array($deL10N->n('%n day ago', '%n days ago', 2), new \DateTime('Mon, 30 Sep 2013 20:39:59 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000'), $deL10N), + + ); + } + + /** + * @dataProvider formatTimeSpanData + */ + public function testFormatTimeSpan($expected, $timestamp, $compare, $locale = null) { + $this->assertEquals((string) $expected, (string) $this->formatter->formatTimeSpan($timestamp, $compare, $locale)); + } + + public function formatDateSpanData() { + // use the same time all the time, so the tests are reliable when time would switch + $time = time(); + $deL10N = new \OC_L10N('lib', 'de'); + return array( + // Normal testing + array('today', $this->getTimestampAgo($time, 30, 15), $time), + array('yesterday', $this->getTimestampAgo($time, 0, 0, 0, 1), $time), + array('4 days ago', $this->getTimestampAgo($time, 0, 0, 0, 4), $time), + array('5 months ago', $this->getTimestampAgo($time, 0, 0, 0, 155), $time), + array('2 years ago', $this->getTimestampAgo($time, 0, 0, 0, 0, 2), $time), + + // Test with compare timestamp + array('today', $this->getTimestampAgo($time, 0, 0, 0, 0, 1), $this->getTimestampAgo($time, 0, 0, 0, 0, 1)), + array('yesterday', $this->getTimestampAgo($time, 30, 15, 3, 1, 1), $this->getTimestampAgo($time, 0, 0, 0, 0, 1)), + array('4 days ago', $this->getTimestampAgo($time, 30, 15, 3, 4, 1), $this->getTimestampAgo($time, 0, 0, 0, 0, 1)), + array('5 months ago', $this->getTimestampAgo($time, 30, 15, 3, 155, 1), $this->getTimestampAgo($time, 0, 0, 0, 0, 1)), + array('2 years ago', $this->getTimestampAgo($time, 30, 15, 3, 35, 3), $this->getTimestampAgo($time, 0, 0, 0, 0, 1)), + + // Test translations + array($deL10N->t('today'), new \DateTime('Wed, 02 Oct 2013 12:00:00 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000'), $deL10N), + array($deL10N->t('yesterday'), new \DateTime('Tue, 01 Oct 2013 00:00:00 +0000'), new \DateTime('Wed, 02 Oct 2013 00:00:00 +0000'), $deL10N), + array($deL10N->n('%n day ago', '%n days ago', 2), new \DateTime('Mon, 30 Sep 2013 00:00:00 +0000'), new \DateTime('Wed, 02 Oct 2013 00:00:00 +0000'), $deL10N), + array($deL10N->n('%n month ago', '%n months ago', 9), new \DateTime('Tue, 31 Dec 2013 00:00:00 +0000'), new \DateTime('Thu, 02 Oct 2014 00:00:00 +0000'), $deL10N), + array($deL10N->n('%n year ago', '%n years ago', 2), new \DateTime('Sun, 01 Jan 2012 00:00:00 +0000'), new \DateTime('Thu, 02 Oct 2014 00:00:00 +0000'), $deL10N), + + // Test time + array('today', new \DateTime('Wed, 02 Oct 2013 00:00:00 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('today', new \DateTime('Wed, 02 Oct 2013 12:00:00 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('today', new \DateTime('Wed, 02 Oct 2013 23:59:58 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + + // Test some special yesterdays + array('yesterday', new \DateTime('Tue, 01 Oct 2013 00:00:00 +0000'), new \DateTime('Wed, 02 Oct 2013 00:00:00 +0000')), + array('yesterday', new \DateTime('Tue, 01 Oct 2013 00:00:00 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('yesterday', new \DateTime('Tue, 01 Oct 2013 23:59:58 +0000'), new \DateTime('Wed, 02 Oct 2013 00:00:00 +0000')), + array('yesterday', new \DateTime('Tue, 01 Oct 2013 23:59:58 +0000'), new \DateTime('Wed, 02 Oct 2013 23:59:59 +0000')), + array('yesterday', new \DateTime('Mon, 30 Sep 2013 00:00:00 +0000'), new \DateTime('Tue, 01 Oct 2013 00:00:00 +0000')), + array('yesterday', new \DateTime('Mon, 31 Dec 2012 00:00:00 +0000'), new \DateTime('Tue, 01 Jan 2013 00:00:00 +0000')), + + // Test last month + array('2 days ago', new \DateTime('Mon, 30 Sep 2013 00:00:00 +0000'), new \DateTime('Wed, 02 Oct 2013 00:00:00 +0000')), + array('last month', new \DateTime('Mon, 30 Sep 2013 00:00:00 +0000'), new \DateTime('Tue, 31 Oct 2013 00:00:00 +0000')), + array('last month', new \DateTime('Sun, 01 Sep 2013 00:00:00 +0000'), new \DateTime('Tue, 01 Oct 2013 00:00:00 +0000')), + array('last month', new \DateTime('Sun, 01 Sep 2013 00:00:00 +0000'), new \DateTime('Thu, 31 Oct 2013 00:00:00 +0000')), + + // Test last year + array('9 months ago', new \DateTime('Tue, 31 Dec 2013 00:00:00 +0000'), new \DateTime('Thu, 02 Oct 2014 00:00:00 +0000')), + array('11 months ago', new \DateTime('Thu, 03 Oct 2013 00:00:00 +0000'), new \DateTime('Thu, 02 Oct 2014 00:00:00 +0000')), + array('last year', new \DateTime('Wed, 02 Oct 2013 00:00:00 +0000'), new \DateTime('Thu, 02 Oct 2014 00:00:00 +0000')), + array('last year', new \DateTime('Tue, 01 Jan 2013 00:00:00 +0000'), new \DateTime('Thu, 02 Oct 2014 00:00:00 +0000')), + array('2 years ago', new \DateTime('Sun, 01 Jan 2012 00:00:00 +0000'), new \DateTime('Thu, 02 Oct 2014 00:00:00 +0000')), + ); + } + + /** + * @dataProvider formatDateSpanData + */ + public function testFormatDateSpan($expected, $timestamp, $compare = null, $locale = null) { + $this->assertEquals((string) $expected, (string) $this->formatter->formatDateSpan($timestamp, $compare, $locale)); + } + + public function formatDateData() { + return array( + array(1102831200, 'December 12, 2004'), + ); + } + + /** + * @dataProvider formatDateData + */ + public function testFormatDate($timestamp, $expected) { + $this->assertEquals($expected, (string) $this->formatter->formatDate($timestamp)); + } + + public function formatDateTimeData() { + return array( + array(1350129205, null, 'October 13, 2012 at 11:53:25 AM GMT+0'), + array(1350129205, new \DateTimeZone('Europe/Berlin'), 'October 13, 2012 at 1:53:25 PM GMT+2'), + ); + } + + /** + * @dataProvider formatDateTimeData + */ + public function testFormatDateTime($timestamp, $timeZone, $expected) { + $this->assertEquals($expected, (string) $this->formatter->formatDateTime($timestamp, 'long', 'long', $timeZone)); + } + + /** + * @expectedException \Exception + */ + function testFormatDateWithInvalidTZ() { + $this->formatter->formatDate(1350129205, 'long', new \DateTimeZone('Mordor/Barad-dûr')); + } +} diff --git a/tests/lib/template.php b/tests/lib/template.php index d77284a5bf2..db58238eae8 100644 --- a/tests/lib/template.php +++ b/tests/lib/template.php @@ -117,15 +117,15 @@ class Test_TemplateFunctions extends \Test\TestCase { public function testRelativeDateMonthsAgo(){ $currentTime = 1380703592; - $elementTime = $currentTime - 86400 * 60; + $elementTime = $currentTime - 86400 * 65; $result = (string)relative_modified_date($elementTime, $currentTime, true); $this->assertEquals('2 months ago', $result); - $elementTime = $currentTime - 86400 * 65; + $elementTime = $currentTime - 86400 * 130; $result = (string)relative_modified_date($elementTime, $currentTime, true); - $this->assertEquals('2 months ago', $result); + $this->assertEquals('4 months ago', $result); } public function testRelativeDateLastYear(){ @@ -146,12 +146,12 @@ class Test_TemplateFunctions extends \Test\TestCase { $elementTime = $currentTime - 86400 * 365.25 * 2; $result = (string)relative_modified_date($elementTime, $currentTime, true); - $this->assertEquals('years ago', $result); + $this->assertEquals('2 years ago', $result); $elementTime = $currentTime - 86400 * 365.25 * 3; $result = (string)relative_modified_date($elementTime, $currentTime, true); - $this->assertEquals('years ago', $result); + $this->assertEquals('3 years ago', $result); } // --------------------------------------------------------------------------- @@ -211,15 +211,15 @@ class Test_TemplateFunctions extends \Test\TestCase { public function testRelativeTimeMonthsAgo(){ $currentTime = 1380703592; - $elementTime = $currentTime - 86400 * 60; + $elementTime = $currentTime - 86400 * 65; $result = (string)relative_modified_date($elementTime, $currentTime, false); $this->assertEquals('2 months ago', $result); - $elementTime = $currentTime - 86400 * 65; + $elementTime = $currentTime - 86400 * 130; $result = (string)relative_modified_date($elementTime, $currentTime, false); - $this->assertEquals('2 months ago', $result); + $this->assertEquals('4 months ago', $result); } public function testRelativeTimeLastYear(){ @@ -240,11 +240,11 @@ class Test_TemplateFunctions extends \Test\TestCase { $elementTime = $currentTime - 86400 * 365.25 * 2; $result = (string)relative_modified_date($elementTime, $currentTime, false); - $this->assertEquals('years ago', $result); + $this->assertEquals('2 years ago', $result); $elementTime = $currentTime - 86400 * 365.25 * 3; $result = (string)relative_modified_date($elementTime, $currentTime, false); - $this->assertEquals('years ago', $result); + $this->assertEquals('3 years ago', $result); } } diff --git a/tests/lib/util.php b/tests/lib/util.php index 3bb4b47c09c..1a2cb09f38d 100644 --- a/tests/lib/util.php +++ b/tests/lib/util.php @@ -41,7 +41,7 @@ class Test_Util extends \Test\TestCase { date_default_timezone_set("UTC"); $result = OC_Util::formatDate(1350129205, false, 'Europe/Berlin'); - $expected = 'October 13, 2012 at 1:53:25 PM GMT+0'; + $expected = 'October 13, 2012 at 1:53:25 PM GMT+2'; $this->assertEquals($expected, $result); } @@ -55,10 +55,22 @@ class Test_Util extends \Test\TestCase { function testFormatDateWithTZFromSession() { date_default_timezone_set("UTC"); + $oldDateTimeFormatter = \OC::$server->query('DateTimeFormatter'); \OC::$server->getSession()->set('timezone', 3); + $newDateTimeFormatter = new \OC\DateTimeFormatter(\OC::$server->getTimeZone(), new \OC_L10N('lib', 'en')); + $this->setDateFormatter($newDateTimeFormatter); + $result = OC_Util::formatDate(1350129205, false); - $expected = 'October 13, 2012 at 2:53:25 PM GMT+0'; + $expected = 'October 13, 2012 at 2:53:25 PM GMT+3'; $this->assertEquals($expected, $result); + + $this->setDateFormatter($oldDateTimeFormatter); + } + + protected function setDateFormatter($formatter) { + \OC::$server->registerService('DateTimeFormatter', function ($c) use ($formatter) { + return $formatter; + }); } function testCallRegister() { |