CakePHP 3 时间列添加了日期
我在 MySQL 数据库中将许多列定义为时间".也就是说,他们有时间,但没有约会.当它们被 CakePHP 3 ORM 读取时,它们被转换成 CakeI18nTime 对象(通过 CakeDatabaseTypeTimeType 类),但结果中总是包含日期和时间,其中日期设置为当前日期.例如,如果值为20:00:00",debug($record['start_time'])
将生成:
I have a number of columns defined in my MySQL database as "time". That is, they have a time, but not a date. When they are read by the CakePHP 3 ORM, they are being converted into CakeI18nTime objects (through the CakeDatabaseTypeTimeType class), but the result always has both a date and a time in it, with the date set to the current date. For example, if the value is "20:00:00", debug($record['start_time'])
will generate:
object(CakeI18nTime) {
'time' => '2015-06-21T20:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
}
当我在模板中回显它时(没有使用 setToStringFormat
),我得到类似 6/21/15 8:00 PM
的信息.当然,我可以使用 $this->Time->format
将它放回仅限时间的格式,但我需要这样做似乎很奇怪.为什么 Cake 无视这只是时间这一事实,更重要的是,有没有办法让它停止?
And when I echo it in a template (without having used setToStringFormat
), I get something like 6/21/15 8:00 PM
. Of course, I can use $this->Time->format
to put it back into a time-only format, but it seems very strange that I would need to do so. Why is Cake ignoring the fact that this is just a time, and, more importantly, is there a way to make it stop?
推荐答案
日期/时间值都被强制转换为相同的基本结构,即 DateTime
或 DateTimeImmutable
对象,因此纯日期值自然会有一个时间添加的值 (00:00:00
),并且仅时间值带有日期(当前日期).
Date/Time values are all being casted to the same base structure, that is a DateTime
or DateTimeImmutable
object, and so naturally date-only values will have a time value added (00:00:00
), and time-only values come with a date (the current date).
CakePHP 将根据 SQL 数据类型使用特定的子类,即
CakePHP will uses specific subclasses depending on the SQL datatype, that is
CakeI18nTime
或CakeI18nFrozenTime
用于TIME
、TIMESTAMP
和日期时间
CakeI18nDate
或CakeI18nFrozenDate
用于DATE
CakeI18nTime
orCakeI18nFrozenTime
forTIME
,TIMESTAMP
, andDATETIME
CakeI18nDate
orCakeI18nFrozenDate
forDATE
在早期的 CakePHP 3 版本中只有 CakeI18nTime
.
In earlier CakePHP 3 versions there was only CakeI18nTime
.
如果有一个单独的类用于仅时间类型会很好,它将具有适当的仅时间默认输出格式集,但是在添加类似的内容之前,您必须注意自己输出格式.
It would be nice if there would be a separate class for time-only types, which would have a proper time-only default output format set, but until something like that is added, you'll have to take care of the output format yourself.
如何在您的视图中显示它取决于您.您可以轻松使用Time
类实例
It is up to you how to display this in your views. You can easily use the i18nFormat()
method of the Time
class instance
$record['start_time']->i18nFormat(
[IntlDateFormatter::NONE, IntlDateFormatter::SHORT]
)
或 Time
助手,只显示时间部分
or the Time
helper, to show only the time part
$this->Time->i18nFormat(
$record['start_time'],
[IntlDateFormatter::NONE, IntlDateFormatter::SHORT]
)
猜猜如果bake 会根据列的类型生成类似的代码不会有什么坏处,您可能想要建议将其作为改进.如前所述,为仅时间列使用额外的类(或可能的选项)也可能值得考虑.
Guess it wouldn't hurt if bake would generate similar code according to the type of column, you may want to suggest that as an enhancement. As mentioned using additional classes (or maybe options) for time-only columns may be something worth to consider too.
如果您希望在使用对象的字符串表示的任何地方都有这种行为,而不必手动调用格式化程序,那么您可以使用扩展的 CakeI18nTime
或具有覆盖 $_toStringFormat
属性的 CakeI18nFrozenTime
类,以便相应地格式化日期.
If you'd wanted this behavior everywhere where the string representation of the object is being used, without having to manually invoke the formatter, then you could make use of an extended CakeI18nTime
or CakeI18nFrozenTime
class with an overriden $_toStringFormat
property, so that it formats the date accordingly.
src/I18n/FrozenTimeOnly.php
namespace AppI18n;
use CakeI18nFrozenTime;
class FrozenTimeOnly extends FrozenTime
{
protected static $_toStringFormat = [
IntlDateFormatter::NONE,
IntlDateFormatter::SHORT
];
}
src/config/bootstrap.php
use CakeDatabaseTypeTimeType;
use AppI18nFrozenTimeOnly;
TimeType::$dateTimeClass = FrozenTimeOnly::class;
// remove the default `useImmutable()` call, you may however
// want to keep further calls for formatting and stuff
Type::build('time');
// ...
这应该是不言自明的,映射到 TimeType
的 time
列现在将使用 AppI18nFrozenTimeOnly
代替默认CakeI18nTime
.
This should pretty much self-explantory, time
columns that are being mapped to TimeType
, will now use AppI18nFrozenTimeOnly
instead of the default CakeI18nTime
.
为了解决这个问题,需要一个自定义的数据库类型,这也很简单.
In order to cope with that, a custom database type will be required, which is rather simple too.
src/Database/Type/TimeOnlyType.php
namespace AppDatabaseType;
use AppI18nFrozenTimeOnly;
use CakeDatabaseTypeTimeType;
class TimeOnlyType extends TimeType
{
public function __construct($name)
{
parent::__construct($name);
$this->_setClassName(FrozenTimeOnly::class, DateTimeImmutable::class);
}
}
应该注意,目前这将实例化一个数据/时间类两次,因为父构造函数也会调用 _setClassName()
,这是给定类的实例将被实例化的地方.
It should be note that currently this will instantiate a data/time class twice, as the parent constructor will invoke _setClassName()
too, which is where an instance of the given class will be instantiated.
src/config/bootstrap.php
use AppDatabaseTypeTimeOnlyType;
Type::map('time', TimeOnlyType::class);
所以这会做的是覆盖默认的 time
类型映射以使用自定义的 AppDatabaseTypeTimeOnlyType
类,而后者将使用AppI18nTimeOnly
将数据库值转换为 PHP 对象时的类,当转换为字符串时,将使用仅时间格式.
So what this will do, is override the default time
type mapping to use the custom AppDatabaseTypeTimeOnlyType
class, which in turn will use the AppI18nTimeOnly
class when converting database values to PHP objects, which when converted to a string, will use the time-only format.
- Cookbook > Time > 设置默认语言环境和格式字符串
- 食谱 > 数据库访问 &ORM > 数据库基础 > 添加自定义类型
相关文章