Skip to content

Commit

Permalink
refactor: convert dates to timestamps
Browse files Browse the repository at this point in the history
  • Loading branch information
simPod committed Jan 29, 2025
1 parent 9a90f8e commit eb9c425
Show file tree
Hide file tree
Showing 8 changed files with 15 additions and 50 deletions.
23 changes: 1 addition & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ Naming used here is the same as in ClickHouse docs.

- [Setup](#setup)
- [Logging](#logging)
- [Time Zones](#time-zones)
- [PSR Factories who?](#psr-factories-who)
- [Sync API](#sync-api)
- [Select](#select)
Expand Down Expand Up @@ -64,7 +63,6 @@ $clickHouseClient = new PsrClickHouseClient(
),
new LoggerChain(),
[],
new DateTimeZone('UTC')
);
```

Expand All @@ -87,25 +85,6 @@ framework:
database: '%clickhouse.database%'
```
### Time Zones
ClickHouse does not have date times with timezones.
Therefore you need to normalize DateTimes' timezones passed as parameters to ensure proper input format.
Following would be inserted as `2020-01-31 01:00:00` into ClickHouse.

```php
new DateTimeImmutable('2020-01-31 01:00:00', new DateTimeZone('Europe/Prague'));
```

If your server uses `UTC`, the value is incorrect for you actually need to insert `2020-01-31 00:00:00`.

Time zone normalization is enabled by passing `DateTimeZone` into `PsrClickHouseClient` constructor.

```php
new PsrClickHouseClient(..., new DateTimeZone('UTC'));
```

### PSR Factories who?
_The library does not implement it's own HTTP.
Expand Down Expand Up @@ -218,7 +197,7 @@ This produces `SELECT 'value'` and it can be passed to `ClickHouseClient::select

Supported types are:
- scalars
- DateTimeImmutable (`\DateTime` is not supported because `ValueFormatter` might modify its timezone so it's not considered safe)
- DateTimeInterface
- [Expression](#expression)
- objects implementing `__toString()`

Expand Down
4 changes: 1 addition & 3 deletions src/Client/PsrClickHouseAsyncClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace SimPod\ClickHouseClient\Client;

use DateTimeZone;
use Exception;
use GuzzleHttp\Promise\Create;
use GuzzleHttp\Promise\PromiseInterface;
Expand Down Expand Up @@ -32,9 +31,8 @@ public function __construct(
private RequestFactory $requestFactory,
private SqlLogger|null $sqlLogger = null,
private array $defaultSettings = [],
DateTimeZone|null $clickHouseTimeZone = null,
) {
$this->sqlFactory = new SqlFactory(new ValueFormatter($clickHouseTimeZone));
$this->sqlFactory = new SqlFactory(new ValueFormatter());
}

/**
Expand Down
4 changes: 1 addition & 3 deletions src/Client/PsrClickHouseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace SimPod\ClickHouseClient\Client;

use DateTimeZone;
use InvalidArgumentException;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface;
Expand Down Expand Up @@ -49,9 +48,8 @@ public function __construct(
private RequestFactory $requestFactory,
private SqlLogger|null $sqlLogger = null,
private array $defaultSettings = [],
DateTimeZone|null $clickHouseTimeZone = null,
) {
$this->valueFormatter = new ValueFormatter($clickHouseTimeZone);
$this->valueFormatter = new ValueFormatter();
$this->sqlFactory = new SqlFactory($this->valueFormatter);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Param/ParamValueConverterRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,15 @@ private static function decimalConverter(): Closure
private static function dateConverter(): Closure
{
return static fn (DateTimeInterface|string|int|float $value) => $value instanceof DateTimeInterface
// We cannot convert to timestamp yet https://github.com/ClickHouse/ClickHouse/issues/75217
? $value->format('Y-m-d')
: $value;
}

private static function dateTimeConverter(): Closure
{
return static fn (DateTimeInterface|string|int|float $value) => $value instanceof DateTimeInterface
? $value->format('Y-m-d H:i:s')
? $value->getTimestamp()
: $value;
}

Expand Down
15 changes: 3 additions & 12 deletions src/Sql/ValueFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
namespace SimPod\ClickHouseClient\Sql;

use BackedEnum;
use DateTimeImmutable;
use DateTimeZone;
use DateTimeInterface;
use SimPod\ClickHouseClient\Exception\UnsupportedParamValue;

use function array_key_first;
Expand All @@ -26,10 +25,6 @@
/** @internal */
final readonly class ValueFormatter
{
public function __construct(private DateTimeZone|null $dateTimeZone = null)
{
}

/** @throws UnsupportedParamValue */
public function format(mixed $value, string|null $paramName = null, string|null $sql = null): string
{
Expand Down Expand Up @@ -66,12 +61,8 @@ public function format(mixed $value, string|null $paramName = null, string|null
: (string) $value->value;
}

if ($value instanceof DateTimeImmutable) {
if ($this->dateTimeZone !== null) {
$value = $value->setTimezone($this->dateTimeZone);
}

return "'" . $value->format('Y-m-d H:i:s') . "'";
if ($value instanceof DateTimeInterface) {
return (string) $value->getTimestamp();
}

if ($value instanceof Expression) {
Expand Down
7 changes: 3 additions & 4 deletions tests/Client/Http/RequestFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,10 @@ public function testParamParsed(): void
new Psr17Factory(),
);

$now = new DateTimeImmutable();
$nowDate = $now->format('Y-m-d');
$now = new DateTimeImmutable();

$request = $requestFactory->prepareSqlRequest(
'SELECT {p1:String}, {p_2:Date}',
'SELECT {p1:String}, {p_2:DateTime}',
new RequestSettings(
[],
[],
Expand All @@ -104,7 +103,7 @@ public function testParamParsed(): void
'Content-Disposition: form-data; name="param_p_2"',
'Content-Length: 10',
'',
$nowDate,
$now->getTimestamp(),
],
),
$body,
Expand Down
3 changes: 1 addition & 2 deletions tests/Sql/ExpressionFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace SimPod\ClickHouseClient\Tests\Sql;

use DateTimeZone;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use SimPod\ClickHouseClient\Sql\ExpressionFactory;
Expand All @@ -18,7 +17,7 @@ final class ExpressionFactoryTest extends TestCaseBase
#[DataProvider('providerTemplateAndValues')]
public function testTemplateAndValues(string $expectedExpressionString, string $template, array $values): void
{
$expressionFactory = new ExpressionFactory(new ValueFormatter(new DateTimeZone('UTC')));
$expressionFactory = new ExpressionFactory(new ValueFormatter());

self::assertSame(
$expectedExpressionString,
Expand Down
6 changes: 3 additions & 3 deletions tests/Sql/ValueFormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function testFormat(
): void {
self::assertSame(
$expectedValue,
(new ValueFormatter(new DateTimeZone('UTC')))->format($value, $paramName, $sql),
(new ValueFormatter())->format($value, $paramName, $sql),
);
}

Expand Down Expand Up @@ -68,9 +68,9 @@ public static function providerFormat(): iterable
'SELECT * FROM table WHERE (a,b) IN (:tuples)',
];

yield 'DateTimeImmutable' => ["'2020-01-31 01:23:45'", new DateTimeImmutable('2020-01-31 01:23:45')];
yield 'DateTimeImmutable' => ['1580433825', new DateTimeImmutable('2020-01-31 01:23:45')];
yield 'DateTimeImmutable different PHP and ClickHouse timezones' => [
"'2020-01-31 01:23:45'",
'1580433825',
new DateTimeImmutable('2020-01-31 02:23:45', new DateTimeZone('Europe/Prague')),
];

Expand Down

0 comments on commit eb9c425

Please sign in to comment.