GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Dates.php$0 ➔ humanDateIsYesterdayOrTomorrow()   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
dl 0
loc 37
rs 8.7057
c 0
b 0
f 0
1
<?php
2
3
namespace BFW\Helpers;
4
5
use \DateTime;
6
use \Exception;
7
8
/**
9
 * Class to have shortcuts to DateTime(Zone) methods and to display a date
10
 * with words and not only numbers (today, yesterday, since... etc).
11
 */
12
class Dates extends DateTime
13
{
14
    /**
15
     * @var string[] $humanReadableI18n Words used in method to transform
16
     *  date difference to human readable.
17
     */
18
    protected static $humanReadableI18n = [
19
        'now'          => 'now',
20
        'today_past'   => '{time} ago',
21
        'today_future' => 'in {time}',
22
        'yesterday'    => 'yesterday',
23
        'tomorrow'     => 'tomorrow',
24
        'others'       => 'the {date}',
25
        'time_part'    => ' at {time}'
26
    ];
27
28
    /**
29
     * @var string[] $humanReadableFormats Date and time formats used in
30
     *  method to transform date difference to human readable.
31
     */
32
    protected static $humanReadableFormats = [
33
        'dateSameYear'      => 'm-d',
34
        'dateDifferentYear' => 'Y-m-d',
35
        'time'              => 'H:i'
36
    ];
37
38
    /**
39
     * Return the value of the humanReadableI18n property
40
     * 
41
     * @return string[]
42
     */
43
    public static function getHumanReadableI18n(): array
44
    {
45
        return self::$humanReadableI18n;
46
    }
47
48
    /**
49
     * Define a new value for a key of the humanReadableI18n property
50
     * 
51
     * @param string $key The key in humanReadableI18n
52
     * @param string $value The new value for the key
53
     * 
54
     * @return void
55
     */
56
    public static function setHumanReadableI18nKey(string $key, string $value)
57
    {
58
        self::$humanReadableI18n[$key] = $value;
59
    }
60
61
    /**
62
     * Define a new value to the property humanReadableI18n
63
     * 
64
     * @param string[] $value The new value for the property
65
     * 
66
     * @return void
67
     */
68
    public static function setHumanReadableI18n(array $value)
69
    {
70
        self::$humanReadableI18n = $value;
71
    }
72
73
    /**
74
     * Return the value of the humanReadableFormats property
75
     * 
76
     * @return string[]
77
     */
78
    public static function getHumanReadableFormats(): array
79
    {
80
        return self::$humanReadableFormats;
81
    }
82
83
    /**
84
     * Define a new value for a key of the humanReadableFormats property
85
     * 
86
     * @param string $key The key in humanReadableFormats
87
     * @param string $value The new value for the key
88
     * 
89
     * @return void
90
     */
91
    public static function setHumanReadableFormatsKey(
92
        string $key,
93
        string $value
94
    ) {
95
        self::$humanReadableFormats[$key] = $value;
96
    }
97
98
    /**
99
     * Define a new value to the property humanReadableFormats
100
     * 
101
     * @param string[] $value The new value for the property
102
     * 
103
     * @return void
104
     */
105
    public static function setHumanReadableFormats(array $value)
106
    {
107
        self::$humanReadableFormats = $value;
108
    }
109
110
    /**
111
     * Return the date. Format is Y-m-d H:i:sO
112
     * 
113
     * @return string
114
     */
115
    public function getDate(): string
116
    {
117
        return parent::format('Y-m-d H:i:sO');
118
    }
119
120
    /**
121
     * Return a numeric representation of a year, 4 digits.
122
     * 
123
     * @return int
124
     */
125
    public function getYear(): int
126
    {
127
        return (int) parent::format('Y');
128
    }
129
130
    /**
131
     * Return the numeric representation of a month, without leading zeros.
132
     * The returned int format can not have leading zeros.
133
     * 
134
     * @return int
135
     */
136
    public function getMonth(): int
137
    {
138
        return (int) parent::format('m');
139
    }
140
141
    /**
142
     * Return the day of the month without leading zeros.
143
     * The returned int format can not have leading zeros.
144
     * 
145
     * @return int
146
     */
147
    public function getDay(): int
148
    {
149
        return (int) parent::format('d');
150
    }
151
152
    /**
153
     * Return 24-hour format without leading zeros.
154
     * The returned int format can not have leading zeros.
155
     * 
156
     * @return int
157
     */
158
    public function getHour(): int
159
    {
160
        return (int) parent::format('H');
161
    }
162
163
    /**
164
     * Return minutes, without leading zeros.
165
     * The returned int format can not have leading zeros.
166
     * 
167
     * @return int
168
     */
169
    public function getMinute(): int
170
    {
171
        return (int) parent::format('i');
172
    }
173
174
    /**
175
     * Return second, without leading zeros.
176
     * The returned int format can not have leading zeros.
177
     * 
178
     * @return int
179
     */
180
    public function getSecond(): int
181
    {
182
        return (int) parent::format('s');
183
    }
184
185
    /**
186
     * Return the difference to Greenwich time (GMT)
187
     * with colon between hours and minutes
188
     * 
189
     * @return string
190
     */
191
    public function getZone(): string
192
    {
193
        return parent::format('P');
194
    }
195
    
196
    /**
197
     * Return date's SQL format (postgresql format).
198
     * The return can be an array or a string.
199
     * 
200
     * @param boolean $returnArray (default false) True to return an array.
201
     * @param boolean $withZone (default false) True to include the timezone
202
     *  into the time returned data.
203
     * 
204
     * @return string[]|string
205
     */
206
    public function getSqlFormat(
207
        bool $returnArray = false,
208
        bool $withZone = false
209
    ) {
210
        $date = $this->format('Y-m-d');
211
        $time = $this->format('H:i:s');
212
        
213
        if ($withZone === true) {
214
            $time .= $this->format('O');
215
        }
216
217
        if ($returnArray) {
218
            return [$date, $time];
219
        }
220
221
        return $date.' '.$time;
222
    }
223
224
    /**
225
     * List all timezone existing in current php version
226
     * 
227
     * @return string[]
228
     */
229
    public function lstTimeZone(): array
230
    {
231
        return parent::getTimezone()->listIdentifiers();
232
    }
233
234
    /**
235
     * List all continent define in php DateTimeZone.
236
     * 
237
     * @return string[]
238
     */
239
    public function lstTimeZoneContinent(): array
240
    {
241
        return [
242
            'Africa',
243
            'America',
244
            'Antartica',
245
            'Arctic',
246
            'Asia',
247
            'Atlantic',
248
            'Australia',
249
            'Europe',
250
            'Indian',
251
            'Pacific'
252
        ];
253
    }
254
255
    /**
256
     * List all available country for a continent
257
     * 
258
     * @param string $continent The continent for which we want
259
     *  the countries list
260
     * 
261
     * @return string[]
262
     */
263
    public function lstTimeZoneCountries(string $continent): array
264
    {
265
        $allCountries = $this->lstTimeZone();
266
        $countries    = [];
267
268
        foreach ($allCountries as $country) {
269
            if (strpos($country, $continent) !== false) {
270
                $countries[] = $country;
271
            }
272
        }
273
274
        return $countries;
275
    }
276
277
    /**
278
     * Transform a date to a human readable format
279
     * 
280
     * @param boolean $returnDateAndTime (default true) True to return date and
281
     *  time concatenated with a space. False to have only date.
282
     * 
283
     * @return string
284
     */
285
    public function humanReadable(bool $returnDateAndTime = true): string
286
    {
287
        $current = new Dates;
288
        $diff    = parent::diff($current);
289
        
290
        $parsedTxt = new class {
291
            public $date = '';
292
            public $time = '';
293
        };
294
295
        if ($current == $this) {
296
            //Now
297
            $this->humanDateNow($parsedTxt);
298
        } elseif (
299
            $this->humanDateIsYesterdayOrTomorrow($diff, $current) === true
0 ignored issues
show
Bug introduced by
It seems like $diff can also be of type false; however, parameter $diff of BFW\Helpers\Dates::human...IsYesterdayOrTomorrow() does only seem to accept DateInterval, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

299
            $this->humanDateIsYesterdayOrTomorrow(/** @scrutinizer ignore-type */ $diff, $current) === true
Loading history...
300
        ) {
301
            if ($diff->invert === 0) {
302
                $this->humanDateYesterday($parsedTxt); //Yesterday
303
            } else {
304
                $this->humanDateTomorrow($parsedTxt); //Tomorrow
305
            }
306
        } elseif ($diff->days === 0) {
307
            //Today
308
            $this->humanDateToday($parsedTxt, $diff);
0 ignored issues
show
Bug introduced by
It seems like $diff can also be of type false; however, parameter $diff of BFW\Helpers\Dates::humanDateToday() does only seem to accept DateInterval, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

308
            $this->humanDateToday($parsedTxt, /** @scrutinizer ignore-type */ $diff);
Loading history...
309
        } else {
310
            $this->humanDateOther($parsedTxt, $current);
311
        }
312
313
        $txtReturned = $parsedTxt->date;
314
        if ($returnDateAndTime === true && $parsedTxt->time !== '') {
315
            $txtReturned .= $parsedTxt->time;
316
        }
317
318
        return $txtReturned;
319
    }
320
    
321
    /**
322
     * Check if the date to read for humanReadable is yesterday or tomorrow.
323
     * 
324
     * We cannot only check the property "d" of DateInterval because it's a
325
     * range of +/- 24 to 48 hours. If we are at 48h before, it's not ok.
326
     * 
327
     * @param \DateInterval $diff Interval between now and date to read
328
     * @param DateTime $current DateTime object for now
329
     * 
330
     * @return bool
331
     */
332
    protected function humanDateIsYesterdayOrTomorrow(
333
        \DateInterval $diff,
334
        \DateTime $current
335
    ): bool {
336
        //To check the range from 24h to 48h
337
        if (($diff->d === 1 && $diff->m === 0 && $diff->y === 0) === false) {
338
            return false;
339
        }
340
        
341
        /**
342
         * With $diff->d === 1, we know if we are in range from 24h to 48h.
343
         * But yesterday or tomorrow day can finish into the range.
344
         * 
345
         * Example :
346
         * 
347
         *    [---03/10---][---04/10---][---05/10---]
348
         * ---|----|-------|----|-------|----|------
349
         *       -48h         -24h         $this
350
         *         [ $diff->d=1 ]
351
         * 
352
         * Like we can see, the $diff->d=1 is not only on the 04/10, but also
353
         * on 03/10 because the range is from 24h to 48h before the date.
354
         * So we need a check to not display "yesterday" for the 03/10.
355
         */
356
        
357
        $twoDays = clone $current;
358
        if ($diff->invert === 0) {
359
            $twoDays->modify('-2 days');
360
        } else {
361
            $twoDays->modify('+2 days');
362
        }
363
        
364
        if ($this->format('d') === $twoDays->format('d')) {
365
            return false;
366
        }
367
        
368
        return true;
369
    }
370
    
371
    /**
372
     * Format date to human readable when the date is now
373
     * 
374
     * @param object $parsedTxt Texts returned by humanReadable method
375
     * 
376
     * @return void
377
     */
378
    protected function humanDateNow($parsedTxt)
379
    {
380
        $currentClass    = get_called_class();
381
        $parsedTxt->date = $currentClass::$humanReadableI18n['now'];
0 ignored issues
show
Bug introduced by
The property humanReadableI18n does not exist on string.
Loading history...
382
    }
383
    
384
    /**
385
     * Format date to human readable when date is today
386
     * 
387
     * @param object $parsedTxt Texts returned by humanReadable method
388
     * @param \DateInterval $diff Interval between now and date to read
389
     * 
390
     * @return void
391
     */
392
    protected function humanDateToday($parsedTxt, \DateInterval $diff)
393
    {
394
        $textKey = 'today_past';
395
        if ($diff->invert === 1) {
396
            $textKey = 'today_future';
397
        }
398
        
399
        $time = '';
400
        if ($diff->h === 0 && $diff->i === 0) {
401
            $time .= $diff->s.'s';
402
        } elseif ($diff->h === 0) {
403
            $time .= $diff->i.'min';
404
        } else {
405
            $time .= $diff->h.'h';
406
        }
407
        
408
        $currentClass    = get_called_class();
409
        $parsedTxt->date = $currentClass::$humanReadableI18n[$textKey];
0 ignored issues
show
Bug introduced by
The property humanReadableI18n does not exist on string.
Loading history...
410
        
411
        $this->humanParseDateAndTimeText($parsedTxt, '', $time);
412
    }
413
    
414
    /**
415
     * Format date to human readable when date is yesterday
416
     * 
417
     * @param object $parsedTxt Texts returned by humanReadable method
418
     * 
419
     * @return void
420
     */
421
    protected function humanDateYesterday($parsedTxt)
422
    {
423
        $currentClass    = get_called_class();
424
        $parsedTxt->date = $currentClass::$humanReadableI18n['yesterday'];
0 ignored issues
show
Bug introduced by
The property humanReadableI18n does not exist on string.
Loading history...
425
        $parsedTxt->time = $currentClass::$humanReadableI18n['time_part'];
426
        
427
        $time = $this->format($currentClass::$humanReadableFormats['time']);
0 ignored issues
show
Bug introduced by
The property humanReadableFormats does not exist on string.
Loading history...
428
        
429
        $this->humanParseDateAndTimeText($parsedTxt, '', $time);
430
    }
431
    
432
    /**
433
     * Format date to human readable when date is tomorrow
434
     * 
435
     * @param object $parsedTxt Texts returned by humanReadable method
436
     * 
437
     * @return void
438
     */
439
    protected function humanDateTomorrow($parsedTxt)
440
    {
441
        $currentClass    = get_called_class();
442
        $parsedTxt->date = $currentClass::$humanReadableI18n['tomorrow'];
0 ignored issues
show
Bug introduced by
The property humanReadableI18n does not exist on string.
Loading history...
443
        $parsedTxt->time = $currentClass::$humanReadableI18n['time_part'];
444
        
445
        $time = $this->format($currentClass::$humanReadableFormats['time']);
0 ignored issues
show
Bug introduced by
The property humanReadableFormats does not exist on string.
Loading history...
446
        
447
        $this->humanParseDateAndTimeText($parsedTxt, '', $time);
448
    }
449
    
450
    /**
451
     * Format date to human readable when date is not now, today or yesterday
452
     * 
453
     * @param object $parsedTxt Texts returned by humanReadable method
454
     * @param \DateTime $current DateTime object for now
455
     * 
456
     * @return void
457
     */
458
    protected function humanDateOther($parsedTxt, \DateTime $current)
459
    {
460
        $currentClass = get_called_class();
461
        
462
        $dateFormat = $currentClass::$humanReadableFormats['dateDifferentYear'];
0 ignored issues
show
Bug introduced by
The property humanReadableFormats does not exist on string.
Loading history...
463
        if ($current->format('Y') === $this->format('Y')) {
464
            $dateFormat = $currentClass::$humanReadableFormats['dateSameYear'];
465
        }
466
        
467
        $parsedTxt->date = $currentClass::$humanReadableI18n['others'];
0 ignored issues
show
Bug introduced by
The property humanReadableI18n does not exist on string.
Loading history...
468
        $parsedTxt->time = $currentClass::$humanReadableI18n['time_part'];
469
        
470
        $date = $this->format($dateFormat);
471
        $time = $this->format($currentClass::$humanReadableFormats['time']);
472
        
473
        $this->humanParseDateAndTimeText($parsedTxt, $date, $time);
474
    }
475
    
476
    /**
477
     * Replace the expression "{date}" by the $date value and the expression
478
     * "{time}" by the $time value into properties "date" and "time" of the
479
     * $parsedTxt object.
480
     * 
481
     * @param object $parsedTxt Texts returned by humanReadable method
482
     * @param string $date The date value used to replace "{date}" into texts
483
     * @param string $time The time value used to replace "{time}" into texts
484
     * 
485
     * @return void
486
     */
487
    protected function humanParseDateAndTimeText(
488
        $parsedTxt,
489
        string $date,
490
        string $time
491
    ) {
492
        $parsedTxt->date = str_replace('{date}', $date, $parsedTxt->date);
493
        $parsedTxt->date = str_replace('{time}', $time, $parsedTxt->date);
494
        
495
        $parsedTxt->time = str_replace('{date}', $date, $parsedTxt->time);
496
        $parsedTxt->time = str_replace('{time}', $time, $parsedTxt->time);
497
    }
498
}
499