1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* @author Tom Klingenberg <https://github.com/ktomk> |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace N98\Util; |
7
|
|
|
|
8
|
|
|
use BadMethodCallException; |
9
|
|
|
use DateInterval; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Class TimeElapsed |
13
|
|
|
* |
14
|
|
|
* Diff a datetime against now and return human readable output (english) like |
15
|
|
|
* 1 year 40 weeks 2 days 1 hour 5 minutes 7 seconds ago |
16
|
|
|
* or |
17
|
|
|
* just now |
18
|
|
|
* |
19
|
|
|
* @note borrowed from <http://stackoverflow.com/questions/1416697/> |
20
|
|
|
* |
21
|
|
|
* echo time_elapsed_string('2013-05-01 00:22:35'); |
22
|
|
|
* echo time_elapsed_string('@1367367755'); # timestamp input |
23
|
|
|
* echo time_elapsed_string('2013-05-01 00:22:35', true); |
24
|
|
|
* |
25
|
|
|
* with changes: |
26
|
|
|
* - extraced into static class methods |
27
|
|
|
* - it is possible to provide the time of now (instead of time() |
28
|
|
|
* - pass integers as seconds (relative to now) |
29
|
|
|
* |
30
|
|
|
* @package N98\Util |
31
|
|
|
*/ |
32
|
|
|
class TimeElapsed |
33
|
|
|
{ |
34
|
|
|
/** |
35
|
|
|
* Full format, e.g. "85 years, 10 months, 3 weeks, 1 day, 3 hours, 29 minutes, 21 seconds ago" |
36
|
|
|
* |
37
|
|
|
* @param int|string $datetimeOrSeconds numbers of seconds (int) or \DateTime time (string) |
38
|
|
|
* @param int|null $now [optional] time() |
39
|
|
|
* @return string |
40
|
|
|
*/ |
41
|
|
View Code Duplication |
public static function full($datetimeOrSeconds, $now = null) |
|
|
|
|
42
|
|
|
{ |
43
|
|
|
$diff = self::diff($datetimeOrSeconds, $now); |
44
|
|
|
|
45
|
|
|
$pieces = self::pieces($diff); |
46
|
|
|
|
47
|
|
|
$buffer = $pieces ? implode(', ', $pieces) . ' ago' : 'just now'; |
48
|
|
|
|
49
|
|
|
return $buffer; |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Short format, e.g. "85 years ago" |
54
|
|
|
* |
55
|
|
|
* @param int|string $datetimeOrSeconds numbers of seconds (int) or \DateTime time (string) |
56
|
|
|
* @param int|null $now [optional] time() |
57
|
|
|
* @return string |
58
|
|
|
*/ |
59
|
|
View Code Duplication |
public static function short($datetimeOrSeconds, $now = null) |
|
|
|
|
60
|
|
|
{ |
61
|
|
|
$diff = self::diff($datetimeOrSeconds, $now); |
62
|
|
|
|
63
|
|
|
$pieces = self::pieces($diff); |
64
|
|
|
|
65
|
|
|
$buffer = $pieces ? $pieces[0] . ' ago' : 'just now'; |
66
|
|
|
|
67
|
|
|
return $buffer; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @param int|string $datetimeOrSeconds numbers of seconds (int) or \DateTime time (string) |
72
|
|
|
* @param int|null $now [optional] time() |
73
|
|
|
* @return DateInterval |
74
|
|
|
*/ |
75
|
|
|
private static function diff($datetimeOrSeconds, $now = null) |
76
|
|
|
{ |
77
|
|
|
$tsNow = $now === null ? time() : $now; |
78
|
|
|
|
79
|
|
|
if (is_numeric($datetimeOrSeconds)) { |
80
|
|
|
// seconds |
81
|
|
|
$timestampAgo = $tsNow - $datetimeOrSeconds; |
82
|
|
|
if ($timestampAgo < 0) { |
83
|
|
|
throw new BadMethodCallException( |
84
|
|
|
sprintf('Negative unix timestamp with "%s" for now @ "%s"', $datetimeOrSeconds, $now) |
85
|
|
|
); |
86
|
|
|
} |
87
|
|
|
$dtStringAgo = "@$timestampAgo"; |
88
|
|
|
} else { |
89
|
|
|
// datetime |
90
|
|
|
$dtStringAgo = $datetimeOrSeconds; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
$now = new \DateTime("@$tsNow"); |
94
|
|
|
$ago = new \DateTime($dtStringAgo); |
95
|
|
|
|
96
|
|
|
$diff = $now->diff($ago); |
97
|
|
|
|
98
|
|
|
if ($diff === false) { |
99
|
|
|
throw new BadMethodCallException( |
100
|
|
|
sprintf('Diff failed with "%s" for now @ "%s"', $datetimeOrSeconds, $now) |
101
|
|
|
); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
return $diff; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* @param DateInterval $diff |
109
|
|
|
* @return array |
110
|
|
|
*/ |
111
|
|
|
private static function pieces(DateInterval $diff) |
112
|
|
|
{ |
113
|
|
|
$keys = array( |
114
|
|
|
'y' => 'year', |
115
|
|
|
'm' => 'month', |
116
|
|
|
'w' => 'week', |
117
|
|
|
'd' => 'day', |
118
|
|
|
'h' => 'hour', |
119
|
|
|
'i' => 'minute', |
120
|
|
|
's' => 'second', |
121
|
|
|
); |
122
|
|
|
|
123
|
|
|
// map diff |
124
|
|
|
$diffArray = array(); |
125
|
|
|
$diffVars = get_object_vars($diff); |
126
|
|
|
foreach ($keys as $unit => $name) { |
127
|
|
|
$diffArray[$unit] = isset($diffVars[$unit]) ? $diffVars[$unit] : null; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
// shorten days by weeks (note: ignoring months and years) |
131
|
|
|
$weeks = floor($diffArray['d'] / 7); |
132
|
|
|
$diffArray['w'] = $weeks; |
133
|
|
|
$diffArray['d'] -= $weeks * 7; |
134
|
|
|
|
135
|
|
|
// fill string buffer array |
136
|
|
|
$pieces = array(); |
137
|
|
|
foreach ($keys as $unit => $name) { |
138
|
|
|
if ($value = $diffArray[$unit]) { |
139
|
|
|
$pieces[] = sprintf('%s %s%s', $value, $name, $value > 1 ? 's' : ''); |
140
|
|
|
} |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
return $pieces; |
144
|
|
|
} |
145
|
|
|
} |
146
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.