StandardDate::determineOffset()   C
last analyzed

Complexity

Conditions 7
Paths 32

Size

Total Lines 38
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 19
nc 32
nop 2
dl 0
loc 38
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
namespace Popy\Calendar\Parser\ResultMapper;
4
5
use DateTimeZone;
6
use Popy\Calendar\Parser\DateLexerResult;
7
use Popy\Calendar\ValueObject\TimeOffset;
8
use Popy\Calendar\Parser\ResultMapperInterface;
9
use Popy\Calendar\ValueObject\DateRepresentationInterface;
10
11
/**
12
 * Maps standard format symbols to DateRepresentationInterface fields.
13
 */
14
class StandardDate implements ResultMapperInterface
15
{
16
    /**
17
     * @inheritDoc
18
     */
19
    public function map(DateLexerResult $parts, DateRepresentationInterface $date)
20
    {
21
        $offset = $this->determineOffset($parts, $date->getOffset());
22
23
        return $date
24
            // SI Units
25
            // U   Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
26
            // u   Microseconds
27
            ->withUnixTime($parts->get('U'))
28
            ->withUnixMicroTime($parts->get('u'))
29
30
            // Offset & timezone
31
            ->withOffset($offset)
32
            ->withTimezone($this->determineTimezone(
33
                $parts,
34
                $offset,
35
                $date->getTimezone()
36
            ))
37
        ;
38
    }
39
40
    /**
41
     * Determine date's offset value/dst/abbrevaition from lexer result,
42
     * overriding only if a value is found.
43
     *
44
     * @param DateLexerResult $parts  Lexer result.
45
     * @param TimeOffset      $offset Current date offset.
46
     *
47
     * @return TimeOffset
48
     */
49
    protected function determineOffset(DateLexerResult $parts, TimeOffset $offset)
50
    {
51
        // Z   Timezone offset in seconds.
52
        if (null !== $value = $parts->get('Z')) {
53
            $value = (int)$value;
54
        } elseif (null !== $o = $parts->getFirst('O', 'P')) {
55
            // O   Difference to Greenwich time (GMT) in hours Example: +0200
56
            // P   Difference to Greenwich time (GMT) with colon between hours and minutes
57
            $o = str_replace(':', '', $o);
58
            $sign = substr($o, 0, 1);
59
            $hours = (int)substr($o, 1, 2);
60
            $minutes = (int)substr($o, 3, 2);
61
62
            $o = $hours * 60 + $minutes;
63
            $o = $o * 60;
64
65
            if ($sign === '-') {
66
                $o = -$o;
67
            }
68
69
            $value = $o;
70
        }
71
72
        if (null !== $value) {
73
            $offset = $offset->withValue($value);
74
        }
75
76
        // I (capital i) Whether or not the date is in daylight saving time
77
        if (null !== $t = $parts->get('I')) {
78
            $offset = $offset->withDst($t);
79
        }
80
        
81
        // T   Timezone abbreviation   Examples: EST, MDT ...
82
        if (null !== $t = $parts->get('T')) {
83
            $offset = $offset->withAbbreviation($t);
84
        }
85
86
        return $offset;
87
    }
88
89
    /**
90
     * Determine date's timezone. If an offset has been found, Timezone has
91
     * no effect on the date parsing, but will have on the date display.
92
     *
93
     * @param DateLexerResult   $parts   Date lexer results.
94
     * @param TimeOffset        $offset  Date offset.
95
     * @param DateTimeZone|null $inputTz Default timezone if any.
96
     *
97
     * @return DateTimeZone
98
     */
99
    protected function determineTimezone(DateLexerResult $parts, TimeOffset $offset, DateTimeZone $inputTz = null)
100
    {
101
        // e   Timezone identifier (added in PHP 5.1.0)    Examples: UTC, GMT, Atlantic/Azores
102
        // O   Difference to Greenwich time (GMT) in hours Example: +0200
103
        // P   Difference to Greenwich time (GMT) with colon between hours and minutes (added in PHP 5.1.3)    Example: +02:00
104
        if (null !== $tz = $parts->getFirst('e', 'O', 'P')) {
105
            return new DateTimeZone($tz);
106
        }
107
108
        // Create a fixed timezone matching the offset.
109
        if (null !== $tz = $offset->buildTimeZone()) {
110
            return $tz;
111
        }
112
113
        if (null !== $inputTz) {
114
            return $inputTz;
115
        }
116
117
        // Fallback.
118
        return new DateTimeZone(date_default_timezone_get());
119
    }
120
}
121