Passed
Push — master ( 99771f...15a419 )
by y
01:52
created

DateTimeTrait::timestamp()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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