PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.2.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.2.0
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Period.php
matomo / app / core Last commit date
API 1 year ago Access 1 year ago Application 1 year ago Archive 1 year ago ArchiveProcessor 1 year ago Archiver 2 years ago AssetManager 1 year ago Auth 1 year ago Category 2 years ago Changes 1 year ago CliMulti 1 year ago Columns 1 year ago Concurrency 1 year ago Config 1 year ago Container 1 year ago CronArchive 1 year ago DataAccess 1 year ago DataFiles 2 years ago DataTable 1 year ago Db 1 year ago DeviceDetector 1 year ago Email 2 years ago Exception 1 year ago Http 1 year ago Intl 1 year ago Log 2 years ago Mail 1 year ago Measurable 1 year ago Menu 1 year ago Metrics 1 year ago Notification 1 year ago Period 1 year ago Plugin 1 year ago ProfessionalServices 1 year ago Report 1 year ago ReportRenderer 1 year ago Scheduler 1 year ago Segment 1 year ago Session 1 year ago Settings 1 year ago Tracker 1 year ago Translation 1 year ago Twig 1 year ago UpdateCheck 1 year ago Updater 1 year ago Updates 1 year ago Validators 1 year ago View 1 year ago ViewDataTable 1 year ago Visualization 1 year ago Widget 1 year ago .htaccess 2 years ago Access.php 1 year ago Archive.php 1 year ago ArchiveProcessor.php 1 year ago AssetManager.php 1 year ago Auth.php 2 years ago AuthResult.php 2 years ago BaseFactory.php 2 years ago Cache.php 2 years ago CacheId.php 1 year ago CliMulti.php 1 year ago Common.php 1 year ago Config.php 1 year ago Console.php 1 year ago Context.php 2 years ago Cookie.php 1 year ago CronArchive.php 1 year ago DI.php 1 year ago DataArray.php 1 year ago DataTable.php 1 year ago Date.php 1 year ago Db.php 1 year ago DbHelper.php 1 year ago Development.php 1 year ago ErrorHandler.php 1 year ago EventDispatcher.php 1 year ago ExceptionHandler.php 1 year ago FileIntegrity.php 1 year ago Filechecks.php 1 year ago Filesystem.php 1 year ago FrontController.php 1 year ago Http.php 1 year ago IP.php 1 year ago Log.php 2 years ago LogDeleter.php 1 year ago Mail.php 1 year ago Metrics.php 1 year ago NoAccessException.php 2 years ago Nonce.php 1 year ago Notification.php 1 year ago NumberFormatter.php 1 year ago Option.php 1 year ago Period.php 1 year ago Piwik.php 1 year ago Plugin.php 1 year ago Process.php 1 year ago Profiler.php 1 year ago ProxyHeaders.php 2 years ago ProxyHttp.php 1 year ago QuickForm2.php 1 year ago RankingQuery.php 1 year ago ReportRenderer.php 1 year ago Request.php 1 year ago Segment.php 1 year ago Sequence.php 2 years ago Session.php 1 year ago SettingsPiwik.php 1 year ago SettingsServer.php 1 year ago Singleton.php 2 years ago Site.php 1 year ago SiteContentDetector.php 1 year ago SupportedBrowser.php 2 years ago TCPDF.php 1 year ago Theme.php 1 year ago Timer.php 2 years ago Tracker.php 1 year ago Twig.php 1 year ago Unzip.php 1 year ago UpdateCheck.php 1 year ago Updater.php 1 year ago UpdaterErrorException.php 2 years ago Updates.php 1 year ago Url.php 1 year ago UrlHelper.php 1 year ago Version.php 1 year ago View.php 1 year ago bootstrap.php 1 year ago dispatch.php 2 years ago testMinimumPhpVersion.php 2 years ago
Period.php
418 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 */
9 namespace Piwik;
10
11 use Piwik\Container\StaticContainer;
12 use Piwik\Period\Factory;
13 use Piwik\Period\Range;
14 use Piwik\Translation\Translator;
15 /**
16 * Date range representation.
17 *
18 * Piwik allows users to view aggregated statistics for single days and for date
19 * ranges consisting of several days. When requesting data, a **date** string and
20 * a **period** string must be used to specify the date range that the data regards.
21 * This is the class Piwik uses to represent and manipulate those date ranges.
22 *
23 * There are five types of periods in Piwik: day, week, month, year and range,
24 * where **range** is any date range. The reason the other periods exist instead
25 * of just **range** is that Piwik will pre-archive reports for days, weeks, months
26 * and years, while every custom date range is archived on-demand.
27 *
28 * @api
29 */
30 abstract class Period
31 {
32 /**
33 * Array of subperiods
34 * @var Period[]
35 */
36 protected $subperiods = array();
37 protected $subperiodsProcessed = \false;
38 /**
39 * @var string
40 */
41 protected $label = null;
42 /**
43 * @var Date
44 */
45 protected $date = null;
46 /**
47 * @var Translator
48 */
49 protected $translator;
50 /**
51 * Constructor.
52 *
53 * @param Date $date
54 * @ignore
55 */
56 public function __construct(\Piwik\Date $date)
57 {
58 $this->date = clone $date;
59 $this->translator = StaticContainer::get('Piwik\\Translation\\Translator');
60 }
61 public function __sleep()
62 {
63 return ['date'];
64 }
65 public function __wakeup()
66 {
67 $this->translator = StaticContainer::get('Piwik\\Translation\\Translator');
68 }
69 /**
70 * Returns true if `$dateString` and `$period` represent multiple periods.
71 *
72 * Will return true for date/period combinations where date references multiple
73 * dates and period is not `'range'`. For example, will return true for:
74 *
75 * - **date** = `2012-01-01,2012-02-01` and **period** = `'day'`
76 * - **date** = `2012-01-01,2012-02-01` and **period** = `'week'`
77 * - **date** = `last7` and **period** = `'month'`
78 *
79 * etc.
80 *
81 * @static
82 * @param $dateString string The **date** query parameter value.
83 * @param $period string The **period** query parameter value.
84 * @return boolean
85 */
86 public static function isMultiplePeriod($dateString, $period)
87 {
88 return is_string($dateString) && (preg_match('/^(last|previous){1}([0-9]*)$/D', $dateString, $regs) || Range::parseDateRange($dateString)) && $period != 'range';
89 }
90 /**
91 * Checks the given date format whether it is a correct date format and if not, throw an exception.
92 *
93 * For valid date formats have a look at the {@link \Piwik\Date::factory()} method and
94 * {@link isMultiplePeriod()} method.
95 *
96 * @param string $dateString
97 * @throws \Exception If `$dateString` is in an invalid format or if the time is before
98 * Tue, 06 Aug 1991.
99 */
100 public static function checkDateFormat($dateString)
101 {
102 if (self::isMultiplePeriod($dateString, 'day')) {
103 return;
104 }
105 \Piwik\Date::factory($dateString);
106 }
107 /**
108 * Returns the first day of the period.
109 *
110 * @return Date
111 */
112 public function getDateStart()
113 {
114 $this->generate();
115 if (count($this->subperiods) == 0) {
116 return $this->getDate();
117 }
118 $periods = $this->getSubperiods();
119 /** @var $currentPeriod Period */
120 $currentPeriod = $periods[0];
121 while ($currentPeriod->getNumberOfSubperiods() > 0) {
122 $periods = $currentPeriod->getSubperiods();
123 $currentPeriod = $periods[0];
124 }
125 return $currentPeriod->getDate();
126 }
127 /**
128 * Returns the start date & time of this period.
129 *
130 * @return Date
131 */
132 public function getDateTimeStart()
133 {
134 return $this->getDateStart()->getStartOfDay();
135 }
136 /**
137 * Returns the end date & time of this period.
138 *
139 * @return Date
140 */
141 public function getDateTimeEnd()
142 {
143 return $this->getDateEnd()->getEndOfDay();
144 }
145 /**
146 * Returns the last day of the period.
147 *
148 * @return Date
149 */
150 public function getDateEnd()
151 {
152 $this->generate();
153 if (count($this->subperiods) == 0) {
154 return $this->getDate();
155 }
156 $periods = $this->getSubperiods();
157 /** @var $currentPeriod Period */
158 $currentPeriod = $periods[count($periods) - 1];
159 while ($currentPeriod->getNumberOfSubperiods() > 0) {
160 $periods = $currentPeriod->getSubperiods();
161 $currentPeriod = $periods[count($periods) - 1];
162 }
163 return $currentPeriod->getDate();
164 }
165 /**
166 * Returns the period ID.
167 *
168 * @return int A unique integer for this type of period.
169 */
170 public function getId()
171 {
172 return \Piwik\Piwik::$idPeriods[$this->getLabel()];
173 }
174 /**
175 * Returns the label for the current period.
176 *
177 * @return string `"day"`, `"week"`, `"month"`, `"year"`, `"range"`
178 */
179 public function getLabel()
180 {
181 return $this->label;
182 }
183 /**
184 * @return Date
185 */
186 protected function getDate()
187 {
188 return $this->date;
189 }
190 protected function generate()
191 {
192 $this->subperiodsProcessed = \true;
193 }
194 /**
195 * Returns the number of available subperiods.
196 *
197 * @return int
198 */
199 public function getNumberOfSubperiods()
200 {
201 $this->generate();
202 return count($this->subperiods);
203 }
204 /**
205 * Returns the set of Period instances that together make up this period. For a year,
206 * this would be 12 months. For a month this would be 28-31 days. Etc.
207 *
208 * @return Period[]
209 */
210 public function getSubperiods()
211 {
212 $this->generate();
213 return $this->subperiods;
214 }
215 /**
216 * Returns whether the date `$date` is within the current period or not.
217 *
218 * Note: the time component of the period's dates and `$date` is ignored.
219 *
220 * @param Date $today
221 * @return bool
222 */
223 public function isDateInPeriod(\Piwik\Date $date)
224 {
225 $ts = $date->getStartOfDay()->getTimestamp();
226 return $ts >= $this->getDateStart()->getStartOfDay()->getTimestamp() && $ts < $this->getDateEnd()->addDay(1)->getStartOfDay()->getTimestamp();
227 }
228 /**
229 * Returns whether the given period date range intersects with this one.
230 *
231 * @param Period $other
232 * @return bool
233 */
234 public function isPeriodIntersectingWith(\Piwik\Period $other)
235 {
236 return !($this->getDateEnd()->getTimestamp() < $other->getDateStart()->getTimestamp() || $this->getDateStart()->getTimestamp() > $other->getDateEnd()->getTimestamp());
237 }
238 /**
239 * Returns the start day and day after the end day for this period in the given timezone.
240 *
241 * @param Date[] $timezone
242 */
243 public function getBoundsInTimezone(string $timezone)
244 {
245 $date1 = $this->getDateTimeStart()->setTimezone($timezone);
246 $date2 = $this->getDateTimeEnd()->setTimezone($timezone);
247 return [$date1, $date2];
248 }
249 /**
250 * Add a date to the period.
251 *
252 * Protected because adding periods after initialization is not supported.
253 *
254 * @param \Piwik\Period $period Valid Period object
255 * @ignore
256 */
257 protected function addSubperiod($period)
258 {
259 $this->subperiods[] = $period;
260 }
261 /**
262 * Returns a list of strings representing the current period.
263 *
264 * @param string $format The format of each individual day.
265 * @return array|string An array of string dates that this period consists of.
266 */
267 public function toString($format = "Y-m-d")
268 {
269 $this->generate();
270 $dateString = array();
271 foreach ($this->subperiods as $period) {
272 $childPeriodStr = $period->toString($format);
273 if (is_array($childPeriodStr)) {
274 $childPeriodStr = implode(",", $childPeriodStr);
275 }
276 $dateString[] = $childPeriodStr;
277 }
278 return $dateString;
279 }
280 /**
281 * See {@link toString()}.
282 *
283 * @return string
284 */
285 public function __toString()
286 {
287 return implode(",", $this->toString());
288 }
289 /**
290 * Returns a pretty string describing this period.
291 *
292 * @return string
293 */
294 public abstract function getPrettyString();
295 /**
296 * Returns a short string description of this period that is localized with the currently used
297 * language.
298 *
299 * @return string
300 */
301 public abstract function getLocalizedShortString();
302 /**
303 * Returns a long string description of this period that is localized with the currently used
304 * language.
305 *
306 * @return string
307 */
308 public abstract function getLocalizedLongString();
309 /**
310 * Returns the label of the period type that is one size smaller than this one, or null if
311 * it's the smallest.
312 *
313 * Range periods and other such 'period collections' are not considered as separate from
314 * the value type of the collection. So a range period will return the result of the
315 * subperiod's `getImmediateChildPeriodLabel()` method.
316 *
317 * @ignore
318 * @return string|null
319 */
320 public abstract function getImmediateChildPeriodLabel();
321 /**
322 * Returns the label of the period type that is one size bigger than this one, or null
323 * if it's the biggest.
324 *
325 * Range periods and other such 'period collections' are not considered as separate from
326 * the value type of the collection. So a range period will return the result of the
327 * subperiod's `getParentPeriodLabel()` method.
328 *
329 * @ignore
330 */
331 public abstract function getParentPeriodLabel();
332 /**
333 * Returns the date range string comprising two dates
334 *
335 * @return string eg, `'2012-01-01,2012-01-31'`.
336 */
337 public function getRangeString()
338 {
339 $dateStart = $this->getDateStart();
340 $dateEnd = $this->getDateEnd();
341 return $dateStart->toString("Y-m-d") . "," . $dateEnd->toString("Y-m-d");
342 }
343 /**
344 * @param string $format
345 *
346 * @return mixed
347 */
348 protected function getTranslatedRange($format)
349 {
350 $dateStart = $this->getDateStart();
351 $dateEnd = $this->getDateEnd();
352 list($formatStart, $formatEnd) = $this->explodeFormat($format);
353 $string = $dateStart->getLocalized($formatStart);
354 $string .= $dateEnd->getLocalized($formatEnd, \false);
355 return $string;
356 }
357 /**
358 * Explodes the given format into two pieces. One that can be user for start date and the other for end date
359 *
360 * @param $format
361 * @return array
362 */
363 protected function explodeFormat($format)
364 {
365 $intervalTokens = array(array('d', 'E', 'C'), array('M', 'L'), array('y'));
366 $offset = strlen($format);
367 // replace string literals encapsulated by ' with same country of *
368 $cleanedFormat = preg_replace_callback('/(\'[^\']+\')/', array($this, 'replaceWithStars'), $format);
369 // search for first duplicate date field
370 foreach ($intervalTokens as $tokens) {
371 if (preg_match_all('/[' . implode('|', $tokens) . ']+/', $cleanedFormat, $matches, \PREG_OFFSET_CAPTURE) && count($matches[0]) > 1 && $offset > $matches[0][1][1]) {
372 $offset = $matches[0][1][1];
373 }
374 }
375 return array(substr($format, 0, $offset), substr($format, $offset));
376 }
377 private function replaceWithStars($matches)
378 {
379 return str_repeat("*", strlen($matches[0]));
380 }
381 protected function getRangeFormat($short = \false)
382 {
383 $maxDifference = 'D';
384 if ($this->getDateStart()->toString('y') != $this->getDateEnd()->toString('y')) {
385 $maxDifference = 'Y';
386 } elseif ($this->getDateStart()->toString('m') != $this->getDateEnd()->toString('m')) {
387 $maxDifference = 'M';
388 }
389 $dateTimeFormatProvider = StaticContainer::get('Piwik\\Intl\\Data\\Provider\\DateTimeFormatProvider');
390 return $dateTimeFormatProvider->getRangeFormatPattern($short, $maxDifference);
391 }
392 /**
393 * Returns all child periods that exist within this periods entire date range. Cascades
394 * downwards over all period types that are smaller than this one. For example, month periods
395 * will cascade to week and day periods and year periods will cascade to month, week and day
396 * periods.
397 *
398 * The method will not return periods that are outside the range of this period.
399 *
400 * @return Period[]
401 * @ignore
402 */
403 public function getAllOverlappingChildPeriods()
404 {
405 return $this->getAllOverlappingChildPeriodsInRange($this->getDateStart(), $this->getDateEnd());
406 }
407 private function getAllOverlappingChildPeriodsInRange(\Piwik\Date $dateStart, \Piwik\Date $dateEnd)
408 {
409 $result = array();
410 $childPeriodType = $this->getImmediateChildPeriodLabel();
411 if (empty($childPeriodType)) {
412 return $result;
413 }
414 $childPeriods = Factory::build($childPeriodType, $dateStart->toString() . ',' . $dateEnd->toString());
415 return array_merge($childPeriods->getSubperiods(), $childPeriods->getAllOverlappingChildPeriodsInRange($dateStart, $dateEnd));
416 }
417 }
418