Passed
Push — master ( 222f48...0fa176 )
by y
01:47
created

DateTimeTrait::datetime()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
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\Text;
8
use Helix\DB\Fluent\Value\ValueTrait;
9
10
/**
11
 * Produces datetime related expressions for the instance.
12
 *
13
 * Each DBMS has its own quirks with dates, which is beyond the scope of this library.
14
 *
15
 * @see https://sqlite.org/lang_datefunc.html
16
 * @see https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format
17
 */
18
trait DateTimeTrait {
19
20
    use ValueTrait;
21
22
    /**
23
     * `YYYY-MM-DD`
24
     *
25
     * @return Text
26
     */
27
    public function date () {
28
        return $this->dateFormat('%Y-%m-%d');
29
    }
30
31
    /**
32
     * Date formatting expression using a driver-appropriate function.
33
     *
34
     * @param string|string[] $format Format, or formats keyed by driver name.
35
     * @return Text
36
     */
37
    public function dateFormat ($format) {
38
        if (is_array($format)) {
39
            $format = $format[$this->db->getDriver()];
40
        }
41
        $format = $this->db->quote($format);
42
        if ($this->db->isSQLite()) {
43
            return Text::factory($this->db, "STRFTIME({$format},{$this})");
44
        }
45
        return Text::factory($this->db, "DATE_FORMAT({$this},{$format})");
46
    }
47
48
    /**
49
     * `YYYY-MM-DD hh:mm:ss`
50
     *
51
     * @return Text
52
     */
53
    public function datetime () {
54
        return $this->dateFormat([
55
            'mysql' => '%Y-%m-%d %H:%i:%S',
56
            'sqlite' => '%Y-%m-%d %H:%M:%S'
57
        ]);
58
    }
59
60
    /**
61
     * `01` to `31`
62
     *
63
     * @return Num
64
     */
65
    public function day () {
66
        return Num::factory($this->db, $this->dateFormat('%d'));
67
    }
68
69
    /**
70
     * `0` to `6` (Sunday is `0`)
71
     *
72
     * @return Num
73
     */
74
    public function dayOfWeek () {
75
        return Num::factory($this->db, $this->dateFormat('%w'));
76
    }
77
78
    /**
79
     * `001` to `366` (365 + 1 during leap year)
80
     *
81
     * @return Num
82
     */
83
    public function dayOfYear () {
84
        return Num::factory($this->db, $this->dateFormat('%j'));
85
    }
86
87
    /**
88
     * `00` to `23`
89
     *
90
     * @return Num
91
     */
92
    public function hours () {
93
        return Num::factory($this->db, $this->dateFormat('%H'));
94
    }
95
96
    /**
97
     * ISO-8601 compatible datetime string, offset `Z` (UTC/Zulu)
98
     *
99
     * https://en.wikipedia.org/wiki/ISO_8601
100
     *
101
     * @return Text
102
     */
103
    public function iso8601 () {
104
        return $this->dateFormat([
105
            'mysql' => '%Y-%m-%dT%H:%i:%SZ',
106
            'sqlite' => '%Y-%m-%dT%H:%M:%SZ',
107
        ]);
108
    }
109
110
    /**
111
     * `00` to `59`
112
     *
113
     * @return Num
114
     */
115
    public function minutes () {
116
        return Num::factory($this->db, $this->dateFormat([
117
            'mysql' => '%i',
118
            'sqlite' => '%M'
119
        ]));
120
    }
121
122
    /**
123
     * `01` to `12`
124
     *
125
     * @return Num
126
     */
127
    public function month () {
128
        return Num::factory($this->db, $this->dateFormat('%m'));
129
    }
130
131
    /**
132
     * `00` to `59`
133
     *
134
     * @return Num
135
     */
136
    public function seconds () {
137
        return Num::factory($this->db, $this->dateFormat('%S'));
138
    }
139
140
    /**
141
     * `00:00:00` to `23:59:59`
142
     *
143
     * @return Text
144
     */
145
    public function time () {
146
        return $this->dateFormat([
147
            'mysql' => '%H:%i:%S',
148
            'sqlite' => '%H:%M:%S'
149
        ]);
150
    }
151
152
    /**
153
     * Unix timestamp.
154
     *
155
     * @return Num
156
     */
157
    public function timestamp () {
158
        if ($this->db->isSQLite()) {
159
            return Num::factory($this->db, "STRFTIME('%s',{$this})");
160
        }
161
        return Num::factory($this->db, "UNIX_TIMESTAMP({$this})");
162
    }
163
164
    /**
165
     * Changes the timezone from UTC to the local timezone.
166
     *
167
     * - SQLite: Uses the operating system's timezone.
168
     * - MySQL: Uses PHP's timezone.
169
     *
170
     * > Warning: Chaining this multiple times will further change the timezone offset.
171
     *
172
     * @return DateTime
173
     */
174
    public function toLocalTz () {
175
        if ($this->db->isSQLite()) {
176
            // docs:
177
            // > The "localtime" modifier (12) assumes the time value to its left is in
178
            // > Universal Coordinated Time (UTC) and adjusts that time value so that it is in localtime.
179
            // > If "localtime" follows a time that is not UTC, then the behavior is undefined.
180
            return DateTime::factory($this->db, "DATETIME({$this},'localtime')");
181
        }
182
        $local = date_default_timezone_get();
183
        return DateTime::factory($this->db, "CONVERT_TZ({$this},'UTC','{$local}')");
184
    }
185
186
    /**
187
     * Changes the timezone from the local timezone to UTC.
188
     *
189
     * > Warning: Datetimes are already stored and retrieved as UTC.
190
     * > Only use this if you know the expression is in the local timezone.
191
     *
192
     * > Warning: Chaining this multiple times will further change the timezone offset.
193
     *
194
     * @return DateTime
195
     */
196
    public function toUtc () {
197
        if ($this->db->isSQLite()) {
198
            // docs:
199
            // > "utc" assumes that the time value to its left is in the local timezone
200
            // > and adjusts that time value to be in UTC. If the time to the left is not in localtime,
201
            // > then the result of "utc" is undefined.
202
            return DateTime::factory($this->db, "DATETIME({$this},'utc')");
203
        }
204
        $local = date_default_timezone_get();
205
        return DateTime::factory($this->db, "CONVERT_TZ({$this},'{$local}','UTC')");
206
    }
207
208
    /**
209
     * `00` to `53`
210
     *
211
     * @return Num
212
     */
213
    public function weekOfYear () {
214
        return Num::factory($this->db, $this->dateFormat([
215
            'mysql' => '%U',
216
            'sqlite' => '%W'
217
        ]));
218
    }
219
220
    /**
221
     * `YYYY`
222
     *
223
     * @return Num
224
     */
225
    public function year () {
226
        return Num::factory($this->db, $this->dateFormat('%Y'));
227
    }
228
}
229