update Piwik to version 2.16 (fixes #91)
This commit is contained in:
parent
296343bf3b
commit
d885a4baa9
5833 changed files with 418860 additions and 226988 deletions
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -10,26 +10,28 @@
|
|||
namespace Piwik;
|
||||
|
||||
use Exception;
|
||||
use Piwik\Container\StaticContainer;
|
||||
use Piwik\Intl\Data\Provider\DateTimeFormatProvider;
|
||||
|
||||
/**
|
||||
* Utility class that wraps date/time related PHP functions. Using this class can
|
||||
* be easier than using `date`, `time`, `date_default_timezone_set`, etc.
|
||||
*
|
||||
*
|
||||
* ### Performance concerns
|
||||
*
|
||||
*
|
||||
* The helper methods in this class are instance methods and thus `Date` instances
|
||||
* need to be constructed before they can be used. The memory allocation can result
|
||||
* in noticeable performance degradation if you construct thousands of Date instances,
|
||||
* say, in a loop.
|
||||
*
|
||||
*
|
||||
* ### Examples
|
||||
*
|
||||
*
|
||||
* **Basic usage**
|
||||
*
|
||||
*
|
||||
* $date = Date::factory('2007-07-24 14:04:24', 'EST');
|
||||
* $date->addHour(5);
|
||||
* echo $date->getLocalized("%longDay% the %day% of %longMonth% at %time%");
|
||||
*
|
||||
* echo $date->getLocalized("EEE, d. MMM y 'at' HH:mm:ss");
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Date
|
||||
|
|
@ -40,6 +42,36 @@ class Date
|
|||
/** The default date time string format. */
|
||||
const DATE_TIME_FORMAT = 'Y-m-d H:i:s';
|
||||
|
||||
const DATETIME_FORMAT_LONG = DateTimeFormatProvider::DATE_FORMAT_LONG;
|
||||
const DATETIME_FORMAT_SHORT = DateTimeFormatProvider::DATETIME_FORMAT_SHORT;
|
||||
const DATE_FORMAT_LONG = DateTimeFormatProvider::DATE_FORMAT_LONG;
|
||||
const DATE_FORMAT_DAY_MONTH = DateTimeFormatProvider::DATE_FORMAT_DAY_MONTH;
|
||||
const DATE_FORMAT_SHORT = DateTimeFormatProvider::DATE_FORMAT_SHORT;
|
||||
const DATE_FORMAT_MONTH_SHORT = DateTimeFormatProvider::DATE_FORMAT_MONTH_SHORT;
|
||||
const DATE_FORMAT_MONTH_LONG = DateTimeFormatProvider::DATE_FORMAT_MONTH_LONG;
|
||||
const DATE_FORMAT_YEAR = DateTimeFormatProvider::DATE_FORMAT_YEAR;
|
||||
const TIME_FORMAT = DateTimeFormatProvider::TIME_FORMAT;
|
||||
|
||||
/**
|
||||
* Max days for months (non-leap-year). See {@link addPeriod()} implementation.
|
||||
*
|
||||
* @var int[]
|
||||
*/
|
||||
private static $maxDaysInMonth = array(
|
||||
'1' => 31,
|
||||
'2' => 28,
|
||||
'3' => 31,
|
||||
'4' => 30,
|
||||
'5' => 31,
|
||||
'6' => 30,
|
||||
'7' => 31,
|
||||
'8' => 31,
|
||||
'9' => 30,
|
||||
'10' => 31,
|
||||
'11' => 30,
|
||||
'12' => 31
|
||||
);
|
||||
|
||||
/**
|
||||
* The stored timestamp is always UTC based.
|
||||
* The returned timestamp via getTimestamp() will have the conversion applied
|
||||
|
|
@ -84,7 +116,6 @@ class Date
|
|||
*/
|
||||
public static function factory($dateString, $timezone = null)
|
||||
{
|
||||
$invalidDateException = new Exception(Piwik::translate('General_ExceptionInvalidDateFormat', array("YYYY-MM-DD, or 'today' or 'yesterday'", "strtotime", "http://php.net/strtotime")) . ": $dateString");
|
||||
if ($dateString instanceof self) {
|
||||
$dateString = $dateString->toString();
|
||||
}
|
||||
|
|
@ -105,7 +136,7 @@ class Date
|
|||
($dateString = strtotime($dateString)) === false
|
||||
)
|
||||
) {
|
||||
throw $invalidDateException;
|
||||
throw self::getInvalidDateFormatException($dateString);
|
||||
} else {
|
||||
$date = new Date($dateString);
|
||||
}
|
||||
|
|
@ -113,7 +144,7 @@ class Date
|
|||
// can't be doing web analytics before the 1st website
|
||||
// Tue, 06 Aug 1991 00:00:00 GMT
|
||||
if ($timestamp < 681436800) {
|
||||
throw $invalidDateException;
|
||||
throw self::getInvalidDateFormatException($dateString);
|
||||
}
|
||||
if (empty($timezone)) {
|
||||
return $date;
|
||||
|
|
@ -133,6 +164,19 @@ class Date
|
|||
return $this->toString(self::DATE_TIME_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current hour in UTC timezone.
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getHourUTC()
|
||||
{
|
||||
$dateTime = $this->getDatetime();
|
||||
$hourInTz = Date::factory($dateTime, 'UTC')->toString('G');
|
||||
|
||||
return $hourInTz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start of the day of the current timestamp in UTC. For example,
|
||||
* if the current timestamp is `'2007-07-24 14:04:24'` in UTC, the result will
|
||||
|
|
@ -164,7 +208,7 @@ class Date
|
|||
/**
|
||||
* Returns a new date object with the same timestamp as `$this` but with a new
|
||||
* timezone.
|
||||
*
|
||||
*
|
||||
* See {@link getTimestamp()} to see how the timezone is used.
|
||||
*
|
||||
* @param string $timezone eg, `'UTC'`, `'Europe/London'`, etc.
|
||||
|
|
@ -222,6 +266,17 @@ class Date
|
|||
return strtotime($datetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date in the "Y-m-d H:i:s" PHP format
|
||||
*
|
||||
* @param int $timestamp
|
||||
* @return string
|
||||
*/
|
||||
public static function getDatetimeFromTimestamp($timestamp)
|
||||
{
|
||||
return date("Y-m-d H:i:s", $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Unix timestamp of the date in UTC.
|
||||
*
|
||||
|
|
@ -253,15 +308,16 @@ class Date
|
|||
// Unit tests pass (@see Date.test.php) but I'm pretty sure this is not the right way to do it
|
||||
date_default_timezone_set($this->timezone);
|
||||
$dtzone = timezone_open('UTC');
|
||||
$time = date('r', $this->timestamp);
|
||||
$dtime = date_create($time);
|
||||
$time = date('r', $this->timestamp);
|
||||
$dtime = date_create($time);
|
||||
|
||||
date_timezone_set($dtime, $dtzone);
|
||||
$dateWithTimezone = date_format($dtime, 'r');
|
||||
$dateWithTimezone = date_format($dtime, 'r');
|
||||
$dateWithoutTimezone = substr($dateWithTimezone, 0, -6);
|
||||
$timestamp = strtotime($dateWithoutTimezone);
|
||||
$timestamp = strtotime($dateWithoutTimezone);
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
return (int)$timestamp;
|
||||
return (int) $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -375,7 +431,6 @@ class Date
|
|||
return 0;
|
||||
}
|
||||
if ($currentYear < $toCompareYear) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
|
|
@ -383,7 +438,7 @@ class Date
|
|||
|
||||
/**
|
||||
* Returns `true` if current date is today.
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isToday()
|
||||
|
|
@ -560,9 +615,39 @@ class Date
|
|||
/**
|
||||
* Returns a localized date string using the given template.
|
||||
* The template should contain tags that will be replaced with localized date strings.
|
||||
*
|
||||
* Allowed tags include:
|
||||
*
|
||||
*
|
||||
* @param string $template eg. `"MMM y"`
|
||||
* @return string eg. `"Aug 2009"`
|
||||
*/
|
||||
public function getLocalized($template)
|
||||
{
|
||||
$template = $this->replaceLegacyPlaceholders($template);
|
||||
|
||||
$dateTimeFormatProvider = StaticContainer::get('Piwik\Intl\Data\Provider\DateTimeFormatProvider');
|
||||
|
||||
$template = $dateTimeFormatProvider->getFormatPattern($template);
|
||||
|
||||
$tokens = self::parseFormat($template);
|
||||
|
||||
$out = '';
|
||||
|
||||
foreach ($tokens AS $token) {
|
||||
if (is_array($token)) {
|
||||
$out .= $this->formatToken(array_shift($token));
|
||||
|
||||
} else {
|
||||
$out .= $token;
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces legacy placeholders
|
||||
*
|
||||
* @deprecated should be removed in Piwik 3.0.0 or later
|
||||
*
|
||||
* - **%day%**: replaced with the day of the month without leading zeros, eg, **1** or **20**.
|
||||
* - **%shortMonth%**: the short month in the current language, eg, **Jan**, **Feb**.
|
||||
* - **%longMonth%**: the whole month name in the current language, eg, **January**, **February**.
|
||||
|
|
@ -571,27 +656,183 @@ class Date
|
|||
* - **%longYear%**: the four digit year, eg, **2007**, **2013**.
|
||||
* - **%shortYear%**: the two digit year, eg, **07**, **13**.
|
||||
* - **%time%**: the time of day, eg, **07:35:00**, or **15:45:00**.
|
||||
*
|
||||
* @param string $template eg. `"%shortMonth% %longYear%"`
|
||||
* @return string eg. `"Aug 2009"`
|
||||
*/
|
||||
public function getLocalized($template)
|
||||
protected function replaceLegacyPlaceholders($template)
|
||||
{
|
||||
if (strpos($template, '%') === false) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
$mapping = array(
|
||||
'%day%' => 'd',
|
||||
'%shortMonth%' => 'MMM',
|
||||
'%longMonth%' => 'MMMM',
|
||||
'%shortDay%' => 'EEE',
|
||||
'%longDay%' => 'EEEE',
|
||||
'%longYear%' => 'y',
|
||||
'%shortYear%' => 'yy',
|
||||
'%time%' => 'HH:mm:ss'
|
||||
);
|
||||
|
||||
return str_replace(array_keys($mapping), array_values($mapping), $template);
|
||||
}
|
||||
|
||||
protected function formatToken($token)
|
||||
{
|
||||
$day = $this->toString('j');
|
||||
$dayOfWeek = $this->toString('N');
|
||||
$monthOfYear = $this->toString('n');
|
||||
$patternToValue = array(
|
||||
"%day%" => $day,
|
||||
"%shortMonth%" => Piwik::translate('General_ShortMonth_' . $monthOfYear),
|
||||
"%longMonth%" => Piwik::translate('General_LongMonth_' . $monthOfYear),
|
||||
"%shortDay%" => Piwik::translate('General_ShortDay_' . $dayOfWeek),
|
||||
"%longDay%" => Piwik::translate('General_LongDay_' . $dayOfWeek),
|
||||
"%longYear%" => $this->toString('Y'),
|
||||
"%shortYear%" => $this->toString('y'),
|
||||
"%time%" => $this->toString('H:i:s')
|
||||
);
|
||||
$out = str_replace(array_keys($patternToValue), array_values($patternToValue), $template);
|
||||
return $out;
|
||||
$translator = StaticContainer::get('Piwik\Translation\Translator');
|
||||
|
||||
switch ($token) {
|
||||
// year
|
||||
case "yyyy":
|
||||
case "y":
|
||||
return $this->toString('Y');
|
||||
case "yy":
|
||||
return $this->toString('y');
|
||||
// month
|
||||
case "MMMM":
|
||||
return $translator->translate('Intl_Month_Long_' . $monthOfYear);
|
||||
case "MMM":
|
||||
return $translator->translate('Intl_Month_Short_' . $monthOfYear);
|
||||
case "MM":
|
||||
return $this->toString('n');
|
||||
case "M":
|
||||
return $this->toString('m');
|
||||
case "LLLL":
|
||||
return $translator->translate('Intl_Month_Long_StandAlone_' . $monthOfYear);
|
||||
case "LLL":
|
||||
return $translator->translate('Intl_Month_Short_StandAlone_' . $monthOfYear);
|
||||
case "LL":
|
||||
return $this->toString('n');
|
||||
case "L":
|
||||
return $this->toString('m');
|
||||
// day
|
||||
case "dd":
|
||||
return $this->toString('d');
|
||||
case "d":
|
||||
return $this->toString('j');
|
||||
case "EEEE":
|
||||
return $translator->translate('Intl_Day_Long_' . $dayOfWeek);
|
||||
case "EEE":
|
||||
case "EE":
|
||||
case "E":
|
||||
return $translator->translate('Intl_Day_Short_' . $dayOfWeek);
|
||||
case "CCCC":
|
||||
return $translator->translate('Intl_Day_Long_StandAlone_' . $dayOfWeek);
|
||||
case "CCC":
|
||||
case "CC":
|
||||
case "C":
|
||||
return $translator->translate('Intl_Day_Short_StandAlone_' . $dayOfWeek);
|
||||
case "D":
|
||||
return 1 + (int)$this->toString('z'); // 1 - 366
|
||||
case "F":
|
||||
return (int)(((int)$this->toString('j') + 6) / 7);
|
||||
// week in month
|
||||
case "w":
|
||||
$weekDay = date('N', mktime(0, 0, 0, $this->toString('m'), 1, $this->toString('y')));
|
||||
return floor(($weekDay + (int)$this->toString('m') - 2) / 7) + 1;
|
||||
// week in year
|
||||
case "W":
|
||||
return $this->toString('N');
|
||||
// hour
|
||||
case "HH":
|
||||
return $this->toString('H');
|
||||
case "H":
|
||||
return $this->toString('G');
|
||||
case "hh":
|
||||
return $this->toString('h');
|
||||
case "h":
|
||||
return $this->toString('g');
|
||||
// minute
|
||||
case "mm":
|
||||
case "m":
|
||||
return $this->toString('i');
|
||||
// second
|
||||
case "ss":
|
||||
case "s":
|
||||
return $this->toString('s');
|
||||
// am / pm
|
||||
case "a":
|
||||
return $this->toString('a') == 'am' ? $translator->translate('Intl_Time_AM') : $translator->translate('Intl_Time_PM');
|
||||
|
||||
// currently not implemented:
|
||||
case "G":
|
||||
case "GG":
|
||||
case "GGG":
|
||||
case "GGGG":
|
||||
case "GGGGG":
|
||||
return ''; // era
|
||||
case "z":
|
||||
case "Z":
|
||||
case "v":
|
||||
return ''; // time zone
|
||||
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected static $tokens = array(
|
||||
'G', 'y', 'M', 'L', 'd', 'h', 'H', 'm', 's', 'E', 'c', 'e', 'D', 'F', 'w', 'W', 'a', 'z', 'Z', 'v',
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses the datetime format pattern and returns a tokenized result array
|
||||
*
|
||||
* Examples:
|
||||
* Input Output
|
||||
* 'dd.mm.yyyy' array(array('dd'), '.', array('mm'), '.', array('yyyy'))
|
||||
* 'y?M?d?EEEE ah:mm:ss' array(array('y'), '?', array('M'), '?', array('d'), '?', array('EEEE'), ' ', array('a'), array('h'), ':', array('mm'), ':', array('ss'))
|
||||
*
|
||||
* @param string $pattern the pattern to be parsed
|
||||
* @return array tokenized parsing result
|
||||
*/
|
||||
protected static function parseFormat($pattern)
|
||||
{
|
||||
static $formats = array(); // cache
|
||||
if (isset($formats[$pattern])) {
|
||||
return $formats[$pattern];
|
||||
}
|
||||
$tokens = array();
|
||||
$n = strlen($pattern);
|
||||
$isLiteral = false;
|
||||
$literal = '';
|
||||
for ($i = 0; $i < $n; ++$i) {
|
||||
$c = $pattern[$i];
|
||||
if ($c === "'") {
|
||||
if ($i < $n - 1 && $pattern[$i + 1] === "'") {
|
||||
$tokens[] = "'";
|
||||
$i++;
|
||||
} elseif ($isLiteral) {
|
||||
$tokens[] = $literal;
|
||||
$literal = '';
|
||||
$isLiteral = false;
|
||||
} else {
|
||||
$isLiteral = true;
|
||||
$literal = '';
|
||||
}
|
||||
} elseif ($isLiteral) {
|
||||
$literal .= $c;
|
||||
} else {
|
||||
for ($j = $i + 1; $j < $n; ++$j) {
|
||||
if ($pattern[$j] !== $c) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$p = str_repeat($c, $j - $i);
|
||||
if (in_array($c, self::$tokens)) {
|
||||
$tokens[] = array($p);
|
||||
} else {
|
||||
$tokens[] = $p;
|
||||
}
|
||||
$i = $j - 1;
|
||||
}
|
||||
}
|
||||
if ($literal !== '') {
|
||||
$tokens[] = $literal;
|
||||
}
|
||||
return $formats[$pattern] = $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -664,6 +905,17 @@ class Date
|
|||
return $this->addHour(-$n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts `$n` seconds from `$this` date and returns the result in a new Date.
|
||||
*
|
||||
* @param int $n Number of seconds to subtract. Can be less than 0.
|
||||
* @return \Piwik\Date
|
||||
*/
|
||||
public function subSeconds($n)
|
||||
{
|
||||
return new Date($this->timestamp - $n, $this->timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a period to `$this` date and returns the result in a new Date instance.
|
||||
*
|
||||
|
|
@ -673,14 +925,41 @@ class Date
|
|||
*/
|
||||
public function addPeriod($n, $period)
|
||||
{
|
||||
if ($n < 0) {
|
||||
$ts = strtotime("$n $period", $this->timestamp);
|
||||
if (strtolower($period) == 'month') { // TODO: comments
|
||||
$dateInfo = getdate($this->timestamp);
|
||||
|
||||
$ts = mktime(
|
||||
$dateInfo['hours'],
|
||||
$dateInfo['minutes'],
|
||||
$dateInfo['seconds'],
|
||||
$dateInfo['mon'] + (int)$n,
|
||||
1,
|
||||
$dateInfo['year']
|
||||
);
|
||||
|
||||
$daysToAdd = min($dateInfo['mday'], self::getMaxDaysInMonth($ts)) - 1;
|
||||
$ts += self::NUM_SECONDS_IN_DAY * $daysToAdd;
|
||||
} else {
|
||||
$ts = strtotime("+$n $period", $this->timestamp);
|
||||
$time = $n < 0 ? "$n $period" : "+$n $period";
|
||||
|
||||
$ts = strtotime($time, $this->timestamp);
|
||||
}
|
||||
|
||||
return new Date($ts, $this->timezone);
|
||||
}
|
||||
|
||||
private static function getMaxDaysInMonth($timestamp)
|
||||
{
|
||||
$month = (int)date('m', $timestamp);
|
||||
if (date('L', $timestamp) == 1
|
||||
&& $month == 2
|
||||
) {
|
||||
return 29;
|
||||
} else {
|
||||
return self::$maxDaysInMonth[$month];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a period from `$this` date and returns the result in a new Date instance.
|
||||
*
|
||||
|
|
@ -703,4 +982,10 @@ class Date
|
|||
{
|
||||
return $secs / self::NUM_SECONDS_IN_DAY;
|
||||
}
|
||||
|
||||
private static function getInvalidDateFormatException($dateString)
|
||||
{
|
||||
$message = Piwik::translate('General_ExceptionInvalidDateFormat', array("YYYY-MM-DD, or 'today' or 'yesterday'", "strtotime", "http://php.net/strtotime"));
|
||||
return new Exception($message . ": $dateString");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue