Skip to content

Commit f4af396

Browse files
committed
✨ DateTimeCollection
✅ **Tested!** ✨ Features ========== * Define `ObjectCollection` for `\DateTime` - Define `containsDateTimeValue` to verify upon "date time + timezone" rather than object hash * Same for nullable `\DateTime`
1 parent a79181c commit f4af396

File tree

9 files changed

+472
-0
lines changed

9 files changed

+472
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\ObjectCollection\DateTime;
6+
7+
use Steevanb\PhpCollection\ObjectCollection\AbstractObjectCollection;
8+
9+
/** @extends AbstractObjectCollection<\DateTime> */
10+
class DateTimeCollection extends AbstractObjectCollection
11+
{
12+
public static function getValueFqcn(): string
13+
{
14+
return \DateTime::class;
15+
}
16+
17+
public function containsDateTimeValue(\DateTime $dateTime): bool
18+
{
19+
foreach ($this->toArray() as $value) {
20+
if (
21+
($dateTime->getTimestamp() + $dateTime->getOffset())
22+
!== ($value->getTimestamp() + $value->getOffset())
23+
) {
24+
continue;
25+
}
26+
27+
return true;
28+
}
29+
30+
return false;
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\ObjectCollection\DateTime;
6+
7+
use Steevanb\PhpCollection\ObjectCollection\AbstractObjectNullableCollection;
8+
9+
/** @extends AbstractObjectNullableCollection<?\DateTime> */
10+
class DateTimeNullableCollection extends AbstractObjectNullableCollection
11+
{
12+
public static function getValueFqcn(): string
13+
{
14+
return \DateTime::class;
15+
}
16+
17+
public function containsDateTimeValue(\DateTime $dateTime): bool
18+
{
19+
foreach ($this->toArray() as $value) {
20+
if (
21+
$value === null
22+
|| ($dateTime->getTimestamp() + $dateTime->getOffset())
23+
!== ($value->getTimestamp() + $value->getOffset())
24+
) {
25+
continue;
26+
}
27+
28+
return true;
29+
}
30+
31+
return false;
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\ObjectCollection;
6+
7+
/** @extends AbstractObjectCollection<\DateTime> */
8+
class DateTimeCollection extends AbstractObjectCollection
9+
{
10+
public static function getValueFqcn(): string
11+
{
12+
return \DateTime::class;
13+
}
14+
15+
public function containsDateTimeValue(\DateTime $dateTime): bool
16+
{
17+
foreach ($this->toArray() as $value) {
18+
if ($dateTime->format(\DateTimeInterface::ATOM) !== $value->format(\DateTimeInterface::ATOM)) {
19+
continue;
20+
}
21+
22+
return true;
23+
}
24+
25+
return false;
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\Tests\Unit\ObjectCollection\DateTime\DateTimeCollection;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Steevanb\PhpCollection\ObjectCollection\DateTime\DateTimeCollection;
9+
10+
final class ContainsDateTimeValueTest extends TestCase
11+
{
12+
public function testContainsDateTimeValue(): void
13+
{
14+
$dateTimeA = new \DateTime();
15+
$dateTimeCopy = $dateTimeA;
16+
// Asserting different timestamps
17+
$dateTimeB = (new \DateTime())->add(new \DateInterval('PT1S'));
18+
$dateTimeClone = clone $dateTimeA;
19+
$dateTimeSameTime = (new \DateTime())->setTimestamp($dateTimeA->getTimestamp());
20+
21+
$dateTimeCollection = new DateTimeCollection([$dateTimeA]);
22+
23+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeA));
24+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeCopy));
25+
static::assertFalse($dateTimeCollection->containsDateTimeValue($dateTimeB));
26+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeClone));
27+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeSameTime));
28+
}
29+
30+
public function testContainsDateTimeValueWithTimezone(): void
31+
{
32+
$dateTime = new \DateTime('2024-07-14 12:00:00');
33+
$dateTimeB = clone $dateTime;
34+
$dateTimeC = clone $dateTime;
35+
$dateTimeD = clone $dateTime;
36+
37+
// Setting timezones
38+
$dateTime->setTimezone(new \DateTimeZone('+0800'));
39+
$dateTimeB->setTimezone(new \DateTimeZone('+0600'));
40+
$dateTimeC->setTimezone(new \DateTimeZone('-0600'));
41+
$dateTimeD->setTimezone($dateTime->getTimezone());
42+
43+
$dateTimeCollection = new DateTimeCollection([$dateTime]);
44+
45+
static::assertFalse($dateTimeCollection->containsDateTimeValue($dateTimeB));
46+
static::assertFalse($dateTimeCollection->containsDateTimeValue($dateTimeC));
47+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeD));
48+
}
49+
50+
public function testContainsDateTimeValueAfterClone(): void
51+
{
52+
$dateTime = new \DateTime();
53+
54+
$dateTimeCollection = (new DateTimeCollection([$dateTime]));
55+
$dateTimeCollectionClone = clone ($dateTimeCollection);
56+
57+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTime));
58+
static::assertTrue($dateTimeCollectionClone->containsDateTimeValue($dateTime));
59+
}
60+
61+
public function testContainsDateTimeValueAfterMerge(): void
62+
{
63+
$dateTime = new \DateTime();
64+
65+
static::assertTrue(
66+
(new DateTimeCollection([$dateTime]))
67+
->merge(new DateTimeCollection([new \DateTime()]))
68+
->containsDateTimeValue($dateTime)
69+
);
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\Tests\Unit\ObjectCollection\DateTime\DateTimeCollection;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Steevanb\PhpCollection\ObjectCollection\DateTime\DateTimeCollection;
9+
10+
final class ContainsTest extends TestCase
11+
{
12+
public function testContains(): void
13+
{
14+
$dateTimeA = new \DateTime();
15+
$dateTimeCopy = $dateTimeA;
16+
$dateTimeB = new \DateTime();
17+
$dateTimeClone = clone $dateTimeA;
18+
$dateTimeSameTime = (new \DateTime())->setTimestamp($dateTimeA->getTimestamp());
19+
20+
$dateTimeCollection = new DateTimeCollection([$dateTimeA]);
21+
22+
static::assertTrue($dateTimeCollection->contains($dateTimeA));
23+
static::assertTrue($dateTimeCollection->contains($dateTimeCopy));
24+
static::assertFalse($dateTimeCollection->contains($dateTimeB));
25+
static::assertFalse($dateTimeCollection->contains($dateTimeClone));
26+
static::assertFalse($dateTimeCollection->contains($dateTimeSameTime));
27+
}
28+
29+
public function testContainsAfterClone(): void
30+
{
31+
$dateTime = new \DateTime();
32+
33+
$dateTimeCollection = (new DateTimeCollection([$dateTime]));
34+
$dateTimeCollectionClone = clone ($dateTimeCollection);
35+
36+
static::assertTrue($dateTimeCollection->contains($dateTime));
37+
static::assertTrue($dateTimeCollectionClone->contains($dateTime));
38+
}
39+
40+
public function testContainsAfterMerge(): void
41+
{
42+
$dateTime = new \DateTime();
43+
44+
static::assertTrue(
45+
(new DateTimeCollection([$dateTime]))
46+
->merge(new DateTimeCollection([new \DateTime()]))
47+
->contains($dateTime)
48+
);
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\Tests\Unit\ObjectCollection\DateTime\DateTimeCollection;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Steevanb\PhpCollection\{
9+
Exception\InvalidTypeException,
10+
ObjectCollection\DateTime\DateTimeCollection
11+
};
12+
13+
final class TypeTest extends TestCase
14+
{
15+
public function testAllowDateTime(): void
16+
{
17+
$dateTime = new \DateTime();
18+
$dateTimeCollection = new DateTimeCollection([$dateTime]);
19+
20+
static::assertCount(expectedCount: 1, haystack: $dateTimeCollection);
21+
static::assertSame(expected: $dateTime, actual: $dateTimeCollection->get(0));
22+
}
23+
24+
/** @dataProvider dataProviderInvalidType */
25+
public function testInvalidType(mixed $value): void
26+
{
27+
$this->expectException(InvalidTypeException::class);
28+
/** @phpstan-ignore-next-line Parameter #1 $values ... constructor expects ... array<int, mixed> given. */
29+
new DateTimeCollection([$value]);
30+
}
31+
32+
public function dataProviderInvalidType(): \Generator
33+
{
34+
yield 'it_throws_invalid_type_exception_on_null_value' => [
35+
'value' => null,
36+
];
37+
yield 'it_throws_invalid_type_exception_on_true_value' => [
38+
'value' => true,
39+
];
40+
yield 'it_throws_invalid_type_exception_on_false_value' => [
41+
'value' => false,
42+
];
43+
yield 'it_throws_invalid_type_exception_on_string_value' => [
44+
'value' => '--value--',
45+
];
46+
yield 'it_throws_invalid_type_exception_on_integer_value' => [
47+
'value' => 42,
48+
];
49+
yield 'it_throws_invalid_type_exception_on_float_value' => [
50+
'value' => 3.14,
51+
];
52+
yield 'it_throws_invalid_type_exception_on_empty_array_value' => [
53+
'value' => [],
54+
];
55+
yield 'it_throws_invalid_type_exception_on_DateTime_array_value' => [
56+
'value' => [new \DateTime()],
57+
];
58+
yield 'it_throws_invalid_type_exception_on_object_value' => [
59+
'value' => new class() {
60+
},
61+
];
62+
yield 'it_throws_invalid_type_exception_on_DateTimeCollection_value' => [
63+
'value' => new DateTimeCollection(),
64+
];
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\Tests\Unit\ObjectCollection\DateTime\DateTimeNullableCollection;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Steevanb\PhpCollection\ObjectCollection\DateTime\DateTimeNullableCollection;
9+
10+
final class ContainsDateTimeValueTest extends TestCase
11+
{
12+
public function testContainsDateTimeValue(): void
13+
{
14+
$dateTimeA = new \DateTime();
15+
$dateTimeCopy = $dateTimeA;
16+
// Asserting different timestamps
17+
$dateTimeB = (new \DateTime())->add(new \DateInterval('PT1S'));
18+
$dateTimeClone = clone $dateTimeA;
19+
$dateTimeSameTime = (new \DateTime())->setTimestamp($dateTimeA->getTimestamp());
20+
21+
$dateTimeCollection = new DateTimeNullableCollection([$dateTimeA, null]);
22+
23+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeA));
24+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeCopy));
25+
static::assertFalse($dateTimeCollection->containsDateTimeValue($dateTimeB));
26+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeClone));
27+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeSameTime));
28+
}
29+
30+
public function testContainsDateTimeValueWithTimezone(): void
31+
{
32+
$dateTime = new \DateTime('2024-07-14 12:00:00');
33+
$dateTimeB = clone $dateTime;
34+
$dateTimeC = clone $dateTime;
35+
$dateTimeD = clone $dateTime;
36+
37+
// Setting timezones
38+
$dateTime->setTimezone(new \DateTimeZone('+0800'));
39+
$dateTimeB->setTimezone(new \DateTimeZone('+0600'));
40+
$dateTimeC->setTimezone(new \DateTimeZone('-0600'));
41+
$dateTimeD->setTimezone($dateTime->getTimezone());
42+
43+
$dateTimeCollection = new DateTimeNullableCollection([$dateTime]);
44+
45+
static::assertFalse($dateTimeCollection->containsDateTimeValue($dateTimeB));
46+
static::assertFalse($dateTimeCollection->containsDateTimeValue($dateTimeC));
47+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeD));
48+
}
49+
50+
public function testContainsDateTimeValueAfterClone(): void
51+
{
52+
$dateTime = new \DateTime();
53+
54+
$dateTimeCollection = (new DateTimeNullableCollection([$dateTime]));
55+
$dateTimeCollectionClone = clone ($dateTimeCollection);
56+
57+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTime));
58+
static::assertTrue($dateTimeCollectionClone->containsDateTimeValue($dateTime));
59+
}
60+
61+
public function testContainsDateTimeValueAfterMerge(): void
62+
{
63+
$dateTime = new \DateTime();
64+
65+
static::assertTrue(
66+
(new DateTimeNullableCollection([$dateTime]))
67+
->merge(new DateTimeNullableCollection([new \DateTime()]))
68+
->containsDateTimeValue($dateTime)
69+
);
70+
}
71+
}

0 commit comments

Comments
 (0)