Passed
Push — master ( c1d97f...7cdedb )
by Carlos C
02:15 queued 11s
created

HusoHorario::invierno()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpCfdi\SatCatalogos\CFDI;
6
7
use DateTimeImmutable;
8
use PhpCfdi\SatCatalogos\Exceptions\SatCatalogosLogicException;
9
10
class HusoHorario
11
{
12
    /** @var string */
13
    private $text;
14
15
    /** @var HusoHorarioEstacion */
16
    private $verano;
17
18
    /** @var HusoHorarioEstacion */
19
    private $invierno;
20
21 20
    public function __construct(string $text, HusoHorarioEstacion $verano, HusoHorarioEstacion $invierno)
22
    {
23 20
        $this->text = $text;
24 20
        $this->verano = $verano;
25 20
        $this->invierno = $invierno;
26
27 20
        if ($verano->tieneCambioHorario() !== $invierno->tieneCambioHorario()) {
28 1
            throw new SatCatalogosLogicException(
29 1
                'No se puede crear un huso horario con estaciones donde solo una tiene cambio de horario'
30
            );
31
        }
32
33 19
        if (! $verano->tieneCambioHorario() and $verano->diferencia() !== $invierno->diferencia()) {
34 1
            throw new SatCatalogosLogicException(
35 1
                'El huso horario no tiene cambio de horario de verano pero tiene no tiene la misma diferencia horaria'
36
            );
37
        }
38 18
    }
39
40 2
    public function nombre(): string
41
    {
42 2
        return $this->text;
43
    }
44
45 2
    public function verano(): HusoHorarioEstacion
46
    {
47 2
        return $this->verano;
48
    }
49
50 2
    public function invierno(): HusoHorarioEstacion
51
    {
52 2
        return $this->invierno;
53
    }
54
55 10
    public function convertToDateTime(string $partialDate): DateTimeImmutable
56
    {
57 10
        $date = $this->dateTimeFromPartial($partialDate, $this->invierno->diferencia());
58
59
        // time zone does not have DST
60 10
        if (! $this->verano->tieneCambioHorario()) {
61
            return $date;
62
        }
63
64 10
        $year = (int) $date->format('Y');
65 10
        $dstSince = $this->dstLimit($year, $this->verano, $this->invierno->diferencia());
66 10
        $dstUntil = $this->dstLimit($year, $this->invierno, $this->invierno->diferencia());
67
68
        // is outside DST, nothing to change
69 10
        if ($date < $dstSince || $date >= $dstUntil) {
70 5
            return $date;
71
        }
72
73
        // is DST
74 5
        $dstHoursDiff = $this->verano->diferencia() - $this->invierno->diferencia();
75 5
        $dstSince = $dstSince->modify(sprintf('%d hours', $dstHoursDiff));
76 5
        $altered = $this->dateTimeFromPartial($partialDate, $this->verano->diferencia());
77 5
        if ($date < $dstSince) {
78 2
            $altered = $altered->modify(sprintf('%d hours', $dstHoursDiff));
79
        }
80 5
        return $altered;
81
    }
82
83 10
    private function dateTimeFromPartial(string $partialDate, int $hoursDiff): DateTimeImmutable
84
    {
85 10
        $sign = $hoursDiff < 0 ? '-' : '+';
86 10
        $iso8601 = sprintf('%s%s%02d00', $partialDate, $sign, abs($hoursDiff));
87
        /** @noinspection PhpUnhandledExceptionInspection */
88 10
        return new DateTimeImmutable($iso8601);
89
    }
90
91 10
    private function dstLimit(int $year, HusoHorarioEstacion $limit, int $hoursDiff): DateTimeImmutable
92
    {
93
        /** @noinspection PhpUnhandledExceptionInspection */
94 10
        $date = new DateTimeImmutable(sprintf('%04d-%02d-01 00:00:00 UTC', $year, $limit->mesNumerico()));
95 10
        $date = $date->modify($limit->diaExpresion());
96 10
        $date = $date->modify(sprintf('%d hours', $limit->horaNumero() - $hoursDiff));
97 10
        return $date;
98
    }
99
}
100