CakePHP 3 时间列获取添加日期

CakePHP 3 time column gets date added

我的 MySQL 数据库中有许多列定义为 "time"。也就是说,他们有时间,但没有约会。当它们被 CakePHP 3 ORM 读取时,它们被转换为 Cake\I18n\Time 对象(通过 Cake\Database\Type\TimeType class),但结果总是包含日期和时间,日期设置为当前日期。例如,如果值为“20:00:00”,debug($record['start_time']) 将生成:

object(Cake\I18n\Time) {
    'time' => '2015-06-21T20:00:00+0000',
    'timezone' => 'UTC',
    'fixedNowTime' => false
}

当我在模板中回应它时(没有使用 setToStringFormat),我得到类似 6/21/15 8:00 PM 的结果。当然,我可以使用 $this->Time->format 将其恢复为仅时间格式,但我需要这样做似乎很奇怪。为什么 Cake 忽略了这样一个事实,即 只是 一次,更重要的是,有没有办法让它停止?

事实是 cakePHP 将你的时间值作为时间对象执行,它扩展了碳和 dateTime,所以你得到一个包含日期的完整 dateTime 实例:(

但是您可以轻松地对您的实体执行自动设置。您只需使用此处描述的访问器和修改器:http://book.cakephp.org/3.0/en/orm/entities.html#accessors-mutators

Date/Time 值都被转换为相同的基本结构,即 DateTimeDateTimeImmutable 对象,因此自然地,仅日期值将添加时间值(00:00:00),并且时间值带有日期(当前日期)。

CakePHP 将根据 SQL 数据类型使用特定的子 classes,即

  • \Cake\I18n\Time\Cake\I18n\FrozenTime 表示 TIMETIMESTAMPDATETIME
  • \Cake\I18n\Date\Cake\I18n\FrozenDate 对于 DATE

在早期的 CakePHP 3 个版本中只有 \Cake\I18n\Time.

如果有一个单独的 class 用于仅限时间的类型,那会很好,它将有一个适当的仅限时间的默认输出格式设置,但在添加类似的东西之前,你会必须自己处理输出格式。

您认为的格式

如何在您的视图中显示它取决于您。您可以轻松使用 Time class 实例

i18nFormat() 方法
$record['start_time']->i18nFormat(
    [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT]
)

Time 助手,仅显示时间部分

$this->Time->i18nFormat(
    $record['start_time'],
    [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT]
)

我猜如果 bake 会根据列的类型生成类似的代码也没什么坏处,您可能想要 suggest that as an enhancement。如前所述,为仅限时间的列使用额外的 classes(或选项)也可能值得考虑。

使用自定义时间class

如果您希望在使用对象的字符串表示形式的任何地方都有这种行为,而不必手动调用格式化程序,那么您可以使用扩展的 \Cake\I18n\Time\Cake\I18n\FrozenTime class 与覆盖 $_toStringFormat 属性,以便它相应地格式化日期。

src/I18n/FrozenTimeOnly.php

namespace App\I18n;

use Cake\I18n\FrozenTime;

class FrozenTimeOnly extends FrozenTime
{
    protected static $_toStringFormat = [
        \IntlDateFormatter::NONE,
        \IntlDateFormatter::SHORT
    ];
}

src/config/bootstrap.php

use Cake\Database\Type\TimeType;
use App\I18n\FrozenTimeOnly;
TimeType::$dateTimeClass = FrozenTimeOnly::class;

// remove the default `useImmutable()` call, you may however
// want to keep further calls for formatting and stuff
Type::build('time'); 
// ...

这应该是不言而喻的,映射到 TimeTypetime 列现在将使用 App\I18n\FrozenTimeOnly 而不是默认的 Cake\I18n\Time

DateTimeType::$dateTimeClass 已弃用

为了解决这个问题,需要自定义数据库类型,这也很简单。

src/Database/Type/TimeOnlyType.php

namespace App\Database\Type;

use App\I18n\FrozenTimeOnly;
use Cake\Database\Type\TimeType;

class TimeOnlyType extends TimeType
{
    public function __construct($name)
    {
        parent::__construct($name);
        $this->_setClassName(FrozenTimeOnly::class, \DateTimeImmutable::class);
    }
}

应该注意的是,目前这将实例化一个 data/time class 两次,因为父构造函数也会调用 _setClassName(),这是给定 class 将被实例化。

src/config/bootstrap.php

use App\Database\Type\TimeOnlyType;
Type::map('time', TimeOnlyType::class);

所以这会做什么,覆盖默认 time 类型映射以使用自定义 \App\Database\Type\TimeOnlyType class,这反过来将使用 \App\I18n\TimeOnly class 将数据库值转换为 PHP 对象时,当转换为字符串时,将使用仅时间格式。

另见