Passed
Push — master ( 7cdedb...e314df )
by Carlos C
57s queued 10s
created

HusoHorario   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 95
Duplicated Lines 0 %

Test Coverage

Coverage 90.91%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 41
c 2
b 0
f 0
dl 0
loc 95
ccs 40
cts 44
cp 0.9091
rs 10
wmc 15

7 Methods

Rating   Name   Duplication   Size   Complexity  
A dstLimit() 0 7 1
A invierno() 0 3 1
A verano() 0 3 1
A nombre() 0 3 1
A dateTimeFromPartial() 0 5 1
A convertToDateTime() 0 34 6
A __construct() 0 15 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpCfdi\SatCatalogos\CFDI;
6
7
use DateTimeImmutable;
8
use Exception;
9
use PhpCfdi\SatCatalogos\Exceptions\SatCatalogosLogicException;
10
11
class HusoHorario
12
{
13
    /** @var string */
14
    private $text;
15
16
    /** @var HusoHorarioEstacion */
17
    private $verano;
18
19
    /** @var HusoHorarioEstacion */
20
    private $invierno;
21
22 20
    public function __construct(string $text, HusoHorarioEstacion $verano, HusoHorarioEstacion $invierno)
23
    {
24 20
        $this->text = $text;
25 20
        $this->verano = $verano;
26 20
        $this->invierno = $invierno;
27
28 20
        if ($verano->tieneCambioHorario() !== $invierno->tieneCambioHorario()) {
29 1
            throw new SatCatalogosLogicException(
30 1
                'No se puede crear un huso horario con estaciones donde solo una tiene cambio de horario'
31
            );
32
        }
33
34 19
        if (! $verano->tieneCambioHorario() and $verano->diferencia() !== $invierno->diferencia()) {
35 1
            throw new SatCatalogosLogicException(
36 1
                'El huso horario no tiene cambio de horario de verano pero tiene no tiene la misma diferencia horaria'
37
            );
38
        }
39 18
    }
40
41 2
    public function nombre(): string
42
    {
43 2
        return $this->text;
44
    }
45
46 2
    public function verano(): HusoHorarioEstacion
47
    {
48 2
        return $this->verano;
49
    }
50
51 2
    public function invierno(): HusoHorarioEstacion
52
    {
53 2
        return $this->invierno;
54
    }
55
56 10
    public function convertToDateTime(string $partialDateText): DateTimeImmutable
57
    {
58
        try {
59 10
            $partialDate = new DateTimeImmutable($partialDateText);
60
        } catch (Exception $exception) {
61
            throw new SatCatalogosLogicException(
62
                sprintf('No se puede entender la fecha parcial "%s" como una fecha', $partialDateText)
63
            );
64
        }
65
66 10
        $date = $this->dateTimeFromPartial($partialDate, $this->invierno->diferencia());
67
68
        // time zone does not have DST
69 10
        if (! $this->verano->tieneCambioHorario()) {
70
            return $date;
71
        }
72
73 10
        $year = (int) $date->format('Y');
74 10
        $dstSince = $this->dstLimit($year, $this->verano, $this->invierno->diferencia());
75 10
        $dstUntil = $this->dstLimit($year, $this->invierno, $this->invierno->diferencia());
76
77
        // is outside DST, nothing to change: NOT $dstSince <= $date < $dstUntil
78 10
        if ($date < $dstSince || $date >= $dstUntil) {
79 5
            return $date;
80
        }
81
82
        // is DST
83 5
        $dstHoursDiff = $this->verano->diferencia() - $this->invierno->diferencia();
84 5
        $dstSince = $dstSince->modify("{$dstHoursDiff} hours");
85 5
        $summerDate = $this->dateTimeFromPartial($partialDate, $this->verano->diferencia());
86 5
        if ($date < $dstSince) { // time is between a non-existent hour
87 2
            $summerDate = $summerDate->modify("{$dstHoursDiff} hours");
88
        }
89 5
        return $summerDate;
90
    }
91
92 10
    private function dateTimeFromPartial(DateTimeImmutable $partialDate, int $hoursDiff): DateTimeImmutable
93
    {
94 10
        $iso8601 = sprintf('%s%+02d00', $partialDate->format('Y-m-d\TH:i:s'), $hoursDiff);
95
        /** @noinspection PhpUnhandledExceptionInspection */
96 10
        return new DateTimeImmutable($iso8601);
97
    }
98
99 10
    private function dstLimit(int $year, HusoHorarioEstacion $limit, int $hoursDiff): DateTimeImmutable
100
    {
101
        /** @noinspection PhpUnhandledExceptionInspection */
102 10
        $date = new DateTimeImmutable(sprintf('%04d-%02d-01T00:00:00+000', $year, $limit->mesNumerico()));
103 10
        $date = $date->modify($limit->diaExpresion());
104 10
        $date = $date->modify(sprintf('%d hours', $limit->horaNumero() - $hoursDiff));
105 10
        return $date;
106
    }
107
}
108