Skip to content

Add DateTimeColumn #968

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
May 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
- Enh #879: Rename `getLastInsertID()` method in `ConnectionInterface` to `getLastInsertId()` (@vjik)
- New #967: Add `FOR` clause to query (@vjik)
- Chg #972: Change in query "distinct" flag type from `bool|null` to `bool` (@vjik)
- New #968: Add `DateTimeColumn` column class (@Tigrov)

## 1.3.0 March 21, 2024

Expand Down
3 changes: 2 additions & 1 deletion UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ Each table column has its own class in the `Yiisoft\Db\Schema\Column` namespace
- `IntegerColumn` for columns with integer type (tinyint, smallint, integer, bigint);
- `BigIntColumn` for columns with integer type with range outside `PHP_INT_MIN` and `PHP_INT_MAX`;
- `DoubleColumn` for columns with fractional number type (float, double, decimal, money);
- `StringColumn` for columns with string or datetime type (char, string, text, datetime, timestamp, date, time);
- `StringColumn` for columns with string type (char, string, text);
- `BinaryColumn` for columns with binary type;
- `DateTimeColumn` for columns with date and time type (timestamp, datetime, time, date);
- `ArrayColumn` for columns with array type;
- `StructuredColumn` for columns with structured type (composite type in PostgreSQL);
- `JsonColumn` for columns with json type.
Expand Down
16 changes: 16 additions & 0 deletions docs/guide/en/connection/oracle.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,19 @@ $pdoDriver = new Driver($dsn, 'user', 'password');
// Connection.
$db = new Connection($pdoDriver, $schemaCache);
```

## Date and Time Formats

After opening a connection, the Oracle driver will set the date and time formats to ISO 8601.
This is required for the correct conversion of date and time values retrieved from the database.

The following SQL statement is executed:

```SQL
ALTER SESSION SET
NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SSXFF'
NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SSXFFTZH:TZM'
NLS_TIME_FORMAT = 'HH24:MI:SSXFF'
NLS_TIME_TZ_FORMAT = 'HH24:MI:SSXFFTZH:TZM'
NLS_DATE_FORMAT = 'YYYY-MM-DD'
```
30 changes: 30 additions & 0 deletions docs/guide/en/schema/typecasting.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,36 @@ $isActive = $row['is_active'];

In the examples above, the value of `is_active` is casted to the correct `boolean` type before it is returned.

## DateTime, Date and Time types

Some databases support date and time types, such as `timestamp`, `datetime`, `date`, `time`, etc.
These types are casted to `DateTimeImmutable` objects using `DateTimeColumn` class when type casting is enabled.

```php
$query = (new Query($db))->from('customer')->where(['id' => 1]);

$row = $query->withTypecasting()->one();
$createdAt = $row['created_at']; // `DateTimeImmutable` object
```

```php
$command = $db->createCommand('SELECT * FROM {{customer}} WHERE id = 1');

$row = $command->withTypecasting()->queryOne();
$createdAt = $row['created_at']; // `DateTimeImmutable` object
```

In the examples above, the value of `created_at` column is casted to the `DateTimeImmutable` type before it is returned.

```php
$db->createCommand()->insert('customer', [
'name' => 'John Doe',
'updated_at' => new DateTimeImmutable(),
])->execute();
```

In the example above, the value of `updated_at` is casted to the correct database type before it is saved.

## Custom type casting

To implement custom type casting you need to extend the `AbstractColumn` class and override the `dbTypecast()`
Expand Down
8 changes: 8 additions & 0 deletions src/Connection/ServerInfoInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
*/
interface ServerInfoInterface
{
/**
* Returns the server's session timezone.
*
* @param bool $refresh Whether to reload the server's session timezone. If `false`, the timezone fetched before
* will be returned if available.
*/
public function getTimezone(bool $refresh = false): string;

/**
* Returns a server version as a string comparable by {@see version_compare()}.
*/
Expand Down
20 changes: 14 additions & 6 deletions src/Constant/ColumnType.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,22 +69,30 @@ final class ColumnType
* Define the abstract column type as `uuid`.
*/
public const UUID = 'uuid';
/**
* Define the abstract column type as `datetime`.
*/
public const DATETIME = 'datetime';
/**
* Define the abstract column type as `timestamp`.
*/
public const TIMESTAMP = 'timestamp';
/**
* Define the abstract column type as `date`.
* Define the abstract column type as `datetime`.
*/
public const DATE = 'date';
public const DATETIME = 'datetime';
/**
* Define the abstract column type as `datetimetz`.
*/
public const DATETIMETZ = 'datetimetz';
/**
* Define the abstract column type as `time`.
*/
public const TIME = 'time';
/**
* Define the abstract column type as `timetz`.
*/
public const TIMETZ = 'timetz';
/**
* Define the abstract column type as `date`.
*/
public const DATE = 'date';
/**
* Define the abstract column type as `array`.
*/
Expand Down
6 changes: 6 additions & 0 deletions src/Driver/Pdo/PdoServerInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PDO;
use Yiisoft\Db\Connection\ServerInfoInterface;
use Yiisoft\Db\Exception\NotSupportedException;

class PdoServerInfo implements ServerInfoInterface
{
Expand All @@ -15,6 +16,11 @@ public function __construct(protected PdoConnectionInterface $db)
{
}

public function getTimezone(bool $refresh = false): string
{
throw new NotSupportedException(__METHOD__ . ' is not supported by this DBMS.');
}

public function getVersion(): string
{
if ($this->version === null) {
Expand Down
12 changes: 10 additions & 2 deletions src/Schema/Column/AbstractColumnFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ protected function getColumnClass(string $type, array $info = []): string
ColumnType::FLOAT => DoubleColumn::class,
ColumnType::DOUBLE => DoubleColumn::class,
ColumnType::BINARY => BinaryColumn::class,
ColumnType::TIMESTAMP => DateTimeColumn::class,
ColumnType::DATETIME => DateTimeColumn::class,
ColumnType::DATETIMETZ => DateTimeColumn::class,
ColumnType::TIME => DateTimeColumn::class,
ColumnType::TIMETZ => DateTimeColumn::class,
ColumnType::DATE => DateTimeColumn::class,
ColumnType::ARRAY => ArrayColumn::class,
ColumnType::STRUCTURED => StructuredColumn::class,
ColumnType::JSON => JsonColumn::class,
Expand Down Expand Up @@ -284,10 +290,12 @@ protected function isType(string $type): bool
ColumnType::TEXT,
ColumnType::BINARY,
ColumnType::UUID,
ColumnType::DATETIME,
ColumnType::TIMESTAMP,
ColumnType::DATE,
ColumnType::DATETIME,
ColumnType::DATETIMETZ,
ColumnType::TIME,
ColumnType::TIMETZ,
ColumnType::DATE,
ColumnType::ARRAY,
ColumnType::STRUCTURED,
ColumnType::JSON => true,
Expand Down
36 changes: 26 additions & 10 deletions src/Schema/Column/ColumnBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,35 +192,51 @@ public static function uuid(): ColumnInterface
}

/**
* Builds a column with the abstract type `datetime`.
* Builds a column with the abstract type `timestamp`.
*/
public static function datetime(int|null $size = 0): ColumnInterface
public static function timestamp(int|null $size = 0): ColumnInterface
{
return new StringColumn(ColumnType::DATETIME, size: $size);
return new DateTimeColumn(ColumnType::TIMESTAMP, size: $size);
}

/**
* Builds a column with the abstract type `timestamp`.
* Builds a column with the abstract type `datetime`.
*/
public static function timestamp(int|null $size = 0): ColumnInterface
public static function datetime(int|null $size = 0): ColumnInterface
{
return new StringColumn(ColumnType::TIMESTAMP, size: $size);
return new DateTimeColumn(ColumnType::DATETIME, size: $size);
}

/**
* Builds a column with the abstract type `date`.
* Builds a column with the abstract type `datetimetz`.
*/
public static function date(): ColumnInterface
public static function datetimeWithTimezone(int|null $size = 0): ColumnInterface
{
return new StringColumn(ColumnType::DATE);
return new DateTimeColumn(ColumnType::DATETIMETZ, size: $size);
}

/**
* Builds a column with the abstract type `time`.
*/
public static function time(int|null $size = 0): ColumnInterface
{
return new StringColumn(ColumnType::TIME, size: $size);
return new DateTimeColumn(ColumnType::TIME, size: $size);
}

/**
* Builds a column with the abstract type `timetz`.
*/
public static function timeWithTimezone(int|null $size = 0): ColumnInterface
{
return new DateTimeColumn(ColumnType::TIMETZ, size: $size);
}

/**
* Builds a column with the abstract type `date`.
*/
public static function date(): ColumnInterface
{
return new DateTimeColumn(ColumnType::DATE);
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/Schema/Column/ColumnFactoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* columns?: array<string, ColumnInterface>,
* comment?: string|null,
* computed?: bool,
* dbTimezone?: string,
* dbType?: string|null,
* defaultValue?: mixed,
* defaultValueRaw?: string|null,
Expand Down
1 change: 0 additions & 1 deletion src/Schema/Column/ColumnInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ public function getPrecision(): int|null;
* Returns the PHP type of the column. Used for generating properties of a related model class.
*
* @return string The PHP type of the column.
* @psalm-return PhpType::*
* @psalm-mutation-free
*/
public function getPhpType(): string;
Expand Down
Loading