Passed
Branch main (2e4b54)
by Andreas
10:30
created

CalendarDay::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10
c 1
b 0
f 0
dl 0
loc 12
rs 9.9332
cc 1
nc 1
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Copyright (c) Andreas Heigl<[email protected]>
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 *
26
 * @author    Andreas Heigl<[email protected]>
27
 * @copyright Andreas Heigl
28
 * @license   http://www.opensource.org/licenses/mit-license.php MIT-License
29
 * @since     20.02.2018
30
 * @link      http://github.com/heiglandreas/org.heigl.Holidaychecker
31
 */
32
33
namespace Org_Heigl\Holidaychecker;
34
35
use DateTimeInterface;
36
use IntlCalendar;
37
38
class CalendarDay
39
{
40
    /** @var int */
41
    private $day;
42
43
    /** @var int */
44
    private $month;
45
46
    /** @var int|null */
47
    private $year;
48
49
    /** @var IntlCalendar */
50
    private $calendar;
51
52
    public function __construct(int $day, int $month, IntlCalendar $calendar)
53
    {
54
        $this->day      = $day;
55
        $this->month    = $month;
56
        $this->year     = null;
57
        $this->calendar = $calendar;
58
        $this->calendar->set(IntlCalendar::FIELD_DAY_OF_MONTH, $day);
59
        $this->calendar->set(IntlCalendar::FIELD_MONTH, $month - 1);
60
        $this->calendar->set(IntlCalendar::FIELD_HOUR_OF_DAY, 12);
61
        $this->calendar->set(IntlCalendar::FIELD_MINUTE, 0);
62
        $this->calendar->set(IntlCalendar::FIELD_SECOND, 0);
63
        $this->calendar->set(IntlCalendar::FIELD_MILLISECOND, 0);
64
    }
65
66
    public function setYear(int $year): void
67
    {
68
        $this->year = $year;
69
        $this->calendar->set(IntlCalendar::FIELD_YEAR, $year);
70
    }
71
72
    public function setGregorianYear(int $year): void
73
    {
74
        $calendarYear = (int) $this->calendar->toDateTime()->format('Y');
75
76
        $diff = $year - $calendarYear;
77
        $realYear = $this->calendar->get(IntlCalendar::FIELD_YEAR);
78
79
        $this->year = $realYear + $diff;
80
        $this->calendar->add(IntlCalendar::FIELD_YEAR, $diff);
81
    }
82
83
    public static function setGregorianYearForDate(int $year, IntlCalendar $calendar): IntlCalendar
84
    {
85
        $datetime = $calendar->toDateTime();
86
        $yearDiff = $year - (int) $datetime->format('Y');
87
88
        $calendar->set(IntlCalendar::FIELD_YEAR, $calendar->get(IntlCalendar::FIELD_YEAR) + $yearDiff);
89
        if ($calendar->toDateTime()->format('Y') < $year) {
90
            $calendar->set(IntlCalendar::FIELD_YEAR, $calendar->get(IntlCalendar::FIELD_YEAR) + 1);
91
        }
92
        if ($calendar->toDateTime()->format('Y') > $year) {
93
            $calendar->set(IntlCalendar::FIELD_YEAR, $calendar->get(IntlCalendar::FIELD_YEAR) - 1);
94
        }
95
96
        return $calendar;
97
    }
98
99
    public function isSameDay(DateTimeInterface $dateTime): bool
100
    {
101
        $cal = clone $this->calendar;
102
        $cal->setTime($dateTime->getTimestamp() * 1000);
103
104
        if (null !== $this->year &&
105
            $cal->get(IntlCalendar::FIELD_YEAR) !== $this->calendar->get(IntlCalendar::FIELD_YEAR)
106
        ) {
107
            return false;
108
        }
109
110
        if ($cal->get(IntlCalendar::FIELD_MONTH) !== $this->calendar->get(IntlCalendar::FIELD_MONTH)) {
111
            return false;
112
        }
113
114
        return $cal->get(IntlCalendar::FIELD_DAY_OF_MONTH) === $this->calendar->get(IntlCalendar::FIELD_DAY_OF_MONTH);
115
    }
116
117
    public function isFollowUpDay(DateTimeInterface $dateTime, string $followUpDay): bool
118
    {
119
        $cal = clone $this->calendar;
120
        $cal = self::setGregorianYearForDate((int) $dateTime->format('Y'), $cal);
121
        $day = $cal->toDateTime();
122
        $day->modify('next ' . $followUpDay);
123
        $cal->setTime($day->getTimestamp() * 1000);
124
        $cal2         = clone $this->calendar;
125
        $cal2->setTime($dateTime->getTimestamp() * 1000);
126
127
        if (null !== $this->year && $cal->get(IntlCalendar::FIELD_YEAR) !== $cal2->get(IntlCalendar::FIELD_YEAR)) {
128
            return false;
129
        }
130
131
        if ($cal->get(IntlCalendar::FIELD_MONTH) !== $cal2->get(IntlCalendar::FIELD_MONTH)) {
132
            return false;
133
        }
134
135
        return $cal->get(IntlCalendar::FIELD_DAY_OF_MONTH) === $cal2->get(IntlCalendar::FIELD_DAY_OF_MONTH);
136
    }
137
138
    public function isPreviousDay(DateTimeInterface $dateTime, string $previousDay): bool
139
    {
140
        $cal = clone $this->calendar;
141
        $cal = self::setGregorianYearForDate((int) $dateTime->format('Y'), $cal);
142
        $day = $cal->toDateTime();
143
        $day->modify('previous ' . $previousDay);
144
        $cal->setTime($day->getTimestamp() * 1000);
145
        $cal2         = clone $this->calendar;
146
        $cal2->setTime($dateTime->getTimestamp() * 1000);
147
148
        if (null !== $this->year && $cal->get(IntlCalendar::FIELD_YEAR) !== $cal2->get(IntlCalendar::FIELD_YEAR)) {
149
            return false;
150
        }
151
152
        if ($cal->get(IntlCalendar::FIELD_MONTH) !== $cal2->get(IntlCalendar::FIELD_MONTH)) {
153
            return false;
154
        }
155
156
        return $cal->get(IntlCalendar::FIELD_DAY_OF_MONTH) === $cal2->get(IntlCalendar::FIELD_DAY_OF_MONTH);
157
    }
158
159
    public function getWeekdayForGregorianYear(int $year): int
160
    {
161
        $cal = $this->getDayForGregorianYear($year);
162
163
        return $cal->get(IntlCalendar::FIELD_DAY_OF_WEEK);
164
    }
165
166
    private function getDayForGregorianYear(int $gregorianYear): IntlCalendar
167
    {
168
        $cal = clone $this->calendar;
169
        $cal->set(IntlCalendar::FIELD_MONTH, $this->month - 1);
170
        $cal->set(IntlCalendar::FIELD_DAY_OF_MONTH, $this->day);
171
172
        $cal = self::setGregorianYearForDate($gregorianYear, $cal);
173
174
        return $cal;
175
    }
176
}
177