Passed
Push — master ( 599701...cf906f )
by ignace nyamagana
03:27
created

Duration::createFromDateString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * League.Period (https://period.thephpleague.com).
5
 *
6
 * (c) Ignace Nyamagana Butera <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace League\Period;
15
16
use DateInterval;
17
use function filter_var;
18
use function preg_match;
19
use function property_exists;
20
use const FILTER_VALIDATE_INT;
21
22
/**
23
 * League Period Duration.
24
 *
25
 * @package League.period
26
 * @author  Ignace Nyamagana Butera <[email protected]>
27
 * @since   4.2.0
28
 */
29
final class Duration extends DateInterval
30
{
31
    private const REGEXP_MICROSECONDS_INTERVAL_SPEC = '@^(?<interval>.*)(\.|,)(?<fraction>\d{1,6})S$@';
32
33
    private const REGEXP_MICROSECONDS_DATE_SPEC = '@^(?<interval>.*)(\.)(?<fraction>\d{1,6})$@';
34
35
    /**
36
     * Returns a continuous portion of time between two datepoints expressed as a DateInterval object.
37
     *
38
     * The duration can be
39
     * <ul>
40
     * <li>an Period object</li>
41
     * <li>a DateInterval object</li>
42
     * <li>an integer interpreted as the duration expressed in seconds.</li>
43
     * <li>a string parsable by DateInterval::createFromDateString</li>
44
     * </ul>
45
     *
46
     * @param mixed $duration a continuous portion of time
47
     */
48
    public static function create($duration): self
49
    {
50
        if ($duration instanceof Period) {
51
            $duration = $duration->getDateInterval();
52
        }
53
54
        if ($duration instanceof DateInterval) {
55
            $new = new self('PT0S');
56
            foreach ($duration as $name => $value) {
57
                if (property_exists($new, $name)) {
58
                    $new->$name = $value;
59
                }
60
            }
61
62
            return $new;
63
        }
64
65
        if (false !== ($second = filter_var($duration, FILTER_VALIDATE_INT))) {
66
            return new self('PT'.$second.'S');
67
        }
68
69
        return self::createFromDateString($duration);
70
    }
71
72
    /**
73
     * @inheritdoc
74
     *
75
     * @param mixed $duration a date with relative parts
76
     */
77
    public static function createFromDateString($duration): self
78
    {
79
        $duration = parent::createFromDateString($duration);
80
        $new = new self('PT0S');
81
        foreach ($duration as $name => $value) {
82
            $new->$name = $value;
83
        }
84
85
        return $new;
86
    }
87
88
    /**
89
     * New instance.
90
     *
91
     * Returns a new instance from an Interval specification
92
     *
93
     * @param string $interval_spec
94
     */
95
    public function __construct($interval_spec)
96
    {
97
        if (1 === preg_match(self::REGEXP_MICROSECONDS_INTERVAL_SPEC, $interval_spec, $matches)) {
98
            parent::__construct($matches['interval'].'S');
99
            $this->f = (float) $matches['fraction'] * 1e5;
100
            return;
101
        }
102
103
        if (1 === preg_match(self::REGEXP_MICROSECONDS_DATE_SPEC, $interval_spec, $matches)) {
104
            parent::__construct($matches['interval']);
105
            $this->f = (float) $matches['fraction'];
106
            return;
107
        }
108
109
        parent::__construct($interval_spec);
110
    }
111
112
    /**
113
     * Returns the ISO8601 interval string representation.
114
     *
115
     * Microseconds fractions are included
116
     */
117
    public function __toString(): string
118
    {
119
        $date = '';
120
        foreach (['Y' => $this->y, 'M' => $this->m, 'D' => $this->d] as $key => $value) {
121
            if (0 !== $value) {
122
                $date .= $value.$key;
123
            }
124
        }
125
126
        $time = '';
127
        foreach (['H' => $this->h, 'I' => $this->i] as $key => $value) {
128
            if (0 !== $value) {
129
                $time .= $value.$key;
130
            }
131
        }
132
133
        if (0.0 !== $this->f) {
0 ignored issues
show
introduced by
The condition 0.0 !== $this->f is always true.
Loading history...
134
            $time .= $this->s.'.'.rtrim((string) ($this->f * 1e6), '0').'S';
135
136
            return 'P'.$date.'T'.$time;
137
        }
138
139
        if (0 !== $this->s) {
140
            $time .= $this->s.'S';
141
142
            return 'P'.$date.'T'.$time;
143
        }
144
145
        if ('' === $date.$time) {
146
            return 'PT0S';
147
        }
148
149
        if ('' !== $time) {
150
            return 'P'.$date.'T'.$time;
151
        }
152
153
        return 'P'.$date;
154
    }
155
}
156