TimeAgo::isLessThan1Hour29Mins59Seconds()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 6
ccs 0
cts 6
cp 0
crap 6
rs 9.4285
c 1
b 0
f 1
1
<?php
2
/**
3
 * Created by rozbo at 2017/3/16 上午11:09
4
 */
5
6
namespace puck\helpers;
7
8
9
10
class TimeAgo
11
{
12
    // defines the number of seconds per "unit"
13
    private $secondsPerMinute=60;
14
    private $secondsPerHour=3600;
15
    private $secondsPerDay=86400;
16
    private $secondsPerMonth=2592000;
17
    private $secondsPerYear=31536000; // 31622400 seconds on leap years though...
18
    private $timezone;
19
    private $previousTimezone;
20
21
    private static $timeAgoStrings=array(
22
        'aboutOneDay' => "1 天前",
23
        'aboutOneHour' => "大约 1 小时前",
24
        'aboutOneMonth' => "大约 1 个月前",
25
        'aboutOneYear' => "大约 1 年前",
26
        'days' => "%s 天前",
27
        'hours' => "%s 小时前",
28
        'lessThanAMinute' => "1 分钟内",
29
        'lessThanOneHour' => "%s 分钟前",
30
        'months' => "%s 个月前",
31
        'oneMinute' => "1 分钟前",
32
        'years' => "超过 %s 年前"
33
    );
34
35
    /**
36
     * TimeAgo constructor.
37
     * @param null|DateTimeZone $timezone the timezone to use (uses system if none is given)
38
     */
39
    public function __construct($timezone=null)
40
    {
41
        $this->timezone=$timezone;
42
        // sets the default timezone
43
        $this->changeTimezone();
44
    }
45
46
    /**
47
     * 析构函数用来恢复时区
48
     */
49
    public function __destruct() {
50
        $this->restoreTimezone();
51
    }
52
53
    /**
54
     * @param integer $past
55
     * @param integer $now
56
     */
57
    public function inStamp($past, $now=null) {
58
        if ($now == null) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $now of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
59
            $now=time();
60
        }
61
        // creates the "time ago" string. This always starts with an "about..."
62
        $timeAgo="";
0 ignored issues
show
Unused Code introduced by
$timeAgo is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
63
64
        // finds the time difference
65
        $timeDifference=$now - $past;
66
        // rule 0
67
        // $past is null or empty or ''
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
68
        if ($past == 0) {
69
            $timeAgo=$this->translate('never');
70
        }
71
        // rule 1
72
        // less than 29secs
73
        else if ($this->isLessThan29Seconds($timeDifference)) {
74
            $timeAgo=$this->translate('lessThanAMinute');
75
        }
76
        // rule 2
77
        // more than 29secs and less than 1min29secss
78
        else if ($this->isLessThan1Min29Seconds($timeDifference)) {
79
            $timeAgo=$this->translate('oneMinute');
80
        }
81
        // rule 3
82
        // between 1min30secs and 44mins29secs
83
        else if ($this->isLessThan44Min29Secs($timeDifference)) {
84
            $minutes=round($timeDifference / $this->secondsPerMinute);
85
            $timeAgo=$this->translate('lessThanOneHour', $minutes);
86
        }
87
        // rule 4
88
        // between 44mins30secs and 1hour29mins59secs
89
        else if ($this->isLessThan1Hour29Mins59Seconds($timeDifference)) {
90
            $timeAgo=$this->translate('aboutOneHour');
91
        }
92
        // rule 5
93
        // between 1hour29mins59secs and 23hours59mins29secs
94
        else if ($this->isLessThan23Hours59Mins29Seconds($timeDifference)) {
95
            $hours=round($timeDifference / $this->secondsPerHour);
96
            $timeAgo=$this->translate('hours', $hours);
97
        }
98
        // rule 6
99
        // between 23hours59mins30secs and 47hours59mins29secs
100
        else if ($this->isLessThan47Hours59Mins29Seconds($timeDifference)) {
101
            $timeAgo=$this->translate('aboutOneDay');
102
        }
103
        // rule 7
104
        // between 47hours59mins30secs and 29days23hours59mins29secs
105
        else if ($this->isLessThan29Days23Hours59Mins29Seconds($timeDifference)) {
106
            $days=round($timeDifference / $this->secondsPerDay);
107
            $timeAgo=$this->translate('days', $days);
108
        }
109
        // rule 8
110
        // between 29days23hours59mins30secs and 59days23hours59mins29secs
111
        else if ($this->isLessThan59Days23Hours59Mins29Secs($timeDifference)) {
112
            $timeAgo=$this->translate('aboutOneMonth');
113
        }
114
        // rule 9
115
        // between 59days23hours59mins30secs and 1year (minus 1sec)
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
116
        else if ($this->isLessThan1Year($timeDifference)) {
117
            $months=round($timeDifference / $this->secondsPerMonth);
118
            // if months is 1, then set it to 2, because we are "past" 1 month
119
            if ($months == 1) {
120
                $months=2;
121
            }
122
123
            $timeAgo=$this->translate('months', $months);
124
        }
125
        // rule 10
126
        // between 1year and 2years (minus 1sec)
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
127
        else if ($this->isLessThan2Years($timeDifference)) {
128
            $timeAgo=$this->translate('aboutOneYear');
129
        }
130
        // rule 11
131
        // 2years or more
132
        else {
133
            $years=floor($timeDifference / $this->secondsPerYear);
134
            $timeAgo=$this->translate('years', $years);
135
        }
136
137
        return $timeAgo;
138
    }
139
    /**
140
     * Fetches the different between $past and $now in a spoken format.
141
     * NOTE: both past and now should be parseable by strtotime
142
     * @param string $past the past date to use
143
     * @param string $now the current time, defaults to now (can be an other time though)
144
     * @return string the difference in spoken format, e.g. 1 day ago
145
     */
146
    public function inWords($past, $now="now")
147
    {
148
149
        // finds the past in datetime
150
        $past=strtotime($past);
151
        // finds the current datetime
152
        $now=strtotime($now);
153
        if ($this->isPastEmpty($past)) {
154
            $past=0;
0 ignored issues
show
Unused Code introduced by
$past is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
155
            $past=0;
156
        }
157
        return $this->inStamp($past, $now);
158
    }
159
160
    /**
161
     * Fetches the date difference between the two given dates.
162
     * NOTE: both past and now should be parseable by strtotime
163
     *
164
     * @param string $past the "past" time to parse
165
     * @param string $now the "now" time to parse
166
     * @return array the difference in dates, using the two dates
167
     */
168
    public function dateDifference($past, $now="now")
169
    {
170
        // initializes the placeholders for the different "times"
171
        $seconds=0;
172
        $minutes=0;
173
        $hours=0;
174
        $days=0;
175
        $months=0;
176
        $years=0;
177
178
        // finds the past in datetime
179
        $past=strtotime($past);
180
        // finds the current datetime
181
        $now=strtotime($now);
182
183
        // calculates the difference
184
        $timeDifference=$now - $past;
185
186
        // starts determining the time difference
187
        if ($timeDifference >= 0) {
188
            switch ($timeDifference) {
189
                // finds the number of years
190
                case ($timeDifference >= $this->secondsPerYear):
191
                    // uses floor to remove decimals
192
                    $years=floor($timeDifference / $this->secondsPerYear);
193
                    // saves the amount of seconds left
194
                    $timeDifference=$timeDifference - ($years * $this->secondsPerYear);
195
196
                // finds the number of months
197
                case ($timeDifference >= $this->secondsPerMonth && $timeDifference <= ($this->secondsPerYear - 1)):
198
                    // uses floor to remove decimals
199
                    $months=floor($timeDifference / $this->secondsPerMonth);
200
                    // saves the amount of seconds left
201
                    $timeDifference=$timeDifference - ($months * $this->secondsPerMonth);
202
203
                // finds the number of days
204
                case ($timeDifference >= $this->secondsPerDay && $timeDifference <= ($this->secondsPerYear - 1)):
205
                    // uses floor to remove decimals
206
                    $days=floor($timeDifference / $this->secondsPerDay);
207
                    // saves the amount of seconds left
208
                    $timeDifference=$timeDifference - ($days * $this->secondsPerDay);
209
210
                // finds the number of hours
211
                case ($timeDifference >= $this->secondsPerHour && $timeDifference <= ($this->secondsPerDay - 1)):
212
                    // uses floor to remove decimals
213
                    $hours=floor($timeDifference / $this->secondsPerHour);
214
                    // saves the amount of seconds left
215
                    $timeDifference=$timeDifference - ($hours * $this->secondsPerHour);
216
217
                // finds the number of minutes
218
                case ($timeDifference >= $this->secondsPerMinute && $timeDifference <= ($this->secondsPerHour - 1)):
219
                    // uses floor to remove decimals
220
                    $minutes=floor($timeDifference / $this->secondsPerMinute);
221
                    // saves the amount of seconds left
222
                    $timeDifference=$timeDifference - ($minutes * $this->secondsPerMinute);
223
224
                // finds the number of seconds
225
                case ($timeDifference <= ($this->secondsPerMinute - 1)):
226
                    // seconds is just what there is in the timeDifference variable
227
                    $seconds=$timeDifference;
228
            }
229
        }
230
231
        $difference=[
232
            "years" => $years,
233
            "months" => $months,
234
            "days" => $days,
235
            "hours" => $hours,
236
            "minutes" => $minutes,
237
            "seconds" => $seconds,
238
        ];
239
240
        return $difference;
241
    }
242
243
    /**
244
     * Translates the given $label, and adds the given $time.
245
     * @param string $label the label to translate
246
     * @param string $time the time to add to the translated text.
247
     * @return string the translated label text including the time.
248
     */
249
    protected function translate($label, $time='')
250
    {
251
        // handles a usecase introduced in #18, where a new translation was added.
252
        // This would cause an array-out-of-bound exception, since the index does not
253
        // exist in most translations.
254
        if (!isset(self::$timeAgoStrings[$label])) {
255
            return '';
256
        }
257
258
        return sprintf(self::$timeAgoStrings[$label], $time);
259
    }
260
261
262
    /**
263
     * Changes the timezone
264
     */
265
    protected function changeTimezone()
266
    {
267
        $this->previousTimezone=false;
268
        if ($this->timezone) {
269
            $this->previousTimezone=date_default_timezone_get();
270
            date_default_timezone_set($this->timezone);
271
        }
272
    }
273
274
    /**
275
     * Restores a previous timezone
276
     */
277
    protected function restoreTimezone()
278
    {
279
        if ($this->previousTimezone) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->previousTimezone of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
280
            date_default_timezone_set($this->previousTimezone);
281
            $this->previousTimezone=false;
282
        }
283
    }
284
285
    /**
286
     * Checks if the given past is empty
287
     * @param string $past the "past" to check
288
     * @return bool true if empty, else false
289
     */
290
    private function isPastEmpty($past)
291
    {
292
        return $past === '' || is_null($past) || empty($past);
293
    }
294
295
    /**
296
     * Checks if the time difference is less than 29seconds
297
     * @param int $timeDifference the time difference in seconds
298
     * @return bool
299
     */
300
    private function isLessThan29Seconds($timeDifference)
301
    {
302
        return $timeDifference <= 29;
303
    }
304
305
    /**
306
     * Checks if the time difference is less than 1min 29seconds
307
     * @param int $timeDifference the time difference in seconds
308
     * @return bool
309
     */
310
    private function isLessThan1Min29Seconds($timeDifference)
311
    {
312
        return $timeDifference >= 30 && $timeDifference <= 89;
313
    }
314
315
    /**
316
     * Checks if the time difference is less than 44mins 29seconds
317
     * @param int $timeDifference the time difference in seconds
318
     * @return bool
319
     */
320
    private function isLessThan44Min29Secs($timeDifference)
321
    {
322
        return $timeDifference >= 90 &&
323
            $timeDifference <= (($this->secondsPerMinute * 44) + 29);
324
    }
325
326
    /**
327
     * Checks if the time difference is less than 1hour 29mins 59seconds
328
     * @param int $timeDifference the time difference in seconds
329
     * @return bool
330
     */
331
    private function isLessThan1Hour29Mins59Seconds($timeDifference)
332
    {
333
        return $timeDifference >= (($this->secondsPerMinute * 44) + 30)
334
            &&
335
            $timeDifference <= ($this->secondsPerHour + ($this->secondsPerMinute * 29) + 59);
336
    }
337
338
    /**
339
     * Checks if the time difference is less than 23hours 59mins 29seconds
340
     * @param int $timeDifference the time difference in seconds
341
     * @return bool
342
     */
343
    private function isLessThan23Hours59Mins29Seconds($timeDifference)
344
    {
345
        return $timeDifference >= (
346
                $this->secondsPerHour +
347
                ($this->secondsPerMinute * 30)
348
            )
349
            &&
350
            $timeDifference <= (
351
                ($this->secondsPerHour * 23) +
352
                ($this->secondsPerMinute * 59) +
353
                29
354
            );
355
    }
356
357
    /**
358
     * Checks if the time difference is less than 27hours 59mins 29seconds
359
     * @param int $timeDifference the time difference in seconds
360
     * @return bool
361
     */
362
    private function isLessThan47Hours59Mins29Seconds($timeDifference)
363
    {
364
        return $timeDifference >= (
365
                ($this->secondsPerHour * 23) +
366
                ($this->secondsPerMinute * 59) +
367
                30
368
            )
369
            &&
370
            $timeDifference <= (
371
                ($this->secondsPerHour * 47) +
372
                ($this->secondsPerMinute * 59) +
373
                29
374
            );
375
    }
376
377
    /**
378
     * Checks if the time difference is less than 29days 23hours 59mins 29seconds
379
     * @param int $timeDifference the time difference in seconds
380
     * @return bool
381
     */
382
    private function isLessThan29Days23Hours59Mins29Seconds($timeDifference)
383
    {
384
        return $timeDifference >= (
385
                ($this->secondsPerHour * 47) +
386
                ($this->secondsPerMinute * 59) +
387
                30
388
            )
389
            &&
390
            $timeDifference <= (
391
                ($this->secondsPerDay * 29) +
392
                ($this->secondsPerHour * 23) +
393
                ($this->secondsPerMinute * 59) +
394
                29
395
            );
396
    }
397
398
    /**
399
     * Checks if the time difference is less than 59days 23hours 59mins 29seconds
400
     * @param int $timeDifference the time difference in seconds
401
     * @return bool
402
     */
403
    private function isLessThan59Days23Hours59Mins29Secs($timeDifference)
404
    {
405
        return $timeDifference >= (
406
                ($this->secondsPerDay * 29) +
407
                ($this->secondsPerHour * 23) +
408
                ($this->secondsPerMinute * 59) +
409
                30
410
            )
411
            &&
412
            $timeDifference <= (
413
                ($this->secondsPerDay * 59) +
414
                ($this->secondsPerHour * 23) +
415
                ($this->secondsPerMinute * 59) +
416
                29
417
            );
418
    }
419
420
    /**
421
     * Checks if the time difference is less than 1 year
422
     * @param int $timeDifference the time difference in seconds
423
     * @return bool
424
     */
425
    private function isLessThan1Year($timeDifference)
426
    {
427
        return $timeDifference >= (
428
                ($this->secondsPerDay * 59) +
429
                ($this->secondsPerHour * 23) +
430
                ($this->secondsPerMinute * 59) +
431
                30
432
            )
433
            &&
434
            $timeDifference < $this->secondsPerYear;
435
    }
436
437
    /**
438
     * Checks if the time difference is less than 2 years
439
     * @param int $timeDifference the time difference in seconds
440
     * @return bool
441
     */
442
    private function isLessThan2Years($timeDifference)
443
    {
444
        return $timeDifference >= $this->secondsPerYear
445
            &&
446
            $timeDifference < ($this->secondsPerYear * 2);
447
    }
448
}