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