CalendarDay   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 19
eloc 58
c 4
b 0
f 0
dl 0
loc 128
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A setGregorianYear() 0 9 1
A __construct() 0 11 1
A setYear() 0 4 1
A getWeekdayForGregorianYear() 0 5 1
A getDayForGregorianYear() 0 7 1
A isModifiedDate() 0 19 4
A getCalendar() 0 3 1
A isSameDay() 0 16 4
A setGregorianYearForDate() 0 14 3
A hasYearSet() 0 3 1
A isFollowUpDay() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Copyright (c) Andreas Heigl<[email protected]>
7
 *
8
 * Licensed under the MIT-license. For details see the included file LICENSE.md
9
 */
10
11
namespace Org_Heigl\Holidaychecker;
12
13
use DateTimeInterface;
14
use IntlCalendar;
15
16
class CalendarDay
17
{
18
	/** @var int */
19
	private $day;
20
21
	/** @var int */
22
	private $month;
23
24
	/** @var int|null */
25
	private $year = null;
26
27
	/** @var IntlCalendar */
28
	private $calendar;
29
30
	public function __construct(int $day, int $month, IntlCalendar $calendar)
31
	{
32
		$this->day = $day;
33
		$this->month = $month;
34
		$this->calendar = $calendar;
35
		$this->calendar->set(IntlCalendar::FIELD_DAY_OF_MONTH, $day);
36
		$this->calendar->set(IntlCalendar::FIELD_MONTH, $month - 1);
37
		$this->calendar->set(IntlCalendar::FIELD_HOUR_OF_DAY, 12);
38
		$this->calendar->set(IntlCalendar::FIELD_MINUTE, 0);
39
		$this->calendar->set(IntlCalendar::FIELD_SECOND, 0);
40
		$this->calendar->set(IntlCalendar::FIELD_MILLISECOND, 0);
41
	}
42
43
	public function setYear(int $year): void
44
	{
45
		$this->year = $year;
46
		$this->calendar->set(IntlCalendar::FIELD_YEAR, $year);
47
	}
48
49
	public function setGregorianYear(int $year): void
50
	{
51
		$calendarYear = (int) $this->calendar->toDateTime()->format('Y');
52
53
		$diff = $year - $calendarYear;
54
		$realYear = $this->calendar->get(IntlCalendar::FIELD_YEAR);
55
56
		$this->year = $realYear + $diff;
57
		$this->calendar->add(IntlCalendar::FIELD_YEAR, $diff);
58
	}
59
60
	public function isSameDay(DateTimeInterface $dateTime): bool
61
	{
62
		$cal = clone $this->calendar;
63
		$cal->setTime($dateTime->getTimestamp() * 1000);
64
65
		if (null !== $this->year &&
66
			$cal->get(IntlCalendar::FIELD_YEAR) !== $this->calendar->get(IntlCalendar::FIELD_YEAR)
67
		) {
68
			return false;
69
		}
70
71
		if ($cal->get(IntlCalendar::FIELD_MONTH) !== $this->calendar->get(IntlCalendar::FIELD_MONTH)) {
72
			return false;
73
		}
74
75
		return $cal->get(IntlCalendar::FIELD_DAY_OF_MONTH) === $this->calendar->get(IntlCalendar::FIELD_DAY_OF_MONTH);
76
	}
77
78
	public function getCalendar(): IntlCalendar
79
	{
80
		return clone $this->calendar;
81
	}
82
83
	public function hasYearSet(): bool
84
	{
85
		return null !== $this->year;
86
	}
87
88
	public function isFollowUpDay(DateTimeInterface $dateTime, string $followUpDay): bool
89
	{
90
		return $this->isModifiedDate($dateTime, $followUpDay, 'next');
91
	}
92
93
	private function isModifiedDate(DateTimeInterface $dateTime, string $modifiedDay, string $direction): bool
94
	{
95
		$cal = clone $this->calendar;
96
		$cal = self::setGregorianYearForDate((int) $dateTime->format('Y'), $cal);
97
		$day = $cal->toDateTime();
98
		$day->modify($direction . ' ' . $modifiedDay);
99
		$cal->setTime($day->getTimestamp() * 1000);
100
		$cal2 = clone $this->calendar;
101
		$cal2->setTime($dateTime->getTimestamp() * 1000);
102
103
		if (null !== $this->year && $cal->get(IntlCalendar::FIELD_YEAR) !== $cal2->get(IntlCalendar::FIELD_YEAR)) {
104
			return false;
105
		}
106
107
		if ($cal->get(IntlCalendar::FIELD_MONTH) !== $cal2->get(IntlCalendar::FIELD_MONTH)) {
108
			return false;
109
		}
110
111
		return $cal->get(IntlCalendar::FIELD_DAY_OF_MONTH) === $cal2->get(IntlCalendar::FIELD_DAY_OF_MONTH);
112
	}
113
114
	public static function setGregorianYearForDate(int $year, IntlCalendar $calendar): IntlCalendar
115
	{
116
		$datetime = $calendar->toDateTime();
117
		$yearDiff = $year - (int) $datetime->format('Y');
118
119
		$calendar->set(IntlCalendar::FIELD_YEAR, $calendar->get(IntlCalendar::FIELD_YEAR) + $yearDiff);
120
		if ($calendar->toDateTime()->format('Y') < $year) {
121
			$calendar->set(IntlCalendar::FIELD_YEAR, $calendar->get(IntlCalendar::FIELD_YEAR) + 1);
122
		}
123
		if ($calendar->toDateTime()->format('Y') > $year) {
124
			$calendar->set(IntlCalendar::FIELD_YEAR, $calendar->get(IntlCalendar::FIELD_YEAR) - 1);
125
		}
126
127
		return $calendar;
128
	}
129
130
	public function getWeekdayForGregorianYear(int $year): int
131
	{
132
		$cal = $this->getDayForGregorianYear($year);
133
134
		return $cal->get(IntlCalendar::FIELD_DAY_OF_WEEK);
135
	}
136
137
	private function getDayForGregorianYear(int $gregorianYear): IntlCalendar
138
	{
139
		$cal = clone $this->calendar;
140
		$cal->set(IntlCalendar::FIELD_MONTH, $this->month - 1);
141
		$cal->set(IntlCalendar::FIELD_DAY_OF_MONTH, $this->day);
142
143
		return self::setGregorianYearForDate($gregorianYear, $cal);
144
	}
145
}
146