Passed
Push — master ( bc9af2...420731 )
by Sebastian
02:22
created

ConvertHelper_DurationConverter   B

Complexity

Total Complexity 49

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 98
c 1
b 0
f 0
dl 0
loc 238
rs 8.48
wmc 49

4 Methods

Rating   Name   Duplication   Size   Complexity  
A setDateFrom() 0 5 1
A __construct() 0 2 1
F convert() 0 179 46
A setDateTo() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like ConvertHelper_DurationConverter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ConvertHelper_DurationConverter, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * File containing the {@see AppUtils\ConvertHelper_DurationConverter} class.
4
 *
5
 * @package Application Utils
6
 * @subpackage ConvertHelper
7
 * @see ConvertHelper_DurationConverter
8
 */
9
10
declare(strict_types=1);
11
12
namespace AppUtils;
13
14
/**
15
 * Converts a timespan to a human readable duration string,
16
 * e.g. "2 months", "4 minutes".
17
 * 
18
 * @package Application Utils
19
 * @subpackage ConvertHelper
20
 * @author Sebastian Mordziol <[email protected]>
21
 * 
22
 * @link http://www.sajithmr.com/php-time-ago-calculation/
23
 */
24
class ConvertHelper_DurationConverter
25
{
26
    const ERROR_NO_DATE_FROM_SET = 43401;
27
    
28
    
29
   /**
30
    * @var int
31
    */
32
    protected $dateFrom;
33
    
34
   /**
35
    * @var int
36
    */
37
    protected $dateTo;
38
    
39
    public function __construct()
40
    {
41
    }
42
    
43
   /**
44
    * Sets the origin date to calculate from.
45
    * 
46
    * NOTE: if this is further in the future than
47
    * the to: date, it will be considered as a 
48
    * calculation for something to come, i.e. 
49
    * "In two days".
50
    *  
51
    * @param \DateTime $date
52
    * @return ConvertHelper_DurationConverter
53
    */
54
    public function setDateFrom(\DateTime $date) : ConvertHelper_DurationConverter
55
    {
56
        $this->dateFrom = ConvertHelper::date2timestamp($date);
57
        
58
        return $this;
59
    }
60
    
61
   /**
62
    * Sets the date to calculate to. Defaults to 
63
    * the current time if not set.
64
    * 
65
    * @param \DateTime $date
66
    * @return ConvertHelper_DurationConverter
67
    */
68
    public function setDateTo(\DateTime $date) : ConvertHelper_DurationConverter
69
    {
70
        $this->dateTo = ConvertHelper::date2timestamp($date);
71
        
72
        return $this;
73
    }
74
    
75
   /**
76
    * Converts the specified dates to a human readable string.
77
    * 
78
    * @throws ConvertHelper_Exception
79
    * @return string
80
    * 
81
    * @see ConvertHelper_DurationConverter::ERROR_NO_DATE_FROM_SET
82
    */
83
    public function convert() : string
84
    {
85
        if(!isset($this->dateFrom)) 
86
        {
87
            throw new ConvertHelper_Exception(
88
                'No date from has been specified.',
89
                null,
90
                self::ERROR_NO_DATE_FROM_SET
91
            );
92
        }
93
        
94
        // no date to set? Assume we want to use today.
95
        if(!isset($this->dateTo)) 
96
        {
97
            $this->dateTo = time();
98
        }
99
        
100
        // Calculate the difference in seconds betweeen
101
        // the two timestamps
102
        
103
        $difference = $this->dateTo - $this->dateFrom;
104
        
105
        $interval = "";
106
        
107
        $future = false;
108
        if($difference < 0) 
109
        {
110
            $difference = $difference * -1;
111
            $future = true;
112
        }
113
        
114
        // If difference is less than 60 seconds,
115
        // seconds is a good interval of choice
116
        
117
        if ($difference < 60) {
118
            $interval = "s";
119
        }
120
        
121
        // If difference is between 60 seconds and
122
        // 60 minutes, minutes is a good interval
123
        elseif ($difference >= 60 && $difference < 60 * 60) {
124
            $interval = "n";
125
        }
126
        
127
        // If difference is between 1 hour and 24 hours
128
        // hours is a good interval
129
        elseif ($difference >= 60 * 60 && $difference < 60 * 60 * 24) {
130
            $interval = "h";
131
        }
132
        
133
        // If difference is between 1 day and 7 days
134
        // days is a good interval
135
        elseif ($difference >= 60 * 60 * 24 && $difference < 60 * 60 * 24 * 7) {
136
            $interval = "d";
137
        }
138
        
139
        // If difference is between 1 week and 30 days
140
        // weeks is a good interval
141
        elseif ($difference >= 60 * 60 * 24 * 7 && $difference < 60 * 60 * 24 * 30) {
142
            $interval = "ww";
143
        }
144
        
145
        // If difference is between 30 days and 365 days
146
        // months is a good interval, again, the same thing
147
        // applies, if the 29th February happens to exist
148
        // between your 2 dates, the function will return
149
        // the 'incorrect' value for a day
150
        elseif ($difference >= 60 * 60 * 24 * 30 && $difference < 60 * 60 * 24 * 365) {
151
            $interval = "m";
152
        }
153
        
154
        // If difference is greater than or equal to 365
155
        // days, return year. This will be incorrect if
156
        // for example, you call the function on the 28th April
157
        // 2008 passing in 29th April 2007. It will return
158
        // 1 year ago when in actual fact (yawn!) not quite
159
        // a year has gone by
160
        elseif ($difference >= 60 * 60 * 24 * 365) {
161
            $interval = "y";
162
        }
163
        
164
        $result = '';
165
        
166
        // Based on the interval, determine the
167
        // number of units between the two dates
168
        // From this point on, you would be hard
169
        // pushed telling the difference between
170
        // this function and DateDiff. If the $datediff
171
        // returned is 1, be sure to return the singular
172
        // of the unit, e.g. 'day' rather 'days'
173
        switch ($interval)
174
        {
175
            case "m":
176
                $months_difference = (int)floor($difference / 60 / 60 / 24 / 29);
177
                $hour = (int)date("H", $this->dateFrom);
178
                $min = (int)date("i", $this->dateFrom);
179
                $sec = (int)date("s", $this->dateFrom);
180
                $month = (int)date("n", $this->dateFrom);
181
                $day = (int)date("j", $this->dateTo);
182
                $year = (int)date("Y", $this->dateFrom);
183
                
184
                while(mktime($hour, $min, $sec, $month + ($months_difference), $day, $year) < $this->dateTo)
185
                {
186
                    $months_difference++;
187
                }
188
                
189
                $datediff = $months_difference;
190
                
191
                // We need this in here because it is possible
192
                // to have an 'm' interval and a months
193
                // difference of 12 because we are using 29 days
194
                // in a month
195
                if ($datediff == 12) {
196
                    $datediff--;
197
                }
198
                
199
                if($future) {
200
                    $result = ($datediff == 1) ? t('In one month', $datediff) : t('In %1s months', $datediff);
201
                } else {
202
                    $result = ($datediff == 1) ? t('One month ago', $datediff) : t('%1s months ago', $datediff);
203
                }
204
                break;
205
                
206
            case "y":
207
                $datediff = floor($difference / 60 / 60 / 24 / 365);
208
                if($future) {
209
                    $result = ($datediff == 1) ? t('In one year', $datediff) : t('In %1s years', $datediff);
210
                } else {
211
                    $result = ($datediff == 1) ? t('One year ago', $datediff) : t('%1s years ago', $datediff);
212
                }
213
                break;
214
                
215
            case "d":
216
                $datediff = floor($difference / 60 / 60 / 24);
217
                if($future) {
218
                    $result = ($datediff == 1) ? t('In one day', $datediff) : t('In %1s days', $datediff);
219
                } else {
220
                    $result = ($datediff == 1) ? t('One day ago', $datediff) : t('%1s days ago', $datediff);
221
                }
222
                break;
223
                
224
            case "ww":
225
                $datediff = floor($difference / 60 / 60 / 24 / 7);
226
                if($future) {
227
                    $result = ($datediff == 1) ? t('In one week', $datediff) : t('In %1s weeks', $datediff);
228
                } else {
229
                    $result = ($datediff == 1) ? t('One week ago', $datediff) : t('%1s weeks ago', $datediff);
230
                }
231
                break;
232
                
233
            case "h":
234
                $datediff = floor($difference / 60 / 60);
235
                if($future) {
236
                    $result = ($datediff == 1) ? t('In one hour', $datediff) : t('In %1s hours', $datediff);
237
                } else {
238
                    $result = ($datediff == 1) ? t('One hour ago', $datediff) : t('%1s hours ago', $datediff);
239
                }
240
                break;
241
                
242
            case "n":
243
                $datediff = floor($difference / 60);
244
                if($future) {
245
                    $result = ($datediff == 1) ? t('In one minute', $datediff) : t('In %1s minutes', $datediff);
246
                } else {
247
                    $result = ($datediff == 1) ? t('One minute ago', $datediff) : t('%1s minutes ago', $datediff);
248
                }
249
                break;
250
                
251
            case "s":
252
                $datediff = $difference;
253
                if($future) {
254
                    $result = ($datediff == 1) ? t('In one second', $datediff) : t('In %1s seconds', $datediff);
255
                } else {
256
                    $result = ($datediff == 1) ? t('One second ago', $datediff) : t('%1s seconds ago', $datediff);
257
                }
258
                break;
259
        }
260
        
261
        return $result;
262
    }
263
}
264