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