Passed
Push — master ( 04902e...99771f )
by y
02:22
created

DateTimeTrait::toUtc()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 4
c 1
b 0
f 1
dl 0
loc 10
rs 10
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
     * `00` to `59`
93
     *
94
     * @return Num
95
     */
96
    public function minutes () {
97
        return Num::factory($this->db, $this->dateFormat([
98
            'mysql' => '%i',
99
            'sqlite' => '%M'
100
        ]));
101
    }
102
103
    /**
104
     * `01` to `12`
105
     *
106
     * @return Num
107
     */
108
    public function month () {
109
        return Num::factory($this->db, $this->dateFormat('%m'));
110
    }
111
112
    /**
113
     * `00` to `59`
114
     *
115
     * @return Num
116
     */
117
    public function seconds () {
118
        return Num::factory($this->db, $this->dateFormat('%S'));
119
    }
120
121
    /**
122
     * `00:00:00` to `23:59:59`
123
     *
124
     * @return Text
125
     */
126
    public function time () {
127
        return Text::factory($this->db, $this->dateFormat([
128
            'mysql' => '%H:%i:%S',
129
            'sqlite' => '%H:%M:%S'
130
        ]));
131
    }
132
133
    /**
134
     * Unix timestamp.
135
     *
136
     * @return Num
137
     */
138
    public function timestamp () {
139
        if ($this->db->isSQLite()) {
140
            return Num::factory($this->db, "STRFTIME('%s',{$this})");
141
        }
142
        return Num::factory($this->db, "UNIX_TIMESTAMP({$this})");
143
    }
144
145
    /**
146
     * Changes the timezone from UTC to the local timezone.
147
     *
148
     * - SQLite: Uses the operating system's timezone.
149
     * - MySQL: Uses PHP's timezone.
150
     *
151
     * > Warning: Chaining this multiple times will further change the timezone offset.
152
     *
153
     * @return DateTime
154
     */
155
    public function toLocalTz () {
156
        if ($this->db->isSQLite()) {
157
            // docs:
158
            // > The "localtime" modifier (12) assumes the time value to its left is in
159
            // > Universal Coordinated Time (UTC) and adjusts that time value so that it is in localtime.
160
            // > If "localtime" follows a time that is not UTC, then the behavior is undefined.
161
            return DateTime::factory($this->db, "DATETIME({$this},'localtime')");
162
        }
163
        $local = date_default_timezone_get();
164
        return DateTime::factory($this->db, "CONVERT_TZ({$this},'UTC','{$local}')");
165
    }
166
167
    /**
168
     * Changes the timezone from the local timezone to UTC.
169
     *
170
     * > Warning: Datetimes are already stored and retrieved as UTC.
171
     * > Only use this if you know the expression is in the local timezone.
172
     *
173
     * > Warning: Chaining this multiple times will further change the timezone offset.
174
     *
175
     * @return DateTime
176
     */
177
    public function toUtc () {
178
        if ($this->db->isSQLite()) {
179
            // docs:
180
            // > "utc" assumes that the time value to its left is in the local timezone
181
            // > and adjusts that time value to be in UTC. If the time to the left is not in localtime,
182
            // > then the result of "utc" is undefined.
183
            return DateTime::factory($this->db, "DATETIME({$this},'utc')");
184
        }
185
        $local = date_default_timezone_get();
186
        return DateTime::factory($this->db, "CONVERT_TZ({$this},'{$local}','UTC')");
187
    }
188
189
    /**
190
     * `00` to `53`
191
     *
192
     * @return Num
193
     */
194
    public function weekOfYear () {
195
        return Num::factory($this->db, $this->dateFormat([
196
            'mysql' => '%U',
197
            'sqlite' => '%W'
198
        ]));
199
    }
200
201
    /**
202
     * `YYYY`
203
     *
204
     * @return Num
205
     */
206
    public function year () {
207
        return Num::factory($this->db, $this->dateFormat('%Y'));
208
    }
209
}