Completed
Push — master ( 2e1b8b...20d39e )
by Tim
26s queued 10s
created

DateTimeUtility::fixDateTimeForDb()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
ccs 0
cts 0
cp 0
cc 3
nc 3
nop 1
crap 12
1
<?php
2
3
/**
4
 * DateTime Utility.
5
 */
6
declare(strict_types=1);
7
8
namespace HDNET\Calendarize\Utility;
9
10
use TYPO3\CMS\Core\Utility\MathUtility;
11
12
/**
13
 * DateTime Utility.
14
 */
15
class DateTimeUtility
16
{
17
    /**
18
     * One second.
19
     */
20
    const SECONDS_SECOND = 1;
21
22
    /**
23
     * One minute in seconds.
24
     */
25
    const SECONDS_MINUTE = 60;
26
27
    /**
28
     * One hour in seconds.
29
     */
30
    const SECONDS_HOUR = 3600;
31
32
    /**
33
     * One day in seconds.
34
     */
35
    const SECONDS_DAY = 86400;
36
37
    /**
38
     * One week in seconds.
39
     */
40
    const SECONDS_WEEK = 604800;
41
42
    /**
43
     * One quartar in seconds (90 days).
44
     */
45
    const SECONDS_QUARTER = 7776000;
46
47
    /**
48
     * One year in seconds (365 days).
49
     */
50
    const SECONDS_YEAR = 31536000;
51
52
    /**
53
     * One decade in seconds (base on a 365 days year).
54
     */
55
    const SECONDS_DECADE = 315360000;
56
57
    /**
58
     * Format date (Backend).
59
     */
60
    const FORMAT_DATE_BACKEND = '%a %d.%m.%Y';
61
62
    /**
63
     * Convert a Week/Year combination to a DateTime of the first day of week.
64
     *
65
     * @param int $week
66
     * @param int $year
67
     * @param int $startDay
68
     *
69
     * @return \DateTime
70
     */
71
    public static function convertWeekYear2DayMonthYear($week, $year, $startDay = 1): \DateTime
72
    {
73
        $date = self::getNow();
74 2
        $date->setTime(0, 0, 0);
75
        $date->setISODate($year, $week, $startDay);
76 2
77
        return $date;
78
    }
79
80
    /**
81
     * Time zone is set by the TYPO3 core.
82
     *
83
     * @return \DateTimeZone
84
     *
85
     * @see \TYPO3\CMS\Core\Core\Bootstrap->setDefaultTimezone()
86
     */
87
    public static function getTimeZone()
88
    {
89
        return new \DateTimeZone(date_default_timezone_get());
90
    }
91
92
    /**
93
     * Time zone that is always UTC.
94
     *
95
     * @return \DateTimeZone
96
     */
97
    public static function getUtcTimeZone()
98
    {
99
        return new \DateTimeZone('UTC');
100
    }
101
102
    /**
103
     * Get the time seconds of the given date (TYPO3 Backend style).
104
     *
105
     * @param \DateTimeInterface $dateTime
106
     *
107
     * @return int
108
     */
109
    public static function getDaySecondsOfDateTime(\DateTimeInterface $dateTime): int
110
    {
111
        $hours = (int)$dateTime->format('G');
112
        $minutes = $hours * self::SECONDS_MINUTE + (int)$dateTime->format('i');
113
114
        return $minutes * self::SECONDS_MINUTE + (int)$dateTime->format('s');
115
    }
116
117
    /**
118
     * Get the time seconds of the given date (TYPO3 Backend style) in the server timezone.
119
     *
120
     * @param \DateTimeInterface $dateTime
121
     *
122
     * @return int
123
     */
124
    public static function getNormalizedDaySecondsOfDateTime(\DateTimeInterface $dateTime): int
125
    {
126
        $date = self::normalizeDateTimeSingle($dateTime);
127
128
        return self::getDaySecondsOfDateTime($date);
129
    }
130
131
    /**
132
     * Get a normalize date time object.
133
     *
134
     * @param int|null $day
135
     * @param int|null $month
136
     * @param int|null $year
137
     *
138
     * @return \DateTime
139
     */
140
    public static function normalizeDateTime($day = null, $month = null, $year = null): \DateTime
141
    {
142
        $date = self::getNow();
143
        // Check if this date should handle always in UTC
144
        // $date->setTimezone(self::getUtcTimeZone());
145 2
        if (!MathUtility::canBeInterpretedAsInteger($year)) {
146
            $year = $date->format('Y');
147 2
        }
148 2
        if (!MathUtility::canBeInterpretedAsInteger($month)) {
149 2
            $month = $date->format('m');
150
        }
151 2
        if (!MathUtility::canBeInterpretedAsInteger($day)) {
152
            $day = $date->format('d');
153
        }
154 2
        $date->setDate((int)$year, (int)$month, (int)$day);
155
        $date->setTime(0, 0, 0);
156
        if ($date->format('m') > $month) {
157
            $date->modify('last day of last month');
158
        } elseif ($date->format('m') < $month) {
159
            $date->modify('first day of next month');
160
        }
161
162
        return $date;
163
    }
164
165
    /**
166
     * Normalize quartar.
167
     *
168
     * @param int|null $quarter
169
     *
170
     * @return int
171
     */
172
    public static function normalizeQuarter(int $quarter = null): int
173
    {
174
        if (null === $quarter) {
175
            $quarter = self::getQuartar(self::getNow());
176
        }
177
178
        return MathUtility::forceIntegerInRange((int)$quarter, 1, 4);
179
    }
180
181
    /**
182
     * Normalize quartar.
183
     *
184
     * @param \DateTimeInterface $date
185
     *
186
     * @return int
187
     */
188
    public static function getQuartar(\DateTimeInterface $date): int
189
    {
190
        $month = (int)$date->format('n');
191
192
        return (int)ceil($month / 3);
193
    }
194
195
    /**
196
     * Reset the DateTime.
197
     *
198
     * @param int|string|\DateTimeInterface|null $dateTime
199
     *
200
     * @return \DateTime
201
     */
202
    public static function resetTime($dateTime = null): \DateTime
203
    {
204
        $dateTime = self::normalizeDateTimeSingle($dateTime);
205
        $dateTime->setTime(0, 0, 0);
206
207
        return $dateTime;
208
    }
209
210
    /**
211
     * Get a normalized date time object in a specific timezone.
212
     *
213
     * @param int|string|\DateTimeInterface|null $dateInformation
214
     * @param \DateTimeZone|null                 $timezone        Timezone to normalize to. Defaults to the self::getTimeZone().
215
     *
216
     * @return \DateTime
217
     *
218
     * @throws \Exception
219
     */
220
    public static function normalizeDateTimeSingle($dateInformation = null, \DateTimeZone $timezone = null): \DateTime
221
    {
222
        $timezone = $timezone ?? self::getTimeZone();
223
        $date = self::getNow();
224
225
        if ($dateInformation instanceof \DateTimeInterface) {
226
            // Convert DateTimeInterface to a DateTime object
227
            $date = \DateTime::createFromFormat(
228
                \DateTimeInterface::ATOM,
229
                $dateInformation->format(\DateTimeInterface::ATOM),
230
                $timezone
231
            );
232
        } elseif (MathUtility::canBeInterpretedAsInteger($dateInformation)) {
233
            // http://php.net/manual/en/datetime.construct#refsect1-datetime.construct-parameters :
234
            // The $timezone parameter and the current timezone are ignored [ie. set to UTC] when the $time parameter [...] is a UNIX timestamp (e.g. @946684800) [...]
235
            $date = new \DateTime("@$dateInformation");
236
        } elseif (\is_string($dateInformation)) {
237
            // Add timezone explicitly here, so that it does not depend on the "current timezone".
238
            $date = new \DateTime($dateInformation, $timezone);
239
        }
240
241
        // Change timezone
242
        $date->setTimezone($timezone);
243
244
        return $date;
245
    }
246
247
    /**
248
     * Get the current date (normalized optimized for queries, because SIM_ACCESS_TIME is rounded to minutes)
249
     * in the current timezone.
250
     *
251
     * @return \DateTime
252
     */
253
    public static function getNow(): \DateTime
254
    {
255
        // NOTE that new \DateTime('@timestamp') does NOT work - @see comment in normalizeDateTimeSingle()
256
        // So we create a date string with timezone information first, and a \DateTime in the current server timezone then.
257
        return new \DateTime(date(\DateTime::ATOM, (int)$GLOBALS['SIM_ACCESS_TIME']), self::getTimeZone());
258
    }
259
260
    /**
261
     * Alias for resetTime.
262
     *
263
     * @see resetTime()
264
     *
265
     * @param int|string|\DateTimeInterface|null $dateInformation
266
     *
267
     * @return \DateTime
268
     */
269
    public static function getDayStart($dateInformation): \DateTime
270
    {
271
        return self::resetTime($dateInformation);
272
    }
273
274
    /**
275
     * Get the End of the given day.
276
     *
277
     * @param int|string|\DateTimeInterface|null $dateInformation
278
     *
279
     * @return \DateTime
280
     */
281
    public static function getDayEnd($dateInformation): \DateTime
282
    {
283
        $dateTime = self::getDayStart($dateInformation);
284
        $dateTime->setTime(23, 59, 59);
285
286
        return $dateTime;
287
    }
288
289
    /**
290
     * Converts DateTime objects for native dates, so that they are stored "as is".
291
     * This is required for Typo3 versions before 11, since they are formatted in UTC, but shouldn't.
292
     *
293
     * @param \DateTime|null $date
294
     *
295
     * @return \DateTime|null
296
     */
297
    public static function fixDateTimeForDb(?\DateTime $date): ?\DateTime
298
    {
299
        if ($date instanceof \DateTimeInterface) {
300
            $typo3Version = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Information\Typo3Version::class);
301
            if ($typo3Version->getMajorVersion() < 11) {
302
                $date = new \DateTime($date->format('Y-m-d\TH:i:s'), self::getUtcTimeZone());
303
            }
304
        }
305
306
        return $date;
307
    }
308
309
    /**
310
     * Converts the native date object from UTC to the local timezone.
311
     * This is required for Typo3 versions before 11, since the dates in the db are assumed as UTC, but aren't.
312
     *
313
     * @param \DateTime|null $date
314
     *
315
     * @return \DateTime|null
316
     */
317
    public static function fixDateTimeForExtbase(?\DateTime $date): ?\DateTime
318
    {
319
        if ($date instanceof \DateTimeInterface) {
320
            $typo3Version = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Information\Typo3Version::class);
321
            if ($typo3Version->getMajorVersion() < 11) {
322
                $date = (clone $date)->setTimezone(self::getUtcTimeZone());
323
                $date = new \DateTime($date->format('Y-m-d\TH:i:s'), self::getTimeZone());
324
            }
325
        }
326
327
        return $date;
328
    }
329
}
330