Completed
Push — master ( 92bd35...fb5c6c )
by Tom
04:10
created

TimeElapsed   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 114
Duplicated Lines 17.54 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 20
loc 114
c 0
b 0
f 0
wmc 15
lcom 1
cbo 0
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A full() 10 10 2
A short() 10 10 2
B diff() 0 31 5
B pieces() 0 34 6

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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