Date::humanize()   B
last analyzed

Complexity

Conditions 11
Paths 14

Size

Total Lines 45
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 35
c 1
b 0
f 0
nc 14
nop 0
dl 0
loc 45
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php 
2
3
/**
4
 * Lenevor Framework
5
 *
6
 * LICENSE
7
 *
8
 * This source file is subject to the new BSD license that is bundled
9
 * with this package in the file license.md.
10
 * It is also available through the world-wide-web at this URL:
11
 * https://lenevor.com/license
12
 * If you did not receive a copy of the license and are unable to
13
 * obtain it through the world-wide-web, please send an email
14
 * to [email protected] so we can send you a copy immediately.
15
 *
16
 * @package     Lenevor
17
 * @subpackage  Base
18
 * @link        https://lenevor.com
19
 * @copyright   Copyright (c) 2019 - 2021 Alexander Campo <[email protected]>
20
 * @license     https://opensource.org/licenses/BSD-3-Clause New BSD license or see https://lenevor.com/license or see /license.md
21
 */
22
23
namespace Syscodes\Support\Chronos\Traits;
24
25
use DateTime;
26
use IntlCalendar;
27
use IntlDateFormatter;
28
29
/**
30
 * A localized date/time package inspired
31
 * by Nesbot/Carbon.
32
 * 
33
 * A simple API extension for DateTime.
34
 * 
35
 * Requires the intl PHP extension.
36
 * 
37
 * @method now($timezone = null, string $locale = null)            Returns a new Time instance with the timezone
38
 * @method today($timezone = null, string $locale = null)          Return a new time with the time set to midnight.
39
 * @method yesterday($timezone = null, string $locale = null)      Returns an instance set to midnight yesterday morning. 
40
 * @method tomorrow($timezone = null, string $locale = null)       Returns an instance set to midnight tomorrow morning.
41
 * 
42
 * 
43
 * @author Alexander Campo <[email protected]>
44
 */
45
trait Date
46
{
47
    use Factory;
48
    use Schedule;
49
    use Utilities;
50
    use Comparison;
51
    use Difference;
52
53
    /**
54
	 * Used to check time string to determine if it is relative time or not.
55
	 *
56
	 * @var string $relativePattern
57
	 */
58
    protected static $relativePattern = '/this|next|last|tomorrow|yesterday|midnight|today|[+-]|first|last|ago/i';
59
60
    /**
61
     * Identifier used to get language.
62
     * 
63
     * @var string $locale
64
     */
65
    protected $locale;
66
    
67
    /**
68
     * @var \Syscodes\Support\Chronos\Date $testNow
0 ignored issues
show
Bug introduced by
The type Syscodes\Support\Chronos\Date was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
69
     */
70
    protected static $testNow;
71
72
    /**
73
     * Get a timezone.
74
     * 
75
     * @var string $timezone
76
     */
77
    protected $timezone;
78
79
    /**
80
     * Format to use when displaying datetime through __toString.
81
     * 
82
     * @var string $toStringFormat
83
     */
84
    protected $toStringFormat = 'yyyy-MM-dd HH:mm:ss';
85
86
    // Getters
87
    
88
    /**
89
     * Returns the name of the current timezone.
90
     * 
91
     * @return string
92
     */
93
    public function getTimezoneName()
94
    {
95
        return $this->timezone->getName();
96
    }
97
98
    /**
99
     * Returns boolean whether object is in UTC.
100
     * 
101
     * @return bool
102
     */
103
    public function getUtc()
104
    {
105
        return $this->getOffset() === 0;
0 ignored issues
show
Bug introduced by
It seems like getOffset() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

105
        return $this->/** @scrutinizer ignore-call */ getOffset() === 0;
Loading history...
106
    }
107
108
    /**
109
     * Get the locale of system.
110
     * 
111
     * @return string
112
     */
113
    public function getLocale()
114
    {
115
        return $this->locale;
116
    }
117
118
    /**
119
     * Returns boolean whether the passed timezone is the same as
120
	 * the local timezone.
121
     * 
122
     * @return bool
123
     */
124
    public function getLocalized()
125
    {
126
        $local = date_default_timezone_get();
127
128
        return $local === $this->getTimezoneName();
129
    }
130
131
    // Setters
132
133
    /**
134
     * Returns a new instance with the timezone.
135
     * 
136
     * @param  \DateTimeZone  $timezone
137
     * 
138
     * @return \Syscodes\Support\Chronos\Time
139
     */
140
    public function setTimezone($timezone)
141
    {
142
        return static::parse($this->toDateTimeString(), $timezone, $this->locale);
0 ignored issues
show
Bug introduced by
$timezone of type DateTimeZone is incompatible with the type null|string expected by parameter $timezone of Syscodes\Support\Chronos\Traits\Date::parse(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

142
        return static::parse($this->toDateTimeString(), /** @scrutinizer ignore-type */ $timezone, $this->locale);
Loading history...
143
    }
144
145
    /**
146
     * Returns a new instance with the date set to the new timestamp.
147
     * 
148
     * @param  int  $timestamp
149
     * 
150
     * @return \Syscodes\Support\Chronos\Time
151
     */
152
    public function setTimestamp($timestamp)
153
    {
154
        $time = date('Y-m-d H:i:s', $timestamp);
155
156
        return static::parse($time, $this->timezone, $this->locale);
157
    }
158
159
    /**
160
     * Helper method to capture the data of reference of the 'setX' methods.
161
     * 
162
     * @param  string  $name
163
     * @param  string  $value
164
     * 
165
     * @return \Syscodes\Support\Chronos\Time
166
     */
167
    protected function setValue(string $name, $value)
168
    {
169
        list($year, $month, $day, $hour, $minute, $second) = explode('-', $this->format('Y-n-j-G-i-s'));
0 ignored issues
show
Bug introduced by
It seems like format() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

169
        list($year, $month, $day, $hour, $minute, $second) = explode('-', $this->/** @scrutinizer ignore-call */ format('Y-n-j-G-i-s'));
Loading history...
170
        $$name                                             = $value;
171
172
        return static::create(
173
            $year, $month, $day, $hour, $minute, $second, $this->getTimezoneName(), $this->locale
0 ignored issues
show
Bug introduced by
$day of type string is incompatible with the type integer|null expected by parameter $day of Syscodes\Support\Chronos\Traits\Date::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

173
            $year, $month, /** @scrutinizer ignore-type */ $day, $hour, $minute, $second, $this->getTimezoneName(), $this->locale
Loading history...
Bug introduced by
$hour of type string is incompatible with the type integer|null expected by parameter $hour of Syscodes\Support\Chronos\Traits\Date::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

173
            $year, $month, $day, /** @scrutinizer ignore-type */ $hour, $minute, $second, $this->getTimezoneName(), $this->locale
Loading history...
Bug introduced by
$minute of type string is incompatible with the type integer|null expected by parameter $minutes of Syscodes\Support\Chronos\Traits\Date::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

173
            $year, $month, $day, $hour, /** @scrutinizer ignore-type */ $minute, $second, $this->getTimezoneName(), $this->locale
Loading history...
Bug introduced by
$year of type string is incompatible with the type integer|null expected by parameter $year of Syscodes\Support\Chronos\Traits\Date::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

173
            /** @scrutinizer ignore-type */ $year, $month, $day, $hour, $minute, $second, $this->getTimezoneName(), $this->locale
Loading history...
Bug introduced by
$month of type string is incompatible with the type integer|null expected by parameter $month of Syscodes\Support\Chronos\Traits\Date::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

173
            $year, /** @scrutinizer ignore-type */ $month, $day, $hour, $minute, $second, $this->getTimezoneName(), $this->locale
Loading history...
Bug introduced by
$second of type string is incompatible with the type integer|null expected by parameter $seconds of Syscodes\Support\Chronos\Traits\Date::create(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

173
            $year, $month, $day, $hour, $minute, /** @scrutinizer ignore-type */ $second, $this->getTimezoneName(), $this->locale
Loading history...
174
        );
175
    }
176
177
    // Formatters
178
179
    /**
180
     * Converts the current instance to a mutable DateTime object.
181
     * 
182
     * @return \DateTime
183
     */
184
    public function toDateTime()
185
    {
186
        $datetime = (new DateTime(null, $this->getTimezone()))::setTimestamp(parent::getTimestamp());
0 ignored issues
show
Bug Best Practice introduced by
The method DateTime::setTimestamp() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

186
        $datetime = (new DateTime(null, $this->getTimezone()))::/** @scrutinizer ignore-call */ setTimestamp(parent::getTimestamp());
Loading history...
Bug introduced by
The method getTimezone() does not exist on Syscodes\Support\Chronos\Traits\Date. Did you maybe mean getTimezoneName()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

186
        $datetime = (new DateTime(null, $this->/** @scrutinizer ignore-call */ getTimezone()))::setTimestamp(parent::getTimestamp());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
187
        
188
        return $datetime;
189
    }
190
191
    /**
192
     * Returns the localized value of the date in the format 'Y-m-d H:i:s'.
193
     * 
194
     * @return string
195
     */
196
    public function toDateTimeString()
197
    {
198
        return $this->toLocalizedFormatter('yyyy-MM-dd HH:mm:ss');
199
    }
200
201
    /**
202
     * Returns a localized version of the date in Y-m-d format.
203
     * 
204
     * i.e. Oct 9, 2019
205
     */
206
    public function toFormattedDateString()
207
    {
208
        return $this->toLocalizedFormatter('MMM d, yyyy');
209
    }
210
211
    /**
212
     * Returns a localized version of the date in Y-m-d format.
213
     * 
214
     * @return string
215
     */
216
    public function toDateString()
217
    {
218
        return $this->toLocalizedFormatter('yyyy-MM-dd');
219
    }
220
221
     /**
222
     * Returns a localized version of the time in nicer date format.
223
     * 
224
     * i.e. 10:20:33
225
     * 
226
     * @return string
227
     */
228
    public function toTimeString()
229
    {
230
        return $this->toLocalizedFormatter('HH:mm:ss');
231
    }
232
233
    /**
234
     * Returns the localized value of this instance in a format specific by the user.
235
     * 
236
     * @param  string|null  $format
237
     * 
238
     * @return string|bool
239
     */
240
    public function toLocalizedFormatter(?string $format = null)
241
    {
242
        $format = $format ?? $this->$toStringFormat;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $toStringFormat seems to be never defined.
Loading history...
243
244
        return IntlDateFormatter::formatObject($this->toDateTime(), $format, $this->locale);
245
    }
246
247
    // Difference
248
249
    /**
250
     * Returns a text string that is easily readable that describes a 
251
     * date and time that has elapsed in a period of time specified 
252
     * by the user or system, like:
253
     * 
254
     * - 10 days ago
255
     * - in 2 days
256
     * - 9 hours ago
257
     * 
258
     * @return mixed
259
     */
260
    public function humanize()
261
    {
262
        $now     = IntlCalendar::fromDateTime(static::now($this->timezone)->toDateTimeString());
0 ignored issues
show
Bug Best Practice introduced by
The method Syscodes\Support\Chronos\Traits\Date::now() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

262
        $now     = IntlCalendar::fromDateTime(static::/** @scrutinizer ignore-call */ now($this->timezone)->toDateTimeString());
Loading history...
263
        $time    = $this->getCalendar()->getTime();
264
        $years   = $now->fieldDifference($time, IntlCalendar::FIELD_YEAR);
265
        $months  = $now->fieldDifference($time, IntlCalendar::FIELD_MONTH);
266
        $days    = $now->fieldDifference($time, IntlCalendar::FIELD_DAY_OF_YEAR);
267
        $hours   = $now->fieldDifference($time, IntlCalendar::FIELD_HOUR_OF_DAY);
268
        $minutes = $now->fieldDifference($time, IntlCalendar::FIELD_MINUTE);
269
270
        $phrase = null;
271
        
272
        if ($years !== 0) {
273
            $phrase = __('time.years', [abs($years)]);
274
            $before = $years < 0;
275
        } elseif ($months !== 0) {
276
            $phrase = __('time.months', [abs($months)]);
277
            $before = $months < 0;
278
        } elseif ($days !== 0 && (abs($days) >= 7)) {
279
            $weeks  = ceil($days / 7);
280
            $phrase = __('time.weeks', [abs($weeks)]);
281
            $before = $days < 0;
282
        } elseif ($days !== 0) {
283
            $before = $days < 0;
284
            $phrase = __('time.days', [abs($days)]);
0 ignored issues
show
Unused Code introduced by
The assignment to $phrase is dead and can be removed.
Loading history...
285
            
286
            // Yesterday/Tomorrow special cases
287
            if (abs($days) === 1) {
288
                return $before ? __('time.yesterday') : __('time.tomorrow');
289
            } else {
290
                $phrase = __('time.days', [abs($days) + 1]);
291
            }
292
        } elseif ($hours !== 0) {
293
            // Display the actual time instead of a regular phrase.
294
            return $this->format('g:i a');
295
        } elseif ($minutes !== 0) {
296
            $phrase = __('time.minutes', [abs($minutes)]);
297
            $before = $minutes < 0;
298
        } else {
299
            return __('time.now');
300
        }
301
        
302
        return $before 
303
            ? __('time.ago', [$phrase]) 
304
            : __('time.inFuture', [$phrase]);
305
    }
306
307
    // Magic Methods
308
309
    /**
310
     * Allow for property-type access to any getX method.
311
     * 
312
     * @param  string  $name
313
     * 
314
     * @return mixed
315
     */
316
    public function __get($name)
317
    {
318
        $method = 'get'.ucfirst($name);
319
320
        if (method_exists($this, $method)) {
321
            return $this->$method();
322
        }
323
324
        return null;
325
    }
326
    
327
    /**
328
     * Outputs a short format version of the datetime.
329
     * 
330
     * @return string
331
     */
332
    public function __toString()
333
    {
334
        return IntlDateFormatter::formatObject($this->toDateTime(), $this->toStringFormat, $this->locale);
335
    }
336
}