Iso8601Weeks::fromUnixTime()   B
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 49
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 27
nc 7
nop 1
dl 0
loc 49
rs 8.5906
c 0
b 0
f 0
1
<?php
2
3
namespace Popy\Calendar\Converter\UnixTimeConverter;
4
5
use Popy\Calendar\Converter\Conversion;
6
use Popy\Calendar\Converter\UnixTimeConverterInterface;
7
use Popy\Calendar\Converter\CompleteLeapYearCalculatorInterface;
8
use Popy\Calendar\ValueObject\DateSolarRepresentationInterface;
9
use Popy\Calendar\ValueObject\DateFragmentedRepresentationInterface;
10
11
/**
12
 * Implementation of the standard (gregorian like) month calculation.
13
 */
14
class Iso8601Weeks implements UnixTimeConverterInterface
15
{
16
    /**
17
     * Leap year calculator.
18
     *
19
     * @var CompleteLeapYearCalculatorInterface
20
     */
21
    protected $calculator;
22
23
    /**
24
     * First day of first year weekday index. 1970 started a thursday.
25
     *
26
     * @var integer
27
     */
28
    protected $firstYearDayIndex = 3;
29
30
    /**
31
     * Class constructor.
32
     *
33
     * @param CompleteLeapYearCalculatorInterface $calculator         Leap year calculator.
34
     * @param integer|null                        $firstYearDayIndex  First day of first year weekday index.
35
     */
36
    public function __construct(CompleteLeapYearCalculatorInterface $calculator, $firstYearDayIndex = null)
37
    {
38
        $this->calculator = $calculator;
39
40
        if (null !== $firstYearDayIndex) {
41
            $this->firstYearDayIndex = $firstYearDayIndex;
42
        }
43
    }
44
45
    /**
46
     * @inheritDoc
47
     */
48
    public function fromUnixTime(Conversion $conversion)
49
    {
50
        $input = $conversion->getTo();
51
52
        if (
53
            !$input instanceof DateFragmentedRepresentationInterface
54
            || !$input instanceof DateSolarRepresentationInterface
55
        ) {
56
            return;
57
        }
58
59
        $year = (int)$input->getYear();
60
        // Assuming the era starting year is 1970, it starts a Thursday.
61
        $dayOfWeek = ($input->getEraDayIndex() + $this->firstYearDayIndex) % 7;
62
63
        // dayOfWeek may be negative is eraDayIndex was negative
64
        if ($dayOfWeek < 0) {
65
            $dayOfWeek += 7;
66
        }
67
68
        $weekIndex = null;
69
70
        // Get day yearl-index of the same week thursday
71
        $thursdayIndex = $input->getDayIndex() + 3 - $dayOfWeek;
72
73
        if ($thursdayIndex >= $this->calculator->getYearLength($year)) {
74
            $year++;
75
            $weekIndex = 0;
76
77
            $thursdayIndex -= $this->calculator->getYearLength($year);
78
        } else {
79
            if ($thursdayIndex < 0) {
80
                $year--;
81
                $thursdayIndex =
82
                    $this->calculator->getYearLength($year)
83
                    + $thursdayIndex
84
                ;
85
            }
86
87
            $weekIndex = intval($thursdayIndex / 7);
88
        }
89
90
        $dateParts = $input->getDateParts()->withTransversals([
91
            $year,
92
            $weekIndex,
93
            $dayOfWeek
94
        ]);
95
96
        $conversion->setTo($input->withDateParts($dateParts));
97
    }
98
99
    /**
100
     * @inheritDoc
101
     */
102
    public function toUnixTime(Conversion $conversion)
103
    {
104
        $input = $conversion->getTo();
105
106
        if (
107
            !$input instanceof DateFragmentedRepresentationInterface
108
            || !$input instanceof DateSolarRepresentationInterface
109
        ) {
110
            return;
111
        }
112
113
        if (null !== $input->getDayIndex() && null !== $input->getYear()) {
114
            return ;
115
        }
116
117
        $year = $input->getDateParts()->getTransversal(0);
118
        $weekIndex = $input->getDateParts()->getTransversal(1);
119
        $dayOfWeek = $input->getDateParts()->getTransversal(2);
120
121
        if (null === $year || null === $weekIndex) {
122
            // Too imprecise to be worth
123
            return;
124
        }
125
126
        $startingEraDayIndex = $this->calculator->getYearEraDayIndex($year);
127
128
        // DoW of the first day of year
129
        $dow = ($startingEraDayIndex + $this->firstYearDayIndex) % 7;
130
131
        // walk until first thursday
132
        $eraDayIndex = $startingEraDayIndex + (10 - $dow) % 7;
133
134
        // Now eraDayIndex points on the thursday of the week #0. Lets go to the
135
        // weekIndex, and move to the dayOfWeek
136
        $eraDayIndex += $weekIndex * 7 + $dayOfWeek - 3;
137
138
        $dayIndex = $eraDayIndex - $startingEraDayIndex;
139
140
        if ($dayIndex < 0) {
141
            $year--;
142
            $eraDayIndex += $this->calculator->getYearLength($year);
143
            $dayIndex = $eraDayIndex - $startingEraDayIndex;
144
        } else {
145
            $yl = $this->calculator->getYearLength($year);
146
147
            if ($dayIndex >= $yl) {
148
                $year++;
149
                $dayIndex -= $yl;
150
                $eraDayIndex += $yl;
151
            }
152
        }
153
154
        $isLeapYear = $this->calculator->isLeapYear($year);
155
156
        $input = $input
157
            ->withYear($year, $isLeapYear)
158
            ->withDayIndex($dayIndex, $eraDayIndex)
159
        ;
160
161
        $conversion->setTo($input);
162
    }
163
}
164