• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tempestphp / tempest-framework / 14639629920

24 Apr 2025 10:41AM UTC coverage: 80.923%. First build
14639629920

Pull #1158

github

web-flow
Merge 11a3af0ac into 06be1af98
Pull Request #1158: feat(datetime): add datetime component

1099 of 1227 new or added lines in 39 files covered. (89.57%)

12849 of 15878 relevant lines covered (80.92%)

100.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.43
/src/Tempest/DateTime/src/TemporalConvenienceMethods.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\DateTime;
6

7
use DateTimeImmutable as NativeDateTimeImmutable;
8
use DateTimeInterface as NativeDateTimeInterface;
9
use Tempest\Support\Comparison;
10
use Tempest\Support\Comparison\Order;
11
use Tempest\Support\Language\Locale;
12

13
/**
14
 * @require-implements TemporalInterface
15
 */
16
trait TemporalConvenienceMethods
17
{
18
    /**
19
     * Returns a native {@see DateTimeInterface} instance for this {@see TemporalInterface} object.
20
     */
21
    public function toNativeDateTime(): NativeDateTimeInterface
4✔
22
    {
23
        return NativeDateTimeImmutable::createFromTimestamp($this->getTimestamp()->getSeconds());
4✔
24
    }
25

26
    /**
27
     * Compare this {@see TemporalInterface} object to the given one.
28
     *
29
     * @param TemporalInterface $other
30
     */
31
    public function compare(mixed $other): Order
10✔
32
    {
33
        $a = $this->getTimestamp()->toParts();
10✔
34
        $b = $other->getTimestamp()->toParts();
10✔
35

36
        return Comparison\Order::from($a[0] !== $b[0] ? $a[0] <=> $b[0] : $a[1] <=> $b[1]);
10✔
37
    }
38

39
    /**
40
     * Checks if this {@see TemporalInterface} object represents the same time as the given one.
41
     *
42
     * Note: this method is an alias for {@see TemporalInterface::atTheSameTime()}.
43
     *
44
     * @param TemporalInterface|string $other
45
     */
46
    public function equals(mixed $other): bool
8✔
47
    {
48
        return $this->atTheSameTime($other);
8✔
49
    }
50

51
    /**
52
     * Checks if this temporal object represents the same time as the given one.
53
     *
54
     * Note: this method is an alias for {@see TemporalInterface::equals()}.
55
     */
56
    public function atTheSameTime(TemporalInterface|string $other): bool
8✔
57
    {
58
        if (is_string($other)) {
8✔
59
            $other = DateTime::parse($other);
1✔
60
        }
61

62
        return $this->compare($other) === Comparison\Order::EQUAL;
8✔
63
    }
64

65
    /**
66
     * Checks if this temporal object is before the given one.
67
     */
68
    public function before(TemporalInterface $other): bool
8✔
69
    {
70
        return $this->compare($other) === Comparison\Order::LESS;
8✔
71
    }
72

73
    /**
74
     * Checks if this temporal object is before or at the same time as the given one.
75
     */
76
    public function beforeOrAtTheSameTime(TemporalInterface $other): bool
6✔
77
    {
78
        return $this->compare($other) !== Comparison\Order::GREATER;
6✔
79
    }
80

81
    /**
82
     * Checks if this temporal object is after the given one.
83
     */
84
    public function after(TemporalInterface $other): bool
6✔
85
    {
86
        return $this->compare($other) === Comparison\Order::GREATER;
6✔
87
    }
88

89
    /**
90
     * Checks if this temporal object is after or at the same time as the given one.
91
     */
92
    public function afterOrAtTheSameTime(TemporalInterface $other): bool
6✔
93
    {
94
        return $this->compare($other) !== Comparison\Order::LESS;
6✔
95
    }
96

97
    /**
98
     * Checks if this temporal object is between the given times (inclusive).
99
     */
100
    public function betweenTimeInclusive(TemporalInterface $a, TemporalInterface $b): bool
6✔
101
    {
102
        $ca = $this->compare($a);
6✔
103
        $cb = $this->compare($b);
6✔
104

105
        return $ca === Comparison\Order::EQUAL || $ca !== $cb;
6✔
106
    }
107

108
    /**
109
     * Checks if this temporal object is between the given times (exclusive).
110
     */
111
    public function betweenTimeExclusive(TemporalInterface $a, TemporalInterface $b): bool
6✔
112
    {
113
        $ca = $this->compare($a);
6✔
114
        $cb = $this->compare($b);
6✔
115

116
        return $ca !== Comparison\Order::EQUAL && $cb !== Comparison\Order::EQUAL && $ca !== $cb;
6✔
117
    }
118

119
    /**
120
     * Adds the specified hours to this temporal object, returning a new instance with the added hours.
121
     *
122
     * @throws Exception\UnderflowException If adding the hours results in an arithmetic underflow.
123
     * @throws Exception\OverflowException If adding the hours results in an arithmetic overflow.
124
     */
125
    public function plusHours(int $hours): static
2✔
126
    {
127
        return $this->plus(Duration::hours($hours));
2✔
128
    }
129

130
    /**
131
     * Adds the specified minutes to this temporal object, returning a new instance with the added minutes.
132
     *
133
     * @throws Exception\UnderflowException If adding the minutes results in an arithmetic underflow.
134
     * @throws Exception\OverflowException If adding the minutes results in an arithmetic overflow.
135
     */
136
    public function plusMinutes(int $minutes): static
2✔
137
    {
138
        return $this->plus(Duration::minutes($minutes));
2✔
139
    }
140

141
    /**
142
     * Adds the specified seconds to this temporal object, returning a new instance with the added seconds.
143
     *
144
     * @throws Exception\UnderflowException If adding the seconds results in an arithmetic underflow.
145
     * @throws Exception\OverflowException If adding the seconds results in an arithmetic overflow.
146
     */
147
    public function plusSeconds(int $seconds): static
64✔
148
    {
149
        return $this->plus(Duration::seconds($seconds));
64✔
150
    }
151

152
    /**
153
     * Adds the specified milliseconds to this temporal object, returning a new instance with the added milliseconds.
154
     *
155
     * @throws Exception\UnderflowException If adding the milliseconds results in an arithmetic underflow.
156
     * @throws Exception\OverflowException If adding the milliseconds results in an arithmetic overflow.
157
     */
158
    public function plusMilliseconds(int $milliseconds): static
2✔
159
    {
160
        return $this->plus(Duration::milliseconds($milliseconds));
2✔
161
    }
162

163
    /**
164
     * Adds the specified nanoseconds to this temporal object, returning a new instance with the added nanoseconds.
165
     *
166
     * @throws Exception\UnderflowException If adding the nanoseconds results in an arithmetic underflow.
167
     * @throws Exception\OverflowException If adding the nanoseconds results in an arithmetic overflow.
168
     */
169
    public function plusNanoseconds(int $nanoseconds): static
2✔
170
    {
171
        return $this->plus(Duration::nanoseconds($nanoseconds));
2✔
172
    }
173

174
    /**
175
     * Subtracts the specified hours from this temporal object, returning a new instance with the subtracted hours.
176
     *
177
     * @throws Exception\UnderflowException If subtracting the hours results in an arithmetic underflow.
178
     * @throws Exception\OverflowException If subtracting the hours results in an arithmetic overflow.
179
     */
180
    public function minusHours(int $hours): static
2✔
181
    {
182
        return $this->minus(Duration::hours($hours));
2✔
183
    }
184

185
    /**
186
     * Subtracts the specified minutes from this temporal object, returning a new instance with the subtracted minutes.
187
     *
188
     * @throws Exception\UnderflowException If subtracting the minutes results in an arithmetic underflow.
189
     * @throws Exception\OverflowException If subtracting the minutes results in an arithmetic overflow.
190
     */
191
    public function minusMinutes(int $minutes): static
2✔
192
    {
193
        return $this->minus(Duration::minutes($minutes));
2✔
194
    }
195

196
    /**
197
     * Subtracts the specified seconds from this temporal object, returning a new instance with the subtracted seconds.
198
     *
199
     * @throws Exception\UnderflowException If subtracting the seconds results in an arithmetic underflow.
200
     * @throws Exception\OverflowException If subtracting the seconds results in an arithmetic overflow.
201
     */
202
    public function minusSeconds(int $seconds): static
3✔
203
    {
204
        return $this->minus(Duration::seconds($seconds));
3✔
205
    }
206

207
    /**
208
     * Subtracts the specified milliseconds from this temporal object, returning a new instance with the subtracted milliseconds.
209
     *
210
     * @throws Exception\UnderflowException If subtracting the milliseconds results in an arithmetic underflow.
211
     * @throws Exception\OverflowException If subtracting the milliseconds results in an arithmetic overflow.
212
     */
NEW
213
    public function minusMilliseconds(int $milliseconds): static
×
214
    {
NEW
215
        return $this->minus(Duration::milliseconds($milliseconds));
×
216
    }
217

218
    /**
219
     * Subtracts the specified nanoseconds from this temporal object, returning a new instance with the subtracted nanoseconds.
220
     *
221
     * @throws Exception\UnderflowException If subtracting the nanoseconds results in an arithmetic underflow.
222
     * @throws Exception\OverflowException If subtracting the nanoseconds results in an arithmetic overflow.
223
     */
224
    public function minusNanoseconds(int $nanoseconds): static
2✔
225
    {
226
        return $this->minus(Duration::nanoseconds($nanoseconds));
2✔
227
    }
228

229
    /**
230
     * Calculates the duration between this temporal object and the given one.
231
     *
232
     * @param TemporalInterface $other The temporal object to calculate the duration to.
233
     *
234
     * @return Duration The duration between the two temporal objects.
235
     */
236
    public function since(TemporalInterface $other): Duration
1✔
237
    {
238
        $a = $this->getTimestamp()->toParts();
1✔
239
        $b = $other->getTimestamp()->toParts();
1✔
240

241
        return Duration::fromParts(0, 0, $a[0] - $b[0], $a[1] - $b[1]);
1✔
242
    }
243

244
    /**
245
     * Converts the current temporal object to a new {@see DateTimeInterface} instance in a different timezone.
246
     *
247
     * @param null|Timezone $timezone The target timezone for the conversion.
248
     */
249
    public function convertToTimezone(?Timezone $timezone): DateTimeInterface
1✔
250
    {
251
        return DateTime::fromTimestamp($this->getTimestamp(), $timezone);
1✔
252
    }
253

254
    /**
255
     * Formats this {@see TemporalInterface} instance based on a specific pattern, with optional customization for timezone and locale.
256
     *
257
     * This method allows for detailed customization of the output string by specifying a format pattern. If no pattern is provided,
258
     * a default, implementation-specific pattern will be used. Additionally, the method supports specifying a timezone and locale
259
     * for further customization of the formatted output. If these are not provided, system defaults will be used.
260
     *
261
     * Example usage:
262
     *
263
     * ```php
264
     * $formatted = $temporal->format('yyyy-MM-dd HH:mm:ss', $timezone, $locale);
265
     * ```
266
     *
267
     * @param null|FormatPattern|string $pattern Optional custom format pattern for the date and time. If null, uses a default pattern.
268
     * @param null|Timezone $timezone Optional timezone for formatting. If null, uses the system's default timezone.
269
     * @param null|Locale $locale Optional locale for formatting. If null, uses the system's default locale.
270
     *
271
     * @return string The formatted date and time string, according to the specified pattern, timezone, and locale.
272
     *
273
     * @see https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax
274
     */
275
    public function format(null|FormatPattern|string $pattern = null, ?Timezone $timezone = null, ?Locale $locale = null): string
9✔
276
    {
277
        $timestamp = $this->getTimestamp();
9✔
278

279
        return namespace\create_intl_date_formatter(null, null, $pattern, $timezone, $locale)->format(
9✔
280
            $timestamp->getSeconds() + ($timestamp->getNanoseconds() / NANOSECONDS_PER_SECOND),
9✔
281
        );
9✔
282
    }
283

284
    /**
285
     * Formats this {@see TemporalInterface} instance to a string based on the RFC 3339 format, with additional
286
     * options for second fractions and timezone representation.
287
     *
288
     * The RFC 3339 format is widely adopted in web and network protocols for its unambiguous representation of date, time,
289
     * and timezone information. This method not only ensures universal readability but also the precise specification
290
     * of time across various systems, being compliant with both RFC 3339 and ISO 8601 standards.
291
     *
292
     * Example usage:
293
     *
294
     * ```php
295
     * // Default formatting
296
     * $rfc_formatted_string = $datetime->toRfc3339();
297
     * // Customized formatting with milliseconds and 'Z' for UTC
298
     * $rfc_formatted_string_with_milliseconds_and_z = $datetime->toRfc3339(SecondsStyle::Milliseconds, true);
299
     * ```
300
     *
301
     * @param null|SecondsStyle $secondsStyle Optional parameter to specify the seconds formatting style. Automatically
302
     *                                         selected based on precision if null.
303
     * @param bool $useZ Determines the representation of UTC timezone. True to use 'Z', false to use the standard offset format.
304
     *
305
     * @return string The formatted string of the {@see TemporalInterface} instance, adhering to the RFC 3339 and compatible with ISO 8601 formats.
306
     *
307
     * @see https://datatracker.ietf.org/doc/html/rfc3339
308
     */
309
    public function toRfc3339(?SecondsStyle $secondsStyle = null, bool $useZ = false): string
1✔
310
    {
311
        return namespace\format_rfc3339($this->getTimestamp(), $secondsStyle, $useZ);
1✔
312
    }
313

314
    /**
315
     * Provides a string representation of this {@see TemporalInterface} instance, formatted according to specified styles for date and time,
316
     * and optionally adjusted for a specific timezone and locale.
317
     *
318
     * This method offers a higher-level abstraction for formatting, allowing users to specify styles for date and time separately
319
     * rather than a custom pattern. If no styles are provided, default styles will be used.
320
     *
321
     * Additionally, the timezone and locale can be specified for locale-sensitive formatting.
322
     *
323
     * Example usage:
324
     *
325
     * ```php
326
     * $string_representation = $temporal->toString(FormatDateStyle::Long, FormatTimeStyle::Short, $timezone, $locale);
327
     * ```
328
     *
329
     * @param null|DateStyle $dateStyle Optional style for the date portion of the output. If null, a default style is used.
330
     * @param null|TimeStyle $timeStyle Optional style for the time portion of the output. If null, a default style is used.
331
     * @param null|Timezone $timezone Optional timezone for formatting. If null, uses the system's default timezone.
332
     * @param null|Locale $locale Optional locale for formatting. If null, uses the system's default locale.
333
     *
334
     * @return string The string representation of the date and time, formatted according to the specified styles, timezone, and locale.
335
     *
336
     * @see DateStyle::default()
337
     * @see TimeStyle::default()
338
     */
339
    public function toString(?DateStyle $dateStyle = null, ?TimeStyle $timeStyle = null, ?Timezone $timezone = null, ?Locale $locale = null): string
1✔
340
    {
341
        $timestamp = $this->getTimestamp();
1✔
342

343
        return namespace\create_intl_date_formatter($dateStyle, $timeStyle, null, $timezone, $locale)->format(
1✔
344
            $timestamp->getSeconds() + ($timestamp->getNanoseconds() / NANOSECONDS_PER_SECOND),
1✔
345
        );
1✔
346
    }
347

348
    /**
349
     * Magic method that provides a default string representation of the date and time.
350
     *
351
     * This method is a shortcut for calling `toString()` with all null arguments, returning a string formatted
352
     * with default styles, timezone, and locale. It is automatically called when the object is used in a string context.
353
     *
354
     * Example usage:
355
     *
356
     * ```php
357
     * $default_string_representation = (string) $temporal; // Uses __toString() for formatting
358
     * ```
359
     *
360
     * @return string The default string representation of the date and time.
361
     *
362
     * @see TemporalInterface::toString()
363
     */
NEW
364
    #[\Override]
×
365
    public function __toString(): string
366
    {
NEW
367
        return $this->toString();
×
368
    }
369

370
    /**
371
     * Stops the execution and dumps the current state of this temporal object.
372
     */
NEW
373
    public function dd(): void
×
374
    {
375
        // @phpstan-ignore disallowed.function
NEW
376
        dd($this); // @mago-expect best-practices/no-debug-symbols
×
377
    }
378
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc