Completed
Push — master ( 6a6782...6e04b4 )
by Samson
01:03
created

DateTime::computeIsoDateNumber()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 16
rs 9.2
cc 4
eloc 11
nc 3
nop 0
1
<?php
2
3
namespace Andegna\Ethiopian;
4
5
use Andegna\Converter\Converter;
6
use Andegna\Converter\FromJdnConverter;
7
use Andegna\Validator\LeapYearValidator;
8
use DateTime as BaseDateTime;
9
use DateTimeZone;
10
11
/**
12
 * Class DateTime.
13
 *
14
 * @method getYear
15
 * @method getMonth
16
 * @method getDay
17
 * @method getDayOfYear
18
 * @method getDaysInMonth
19
 * @method getIsoWeekNumber
20
 * @method getIsoYearNumber
21
 * @method isLeapYear
22
 * @method getHour
23
 * @method getMinute
24
 * @method getSecond
25
 * @method getMicro
26
 * @method getDayOfWeek
27
 * @method getTimestamp
28
 */
29
class DateTime
30
{
31
    use DateTimeProcessor,
32
        DateFormatter;
33
34
    /** @var int */
35
    protected $year;
36
37
    /** @var int */
38
    protected $month;
39
40
    /** @var int */
41
    protected $day;
42
43
    /** @var int */
44
    protected $dayOfYear;
45
46
    /** @var int */
47
    protected $daysInMonth;
48
49
    /** @var int */
50
    protected $isoWeekNumber;
51
52
    /** @var int */
53
    protected $isoYearNumber;
54
55
    /** @var bool */
56
    protected $leapYear;
57
58
    /** @var BaseDateTime dateTime */
59
    protected $dateTime;
60
61
    /**
62
     * DateTime constructor.
63
     *
64
     * @param BaseDateTime|null $dateTime
65
     */
66
    public function __construct(BaseDateTime $dateTime = null)
67
    {
68
        if (is_null($dateTime)) {
69
            $this->dateTime = $this->defaultDateTime();
70
        } else {
71
            $this->dateTime = $dateTime;
72
        }
73
74
        $this->updateComputedFields();
75
    }
76
77
    /**
78
     * @return BaseDateTime
79
     */
80
    protected function defaultDateTime()
81
    {
82
        $dateTimeZone = new DateTimeZone(date_default_timezone_get());
83
84
        // just like the default \DateTime constructor
85
        return new BaseDateTime('now', $dateTimeZone);
86
    }
87
88
    /**
89
     * This fields are just for catching.
90
     *
91
     * @return void
92
     */
93
    protected function updateComputedFields()
94
    {
95
        // Julian Date Number of the available datetime
96
        $jdn = $this->getJdnFromBase($this->dateTime);
97
98
        $converter = new FromJdnConverter($jdn);
99
100
        $this->setDateFromConverter($converter);
101
        $this->computeFields();
102
    }
103
104
    /**
105
     * Return the JDN of the given gregorian date time.
106
     *
107
     * @param BaseDateTime $dateTime
108
     *
109
     * @return int
110
     */
111
    protected function getJdnFromBase(BaseDateTime $dateTime)
112
    {
113
        $year = $dateTime->format('Y');
114
        $month = $dateTime->format('m');
115
        $day = $dateTime->format('d');
116
117
        return gregoriantojd($month, $day, $year);
118
    }
119
120
    /**
121
     * Set the converted year, month and day from the given converter.
122
     *
123
     * @param Converter $converter
124
     *
125
     * @return void
126
     */
127
    protected function setDateFromConverter(Converter $converter)
128
    {
129
        $this->year = $converter->getYear();
130
        $this->month = $converter->getMonth();
131
        $this->day = $converter->getDay();
132
    }
133
134
    /**
135
     * Computer the available properties.
136
     *
137
     * @return void
138
     */
139
    protected function computeFields()
140
    {
141
        $this->computeLeapYear();
142
        $this->computeDayOfYear();
143
        $this->computeDaysInMonth();
144
        $this->computeIsoDateNumber();
145
    }
146
147
    /**
148
     * Compute the leapYear property.
149
     *
150
     * @return void
151
     */
152
    protected function computeLeapYear()
153
    {
154
        $leapYear = new LeapYearValidator($this->year);
155
156
        $this->leapYear = $leapYear->isValid();
157
    }
158
159
    /**
160
     * Compute the dayOfYear property.
161
     *
162
     * @return void
163
     */
164
    protected function computeDayOfYear()
165
    {
166
        $this->dayOfYear = ($this->month - 1) * 30 + ($this->day - 1);
167
    }
168
169
    /**
170
     * Compute the daysInMonth property.
171
     *
172
     * @return void
173
     */
174
    protected function computeDaysInMonth()
175
    {
176
        if ($this->month === 13) {
177
            $this->daysInMonth = $this->leapYear ? 6 : 5;
178
        }
179
180
        $this->daysInMonth = 30;
181
    }
182
183
    /**
184
     * Compute the isoWeekNumber and isoYearNumber properties.
185
     *
186
     * @return void
187
     */
188
    protected function computeIsoDateNumber()
189
    {
190
        $weekNumber = $this->getISOWeekNumberEstimate();
191
        $yearNumber = $this->year;
192
193
        if ($weekNumber == 0) {
194
            $yearNumber--;
195
            $weekNumber = $this->getLastYearLastIsoWeekNumber();
196
        } elseif ($weekNumber == 53 && $this->doesYearHas53Weeks($this->year)) {
197
            $yearNumber++;
198
            $weekNumber = 1;
199
        }
200
201
        $this->isoWeekNumber = $weekNumber;
202
        $this->isoYearNumber = $yearNumber;
203
    }
204
205
    /**
206
     * @return int
207
     */
208
    protected function getISOWeekNumberEstimate()
209
    {
210
        return (int) floor(($this->getDayOfYear() - $this->getDayOfWeek() + 10) / 7);
0 ignored issues
show
Documentation Bug introduced by
The method getDayOfYear does not exist on object<Andegna\Ethiopian\DateTime>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
Documentation Bug introduced by
The method getDayOfWeek does not exist on object<Andegna\Ethiopian\DateTime>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
211
    }
212
213
    /**
214
     * @return int
215
     */
216
    protected function getLastYearLastIsoWeekNumber()
217
    {
218
        return DateTimeFactory::lastDayOf($this->year - 1)
0 ignored issues
show
Bug introduced by
The method getIsoWeekNumber() does not exist on Andegna\Ethiopian\DateTime. Did you maybe mean getISOWeekNumberEstimate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
219
            ->getIsoWeekNumber();
220
    }
221
222
    /**
223
     * @param $year
224
     *
225
     * @return bool
226
     */
227
    protected function doesYearHas53Weeks($year)
228
    {
229
        $leapYear = (new LeapYearValidator($year))->isValid();
230
        $lastDayOfTheWeek = DateTimeFactory::lastDayOf($year)->getDayOfWeek();
0 ignored issues
show
Documentation Bug introduced by
The method getDayOfWeek does not exist on object<Andegna\Ethiopian\DateTime>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
231
232
        return ($lastDayOfTheWeek == 5 && !$leapYear)
233
            || $lastDayOfTheWeek != 4;
234
    }
235
236
    /**
237
     * Return the <b>clone</b> of the base gregorian date time.
238
     *
239
     * @return BaseDateTime
240
     */
241
    public function toGregorian()
242
    {
243
        return clone $this->dateTime;
244
    }
245
}
246