Passed
Push — master ( 6b6e47...003970 )
by y
01:34
created

DateTimeTrait::modify()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 4
eloc 12
c 2
b 1
f 0
nc 8
nop 6
dl 0
loc 21
rs 9.8666
1
<?php
2
3
namespace Helix\DB\Fluent\DateTime;
4
5
use Helix\DB\Fluent\DateTime;
6
use Helix\DB\Fluent\Num;
7
use Helix\DB\Fluent\Str;
8
use Helix\DB\Fluent\Value\ValueTrait;
9
10
/**
11
 * Date-time expression manipulation.
12
 *
13
 * @see https://sqlite.org/lang_datefunc.html
14
 * @see https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format
15
 */
16
trait DateTimeTrait
17
{
18
19
    use DateTimeModifyTrait;
20
    use ValueTrait;
21
22
    /**
23
     * `YYYY-MM-DD`
24
     *
25
     * Because this format is reentrant, a {@link DateTime} is returned.
26
     *
27
     * @return DateTime
28
     */
29
    public function date()
30
    {
31
        return DateTime::factory($this->db, "DATE({$this})");
32
    }
33
34
    /**
35
     * Date formatting expression using a driver-appropriate function.
36
     *
37
     * @param string|string[] $format Format, or formats keyed by driver name.
38
     * @return Str
39
     */
40
    public function dateFormat($format)
41
    {
42
        if (is_array($format)) {
43
            $format = $format[$this->db->getDriver()];
44
        }
45
        $format = $this->db->quote($format);
46
        if ($this->db->isSQLite()) {
47
            return Str::factory($this->db, "STRFTIME({$format},{$this})");
48
        }
49
        return Str::factory($this->db, "DATE_FORMAT({$this},{$format})");
50
    }
51
52
    /**
53
     * `YYYY-MM-DD hh:mm:ss`
54
     *
55
     * Because this format is reentrant, a {@link DateTime} is returned.
56
     *
57
     * @return DateTime
58
     */
59
    public function datetime()
60
    {
61
        return DateTime::fromFormat($this->db, [
62
            'mysql' => "DATE_FORMAT(%s,'%%Y-%%m-%%d %%H:%%i:%%S')",
63
            'sqlite' => "DATETIME(%s)"
64
        ], $this);
65
    }
66
67
    /**
68
     * `01` to `31`
69
     *
70
     * @return Num
71
     */
72
    public function day()
73
    {
74
        return Num::factory($this->db, $this->dateFormat('%d'));
75
    }
76
77
    /**
78
     * `0` to `6` (Sunday is `0`)
79
     *
80
     * @return Num
81
     */
82
    public function dayOfWeek()
83
    {
84
        return Num::factory($this->db, $this->dateFormat('%w'));
85
    }
86
87
    /**
88
     * `001` to `366` (365 + 1 during leap year)
89
     *
90
     * @return Num
91
     */
92
    public function dayOfYear()
93
    {
94
        return Num::factory($this->db, $this->dateFormat('%j'));
95
    }
96
97
    /**
98
     * Date-time difference (`$x - $this`) in fractional days elapsed.
99
     *
100
     * @param null|DateTime $x Defaults to the current time.
101
     * @return Num
102
     */
103
    public function diffDays(DateTime $x = null)
104
    {
105
        return ($x ?? DateTime::now($this->db))->julian()->sub($this->julian());
106
    }
107
108
    /**
109
     * Date-time difference (`$x - $this`) in fractional hours elapsed.
110
     *
111
     * @param null|DateTime $x Defaults to the current time.
112
     * @return Num
113
     */
114
    public function diffHours(DateTime $x = null)
115
    {
116
        return $this->diffDays($x)->mul(24);
117
    }
118
119
    /**
120
     * Date-time difference (`$x - $this`) in fractional minutes elapsed.
121
     *
122
     * @param null|DateTime $x Defaults to the current time.
123
     * @return Num
124
     */
125
    public function diffMinutes(DateTime $x = null)
126
    {
127
        return $this->diffDays($x)->mul(24 * 60);
128
    }
129
130
    /**
131
     * Date-time difference (`$x - $this`) in fractional months elapsed.
132
     *
133
     * @param null|DateTime $x Defaults to the current time.
134
     * @return Num
135
     */
136
    public function diffMonths(DateTime $x = null)
137
    {
138
        return $this->diffDays($x)->div(365.2425 / 12);
139
    }
140
141
    /**
142
     * Date-time difference (`$x - $this`) in fractional seconds elapsed.
143
     *
144
     * @param null|DateTime $x Defaults to the current time.
145
     * @return Num
146
     */
147
    public function diffSeconds(DateTime $x = null)
148
    {
149
        return $this->diffDays($x)->mul(24 * 60 * 60);
150
    }
151
152
    /**
153
     * Date-time difference (`$x - $this`) in fractional years elapsed.
154
     *
155
     * @param null|DateTime $x Defaults to the current time.
156
     * @return Num
157
     */
158
    public function diffYears(DateTime $x = null)
159
    {
160
        return $this->diffDays($x)->div(365.2425);
161
    }
162
163
    /**
164
     * `00` to `23`
165
     *
166
     * @return Num
167
     */
168
    public function hours()
169
    {
170
        return Num::factory($this->db, $this->dateFormat('%H'));
171
    }
172
173
    /**
174
     * ISO-8601 compatible datetime string, offset `Z` (UTC/Zulu)
175
     *
176
     * https://en.wikipedia.org/wiki/ISO_8601
177
     *
178
     * @return Str
179
     */
180
    public function iso8601()
181
    {
182
        return $this->dateFormat([
183
            'mysql' => '%Y-%m-%dT%H:%i:%SZ',
184
            'sqlite' => '%Y-%m-%dT%H:%M:%SZ',
185
        ]);
186
    }
187
188
    /**
189
     * Julian day number (fractional).
190
     *
191
     * @return Num
192
     */
193
    public function julian()
194
    {
195
        return Num::fromFormat($this->db, [
196
            // mysql: julian "year zero" offset, plus number of fractional days since "year zero".
197
            'mysql' => "(1721059.5 + (TO_SECONDS(%s) / 86400))",
198
            'sqlite' => "JULIANDAY(%s)"
199
        ], $this);
200
    }
201
202
    /**
203
     * `00` to `59`
204
     *
205
     * @return Num
206
     */
207
    public function minutes()
208
    {
209
        return Num::factory($this->db, $this->dateFormat([
210
            'mysql' => '%i',
211
            'sqlite' => '%M'
212
        ]));
213
    }
214
215
    /**
216
     * `01` to `12`
217
     *
218
     * @return Num
219
     */
220
    public function month()
221
    {
222
        return Num::factory($this->db, $this->dateFormat('%m'));
223
    }
224
225
    /**
226
     * `00` to `59`
227
     *
228
     * @return Num
229
     */
230
    public function seconds()
231
    {
232
        return Num::factory($this->db, $this->dateFormat('%S'));
233
    }
234
235
    /**
236
     * `00:00:00` to `23:59:59`
237
     *
238
     * @return Str
239
     */
240
    public function time()
241
    {
242
        return $this->dateFormat([
243
            'mysql' => '%H:%i:%S',
244
            'sqlite' => '%H:%M:%S'
245
        ]);
246
    }
247
248
    /**
249
     * Unix timestamp.
250
     *
251
     * @return Num
252
     */
253
    public function timestamp()
254
    {
255
        return Num::fromFormat($this->db, [
256
            'mysql' => "UNIX_TIMESTAMP(%s)",
257
            'sqlite' => "STRFTIME('%%s',%s)",
258
        ], $this);
259
    }
260
261
    /**
262
     * `00` to `53`
263
     *
264
     * @return Num
265
     */
266
    public function weekOfYear()
267
    {
268
        return Num::factory($this->db, $this->dateFormat([
269
            'mysql' => '%U',
270
            'sqlite' => '%W'
271
        ]));
272
    }
273
274
    /**
275
     * `YYYY`
276
     *
277
     * @return Num
278
     */
279
    public function year()
280
    {
281
        return Num::factory($this->db, $this->dateFormat('%Y'));
282
    }
283
}
284