Completed
Push — master ( bef2f6...6b39f8 )
by Tim
02:02
created

DateTimeUtility::normalizeDateTimeSingle()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 8.8337
c 0
b 0
f 0
ccs 0
cts 0
cp 0
cc 6
nc 5
nop 2
crap 42
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
     * Sets the time seconds on the given date.
133
     *
134
     * @param \DateTime $date
135
     * @param int       $seconds
136
     *
137
     * @return \DateTime
138
     */
139
    public static function setSecondsOfDateTime(\DateTime $date, int $seconds): \DateTime
140
    {
141
        $date = clone $date;
142
        $date->setTime(0, 0, 0);
143
        $date->modify("+$seconds seconds");
144
145 2
        return $date;
146
    }
147 2
148 2
    /**
149 2
     * Get a normalize date time object.
150
     *
151 2
     * @param int|null $day
152
     * @param int|null $month
153
     * @param int|null $year
154 2
     *
155
     * @return \DateTime
156
     */
157
    public static function normalizeDateTime($day = null, $month = null, $year = null): \DateTime
158
    {
159
        $date = self::getNow();
160
        // Check if this date should handle always in UTC
161
        // $date->setTimezone(self::getUtcTimeZone());
162
        if (!MathUtility::canBeInterpretedAsInteger($year)) {
163
            $year = $date->format('Y');
164
        }
165
        if (!MathUtility::canBeInterpretedAsInteger($month)) {
166
            $month = $date->format('m');
167
        }
168
        if (!MathUtility::canBeInterpretedAsInteger($day)) {
169
            $day = $date->format('d');
170
        }
171
        $date->setDate((int)$year, (int)$month, (int)$day);
172
        $date->setTime(0, 0, 0);
173
        if ($date->format('m') > $month) {
174
            $date->modify('last day of last month');
175
        } elseif ($date->format('m') < $month) {
176
            $date->modify('first day of next month');
177
        }
178
179
        return $date;
180
    }
181
182
    /**
183
     * Normalize quartar.
184
     *
185
     * @param int|null $quarter
186
     *
187
     * @return int
188
     */
189
    public static function normalizeQuarter(int $quarter = null): int
190
    {
191
        if (null === $quarter) {
192
            $quarter = self::getQuartar(self::getNow());
193
        }
194
195
        return MathUtility::forceIntegerInRange((int)$quarter, 1, 4);
196
    }
197
198
    /**
199
     * Normalize quartar.
200
     *
201
     * @param \DateTimeInterface $date
202
     *
203
     * @return int
204
     */
205
    public static function getQuartar(\DateTimeInterface $date): int
206
    {
207
        $month = (int)$date->format('n');
208
209
        return (int)ceil($month / 3);
210
    }
211
212
    /**
213
     * Reset the DateTime.
214
     *
215
     * @param int|string|\DateTimeInterface|null $dateTime
216
     *
217
     * @return \DateTime
218
     */
219
    public static function resetTime($dateTime = null): \DateTime
220
    {
221
        $dateTime = self::normalizeDateTimeSingle($dateTime);
222
        $dateTime->setTime(0, 0, 0);
223
224
        return $dateTime;
225
    }
226
227
    /**
228
     * Get a normalized date time object in a specific timezone.
229
     *
230
     * @param int|string|\DateTimeInterface|null $dateInformation
231
     * @param \DateTimeZone|null                 $timezone        Timezone to normalize to. Defaults to the self::getTimeZone().
232
     *
233
     * @return \DateTime
234
     *
235
     * @throws \Exception
236
     */
237
    public static function normalizeDateTimeSingle($dateInformation = null, \DateTimeZone $timezone = null): \DateTime
238
    {
239
        $timezone = $timezone ?? self::getTimeZone();
240
        $date = self::getNow();
241
242
        if ($dateInformation instanceof \DateTimeInterface) {
243
            // Convert DateTimeInterface to a DateTime object
244
            $date = \DateTime::createFromFormat(
245
                \DateTimeInterface::ATOM,
246
                $dateInformation->format(\DateTimeInterface::ATOM),
247
                $timezone
248
            );
249
        } elseif (MathUtility::canBeInterpretedAsInteger($dateInformation)) {
250
            // http://php.net/manual/en/datetime.construct#refsect1-datetime.construct-parameters :
251
            // The $timezone parameter and the current timezone are ignored [ie. set to UTC] when the $time parameter [...] is a UNIX timestamp (e.g. @946684800) [...]
252
            $date = new \DateTime("@$dateInformation");
253
        } elseif (\is_string($dateInformation) && in_array($dateInformation[0], ['-', '+'])) {
254
            $date = self::getNow();
255
            $date->modify($dateInformation);
256
        } elseif (\is_string($dateInformation)) {
257
            // Add timezone explicitly here, so that it does not depend on the "current timezone".
258
            $date = new \DateTime($dateInformation, $timezone);
259
        }
260
261
        // Change timezone
262
        $date->setTimezone($timezone);
263
264
        return $date;
265
    }
266
267
    /**
268
     * Get the current date (normalized optimized for queries, because SIM_ACCESS_TIME is rounded to minutes)
269
     * in the current timezone.
270
     *
271
     * @return \DateTime
272
     */
273
    public static function getNow(): \DateTime
274
    {
275
        // NOTE that new \DateTime('@timestamp') does NOT work - @see comment in normalizeDateTimeSingle()
276
        // So we create a date string with timezone information first, and a \DateTime in the current server timezone then.
277
        return new \DateTime(date(\DateTime::ATOM, (int)$GLOBALS['SIM_ACCESS_TIME']), self::getTimeZone());
278
    }
279
280
    /**
281
     * Alias for resetTime.
282
     *
283
     * @see resetTime()
284
     *
285
     * @param int|string|\DateTimeInterface|null $dateInformation
286
     *
287
     * @return \DateTime
288
     */
289
    public static function getDayStart($dateInformation): \DateTime
290
    {
291
        return self::resetTime($dateInformation);
292
    }
293
294
    /**
295
     * Get the End of the given day.
296
     *
297
     * @param int|string|\DateTimeInterface|null $dateInformation
298
     *
299
     * @return \DateTime
300
     */
301
    public static function getDayEnd($dateInformation): \DateTime
302
    {
303
        $dateTime = self::getDayStart($dateInformation);
304
        $dateTime->setTime(23, 59, 59);
305
306
        return $dateTime;
307
    }
308
309
    /**
310
     * Converts DateTime objects for native dates, so that they are stored "as is".
311
     * This is required for Typo3 versions before 11, since they are formatted in UTC, but shouldn't.
312
     *
313
     * @param \DateTime|null $date
314
     *
315
     * @return \DateTime|null
316
     */
317
    public static function fixDateTimeForDb(?\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 = new \DateTime($date->format('Y-m-d\TH:i:s'), self::getUtcTimeZone());
323
            }
324
        }
325
326
        return $date;
327
    }
328
329
    /**
330
     * Converts the native date object from UTC to the local timezone.
331
     * This is required for Typo3 versions before 11, since the dates in the db are assumed as UTC, but aren't.
332
     *
333
     * @param \DateTime|null $date
334
     *
335
     * @return \DateTime|null
336
     */
337
    public static function fixDateTimeForExtbase(?\DateTime $date): ?\DateTime
338
    {
339
        if ($date instanceof \DateTimeInterface) {
340
            $typo3Version = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Information\Typo3Version::class);
341
            if ($typo3Version->getMajorVersion() < 11) {
342
                $date = (clone $date)->setTimezone(self::getUtcTimeZone());
343
                $date = new \DateTime($date->format('Y-m-d\TH:i:s'), self::getTimeZone());
344
            }
345
        }
346
347
        return $date;
348
    }
349
}
350