PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.7.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.7.0
5.13.0 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 6 months ago Access 8 months ago Application 6 months ago Archive 7 months ago ArchiveProcessor 6 months ago Archiver 2 years ago AssetManager 6 months ago Auth 8 months ago Category 8 months ago Changes 8 months ago CliMulti 1 year ago Columns 8 months ago Concurrency 8 months ago Config 8 months ago Container 8 months ago CronArchive 8 months ago DataAccess 7 months ago DataFiles 2 years ago DataTable 8 months ago Db 6 months ago DeviceDetector 1 year ago Email 2 years ago Exception 6 months ago Http 6 months ago Intl 8 months ago Log 2 years ago Mail 1 year ago Measurable 8 months ago Menu 8 months ago Metrics 8 months ago Notification 8 months ago Period 8 months ago Plugin 6 months ago Policy 6 months ago ProfessionalServices 1 year ago Report 1 year ago ReportRenderer 1 year ago Request 8 months ago Scheduler 8 months ago Segment 6 months ago Session 6 months ago Settings 6 months ago Tracker 6 months ago Translation 1 year ago Twig 1 year ago UpdateCheck 8 months ago Updater 6 months ago Updates 6 months ago Validators 1 year ago View 8 months ago ViewDataTable 8 months ago Visualization 1 year ago Widget 1 year ago .htaccess 2 years ago Access.php 6 months ago Archive.php 8 months ago ArchiveProcessor.php 6 months ago AssetManager.php 1 year ago Auth.php 8 months ago AuthResult.php 8 months ago BaseFactory.php 2 years ago Cache.php 2 years ago CacheId.php 6 months ago CliMulti.php 8 months ago Common.php 8 months ago Config.php 6 months ago Console.php 1 year ago Context.php 2 years ago Cookie.php 1 year ago CronArchive.php 8 months ago DI.php 1 year ago DataArray.php 7 months ago DataTable.php 6 months ago Date.php 6 months ago Db.php 1 year ago DbHelper.php 8 months ago Development.php 1 year ago ErrorHandler.php 8 months ago EventDispatcher.php 1 year ago ExceptionHandler.php 6 months ago FileIntegrity.php 1 year ago Filechecks.php 1 year ago Filesystem.php 1 year ago FrontController.php 6 months ago Http.php 6 months ago IP.php 1 year ago Log.php 8 months ago LogDeleter.php 1 year ago Mail.php 1 year ago Metrics.php 8 months ago NoAccessException.php 2 years ago Nonce.php 8 months ago Notification.php 8 months ago NumberFormatter.php 7 months ago Option.php 7 months ago Period.php 7 months ago Piwik.php 8 months ago Plugin.php 1 year ago Process.php 1 year ago Profiler.php 8 months ago ProxyHeaders.php 6 months ago ProxyHttp.php 7 months ago QuickForm2.php 1 year ago RankingQuery.php 7 months ago ReportRenderer.php 1 year ago Request.php 1 year ago Segment.php 8 months ago Sequence.php 8 months ago Session.php 1 year ago SettingsPiwik.php 1 year ago SettingsServer.php 1 year ago Singleton.php 2 years ago Site.php 6 months 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 6 months ago Twig.php 8 months 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 6 months ago UrlHelper.php 1 year ago Version.php 6 months ago View.php 8 months ago bootstrap.php 1 year ago dispatch.php 2 years ago testMinimumPhpVersion.php 8 months 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 $date
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