Completed
Push — master ( ffb041...fc3bc1 )
by kill
06:36
created

TimeAgo::changeTimezone()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 5
c 1
b 0
f 1
nc 2
nop 0
dl 0
loc 8
rs 9.4285
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
    public function inStamp($past, $now = null) {
54
        if($now==null){
55
            $now=time();
56
        }
57
        // creates the "time ago" string. This always starts with an "about..."
58
        $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...
59
60
        // finds the time difference
61
        $timeDifference = $now - $past;
62
        // rule 0
63
        // $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...
64
        if ($past==0) {
65
            $timeAgo = $this->translate('never');
66
        }
67
        // rule 1
68
        // less than 29secs
69
        else if ($this->isLessThan29Seconds($timeDifference)) {
70
            $timeAgo = $this->translate('lessThanAMinute');
71
        }
72
        // rule 2
73
        // more than 29secs and less than 1min29secss
74
        else if ($this->isLessThan1Min29Seconds($timeDifference)) {
75
            $timeAgo = $this->translate('oneMinute');
76
        }
77
        // rule 3
78
        // between 1min30secs and 44mins29secs
79
        else if ($this->isLessThan44Min29Secs($timeDifference)) {
80
            $minutes = round($timeDifference / $this->secondsPerMinute);
81
            $timeAgo = $this->translate('lessThanOneHour', $minutes);
82
        }
83
        // rule 4
84
        // between 44mins30secs and 1hour29mins59secs
85
        else if ($this->isLessThan1Hour29Mins59Seconds($timeDifference)) {
86
            $timeAgo = $this->translate('aboutOneHour');
87
        }
88
        // rule 5
89
        // between 1hour29mins59secs and 23hours59mins29secs
90
        else if ($this->isLessThan23Hours59Mins29Seconds($timeDifference)) {
91
            $hours = round($timeDifference / $this->secondsPerHour);
92
            $timeAgo = $this->translate('hours', $hours);
93
        }
94
        // rule 6
95
        // between 23hours59mins30secs and 47hours59mins29secs
96
        else if ($this->isLessThan47Hours59Mins29Seconds($timeDifference)) {
97
            $timeAgo = $this->translate('aboutOneDay');
98
        }
99
        // rule 7
100
        // between 47hours59mins30secs and 29days23hours59mins29secs
101
        else if ($this->isLessThan29Days23Hours59Mins29Seconds($timeDifference)) {
102
            $days = round($timeDifference / $this->secondsPerDay);
103
            $timeAgo = $this->translate('days', $days);
104
        }
105
        // rule 8
106
        // between 29days23hours59mins30secs and 59days23hours59mins29secs
107
        else if ($this->isLessThan59Days23Hours59Mins29Secs($timeDifference)) {
108
            $timeAgo = $this->translate('aboutOneMonth');
109
        }
110
        // rule 9
111
        // 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...
112
        else if ($this->isLessThan1Year($timeDifference)) {
113
            $months = round($timeDifference / $this->secondsPerMonth);
114
            // if months is 1, then set it to 2, because we are "past" 1 month
115
            if ($months == 1) {
116
                $months = 2;
117
            }
118
119
            $timeAgo = $this->translate('months', $months);
120
        }
121
        // rule 10
122
        // 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...
123
        else if ($this->isLessThan2Years($timeDifference)) {
124
            $timeAgo = $this->translate('aboutOneYear');
125
        }
126
        // rule 11
127
        // 2years or more
128
        else {
129
            $years = floor($timeDifference / $this->secondsPerYear);
130
            $timeAgo = $this->translate('years', $years);
131
        }
132
133
        return $timeAgo;
134
    }
135
    /**
136
     * Fetches the different between $past and $now in a spoken format.
137
     * NOTE: both past and now should be parseable by strtotime
138
     * @param string $past the past date to use
139
     * @param string $now the current time, defaults to now (can be an other time though)
140
     * @return string the difference in spoken format, e.g. 1 day ago
141
     */
142
    public function inWords($past, $now = "now")
143
    {
144
145
        // finds the past in datetime
146
        $past = strtotime($past);
147
        // finds the current datetime
148
        $now = strtotime($now);
149
        if ($this->isPastEmpty($past)) {
150
            $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...
151
            $past=0;
152
        }
153
        return $this->inStamp($past,$now);
154
    }
155
156
    /**
157
     * Fetches the date difference between the two given dates.
158
     * NOTE: both past and now should be parseable by strtotime
159
     *
160
     * @param string $past the "past" time to parse
161
     * @param string $now the "now" time to parse
162
     * @return array the difference in dates, using the two dates
163
     */
164
    public function dateDifference($past, $now = "now")
165
    {
166
        // initializes the placeholders for the different "times"
167
        $seconds = 0;
168
        $minutes = 0;
169
        $hours = 0;
170
        $days = 0;
171
        $months = 0;
172
        $years = 0;
173
174
        // finds the past in datetime
175
        $past = strtotime($past);
176
        // finds the current datetime
177
        $now = strtotime($now);
178
179
        // calculates the difference
180
        $timeDifference = $now - $past;
181
182
        // starts determining the time difference
183
        if ($timeDifference >= 0) {
184
            switch ($timeDifference) {
185
                // finds the number of years
186
                case ($timeDifference >= $this->secondsPerYear):
187
                    // uses floor to remove decimals
188
                    $years = floor($timeDifference / $this->secondsPerYear);
189
                    // saves the amount of seconds left
190
                    $timeDifference = $timeDifference - ($years * $this->secondsPerYear);
191
192
                // finds the number of months
193
                case ($timeDifference >= $this->secondsPerMonth && $timeDifference <= ($this->secondsPerYear - 1)):
194
                    // uses floor to remove decimals
195
                    $months = floor($timeDifference / $this->secondsPerMonth);
196
                    // saves the amount of seconds left
197
                    $timeDifference = $timeDifference - ($months * $this->secondsPerMonth);
198
199
                // finds the number of days
200
                case ($timeDifference >= $this->secondsPerDay && $timeDifference <= ($this->secondsPerYear - 1)):
201
                    // uses floor to remove decimals
202
                    $days = floor($timeDifference / $this->secondsPerDay);
203
                    // saves the amount of seconds left
204
                    $timeDifference = $timeDifference - ($days * $this->secondsPerDay);
205
206
                // finds the number of hours
207
                case ($timeDifference >= $this->secondsPerHour && $timeDifference <= ($this->secondsPerDay - 1)):
208
                    // uses floor to remove decimals
209
                    $hours = floor($timeDifference / $this->secondsPerHour);
210
                    // saves the amount of seconds left
211
                    $timeDifference = $timeDifference - ($hours * $this->secondsPerHour);
212
213
                // finds the number of minutes
214
                case ($timeDifference >= $this->secondsPerMinute && $timeDifference <= ($this->secondsPerHour - 1)):
215
                    // uses floor to remove decimals
216
                    $minutes = floor($timeDifference / $this->secondsPerMinute);
217
                    // saves the amount of seconds left
218
                    $timeDifference = $timeDifference - ($minutes * $this->secondsPerMinute);
219
220
                // finds the number of seconds
221
                case ($timeDifference <= ($this->secondsPerMinute - 1)):
222
                    // seconds is just what there is in the timeDifference variable
223
                    $seconds = $timeDifference;
224
            }
225
        }
226
227
        $difference = [
228
            "years" => $years,
229
            "months" => $months,
230
            "days" => $days,
231
            "hours" => $hours,
232
            "minutes" => $minutes,
233
            "seconds" => $seconds,
234
        ];
235
236
        return $difference;
237
    }
238
239
    /**
240
     * Translates the given $label, and adds the given $time.
241
     * @param string $label the label to translate
242
     * @param string $time the time to add to the translated text.
243
     * @return string the translated label text including the time.
244
     */
245
    protected function translate($label, $time = '')
246
    {
247
        // handles a usecase introduced in #18, where a new translation was added.
248
        // This would cause an array-out-of-bound exception, since the index does not
249
        // exist in most translations.
250
        if (!isset(self::$timeAgoStrings[$label])) {
251
            return '';
252
        }
253
254
        return sprintf(self::$timeAgoStrings[$label], $time);
255
    }
256
257
258
    /**
259
     * Changes the timezone
260
     */
261
    protected function changeTimezone()
262
    {
263
        $this->previousTimezone = false;
264
        if ($this->timezone) {
265
            $this->previousTimezone = date_default_timezone_get();
266
            date_default_timezone_set($this->timezone);
267
        }
268
    }
269
270
    /**
271
     * Restores a previous timezone
272
     */
273
    protected function restoreTimezone()
274
    {
275
        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...
276
            date_default_timezone_set($this->previousTimezone);
277
            $this->previousTimezone = false;
278
        }
279
    }
280
281
    /**
282
     * Checks if the given past is empty
283
     * @param string $past the "past" to check
284
     * @return bool true if empty, else false
285
     */
286
    private function isPastEmpty($past)
287
    {
288
        return $past === '' || is_null($past) || empty($past);
289
    }
290
291
    /**
292
     * Checks if the time difference is less than 29seconds
293
     * @param int $timeDifference the time difference in seconds
294
     * @return bool
295
     */
296
    private function isLessThan29Seconds($timeDifference)
297
    {
298
        return $timeDifference <= 29;
299
    }
300
301
    /**
302
     * Checks if the time difference is less than 1min 29seconds
303
     * @param int $timeDifference the time difference in seconds
304
     * @return bool
305
     */
306
    private function isLessThan1Min29Seconds($timeDifference)
307
    {
308
        return $timeDifference >= 30 && $timeDifference <= 89;
309
    }
310
311
    /**
312
     * Checks if the time difference is less than 44mins 29seconds
313
     * @param int $timeDifference the time difference in seconds
314
     * @return bool
315
     */
316
    private function isLessThan44Min29Secs($timeDifference)
317
    {
318
        return $timeDifference >= 90 &&
319
            $timeDifference <= (($this->secondsPerMinute * 44) + 29);
320
    }
321
322
    /**
323
     * Checks if the time difference is less than 1hour 29mins 59seconds
324
     * @param int $timeDifference the time difference in seconds
325
     * @return bool
326
     */
327
    private function isLessThan1Hour29Mins59Seconds($timeDifference)
328
    {
329
        return $timeDifference >= (($this->secondsPerMinute * 44) + 30)
330
            &&
331
            $timeDifference <= ($this->secondsPerHour + ($this->secondsPerMinute * 29) + 59);
332
    }
333
334
    /**
335
     * Checks if the time difference is less than 23hours 59mins 29seconds
336
     * @param int $timeDifference the time difference in seconds
337
     * @return bool
338
     */
339
    private function isLessThan23Hours59Mins29Seconds($timeDifference)
340
    {
341
        return $timeDifference >= (
342
                $this->secondsPerHour +
343
                ($this->secondsPerMinute * 30)
344
            )
345
            &&
346
            $timeDifference <= (
347
                ($this->secondsPerHour * 23) +
348
                ($this->secondsPerMinute * 59) +
349
                29
350
            );
351
    }
352
353
    /**
354
     * Checks if the time difference is less than 27hours 59mins 29seconds
355
     * @param int $timeDifference the time difference in seconds
356
     * @return bool
357
     */
358
    private function isLessThan47Hours59Mins29Seconds($timeDifference)
359
    {
360
        return $timeDifference >= (
361
                ($this->secondsPerHour * 23) +
362
                ($this->secondsPerMinute * 59) +
363
                30
364
            )
365
            &&
366
            $timeDifference <= (
367
                ($this->secondsPerHour * 47) +
368
                ($this->secondsPerMinute * 59) +
369
                29
370
            );
371
    }
372
373
    /**
374
     * Checks if the time difference is less than 29days 23hours 59mins 29seconds
375
     * @param int $timeDifference the time difference in seconds
376
     * @return bool
377
     */
378
    private function isLessThan29Days23Hours59Mins29Seconds($timeDifference)
379
    {
380
        return $timeDifference >= (
381
                ($this->secondsPerHour * 47) +
382
                ($this->secondsPerMinute * 59) +
383
                30
384
            )
385
            &&
386
            $timeDifference <= (
387
                ($this->secondsPerDay * 29) +
388
                ($this->secondsPerHour * 23) +
389
                ($this->secondsPerMinute * 59) +
390
                29
391
            );
392
    }
393
394
    /**
395
     * Checks if the time difference is less than 59days 23hours 59mins 29seconds
396
     * @param int $timeDifference the time difference in seconds
397
     * @return bool
398
     */
399
    private function isLessThan59Days23Hours59Mins29Secs($timeDifference)
400
    {
401
        return $timeDifference >= (
402
                ($this->secondsPerDay * 29) +
403
                ($this->secondsPerHour * 23) +
404
                ($this->secondsPerMinute * 59) +
405
                30
406
            )
407
            &&
408
            $timeDifference <= (
409
                ($this->secondsPerDay * 59) +
410
                ($this->secondsPerHour * 23) +
411
                ($this->secondsPerMinute * 59) +
412
                29
413
            );
414
    }
415
416
    /**
417
     * Checks if the time difference is less than 1 year
418
     * @param int $timeDifference the time difference in seconds
419
     * @return bool
420
     */
421
    private function isLessThan1Year($timeDifference)
422
    {
423
        return $timeDifference >= (
424
                ($this->secondsPerDay * 59) +
425
                ($this->secondsPerHour * 23) +
426
                ($this->secondsPerMinute * 59) +
427
                30
428
            )
429
            &&
430
            $timeDifference < $this->secondsPerYear;
431
    }
432
433
    /**
434
     * Checks if the time difference is less than 2 years
435
     * @param int $timeDifference the time difference in seconds
436
     * @return bool
437
     */
438
    private function isLessThan2Years($timeDifference)
439
    {
440
        return $timeDifference >= $this->secondsPerYear
441
            &&
442
            $timeDifference < ($this->secondsPerYear * 2);
443
    }
444
}