修补/保存时,为什么日期/时间值解释不正确?

Fro*_*gyp 5 datetime cakephp marshalling internationalization cakephp-3.0

我尝试从cakephp 3表单中保存数据.所有数据都保存得很好,但日期时间没有.我有2个日期时间字段.这些字段由jquery-ui小部件填充.

在实体化时,似乎发生了这个问题.

$intervention = $this->Interventions->patchEntity($intervention, $this->request->data);
Run Code Online (Sandbox Code Playgroud)
  • 调试$ this-> request-> data:

    'user_id' => '1',
    'description' => 'test',
    'starttime' => '2015/11/15 10:00',
    'endtime' => '2015/11/15 12:10'
    
    Run Code Online (Sandbox Code Playgroud)
  • 在pacthEntity之后调试我的对象$干预:

对象(应用程序\模型\实体\干预)

'id' => (int) 3,
'user_id' => (int) 1,
'description' => 'test',
'starttime' => null,
'endtime' => null
...
Run Code Online (Sandbox Code Playgroud)

starttime和endtime变为null,我不明白为什么.

有人曾经有过这个pb吗?

我尝试(用于调试和理解)强制字段值,然后在mysql中修补和datetime字段都可以.

$intervention->starttime = date('Y-m-d H:i:s', strtotime($this->request->data['starttime'])); 
$intervention->endtime = date('Y-m-d H:i:s', strtotime($this->request->data['endtime']));
Run Code Online (Sandbox Code Playgroud)

感谢帮助

ndm*_*ndm 20

日期/时间值以区域设置感知方式进行转换/解析


更新:这是3.2.5之前的CakePHP应用程序模板版本的默认行为.从3.2.5开始,默认情况下不再启用语言环境解析,这将使日期/时间编组逻辑期望默认格式Y-m-d H:i:s.


在编组过程中,根据相应的列类型对值进行"转换".对于DATETIME列,这是由\Cake\Database\Type\DateTimeType类型类完成的.

确切地说,这是完成的\Cake\Database\Type\DateTimeType::marshall().

使用默认的应用程序模板配置,DateTimeType配置为使用区域设置感知解析,并且由于没有设置默认的区域设置格式,因此 \Cake\I18n\Time::parseDateTime()将根据其默认的"字符串格式"(Time::$_toStringFormat)来解析值,默认情况下可识别区域设置[IntlDateFormatter::SHORT, IntlDateFormatter::SHORT].

因此,如果您的语言环境设置为en_US,那么该值将使用M/d/yy, h:mm a您的值不适合的预期格式进行解析,因此您最终将最终null设置为实体属性.

使解析器使用正确的格式

TL;博士

如果jQuery小部件的格式没有在您的应用程序中的任何位置使用,您可以例如临时设置正确的区域设置格式,或者禁用区域设置解析,例如

// for time- or date-only comlumn types you'd use 'time' or 'date' instead of 'datetime'
$dateTimeType = Type::build('datetime')->setLocaleFormat('yyyy/MM/dd HH:mm');

// ...
$intervention = $this->Interventions->patchEntity($intervention, $this->request->data);
// ...

$dateTimeType->setLocaleFormat(null);
Run Code Online (Sandbox Code Playgroud)

要么

$dateTimeType = Type::build('datetime')->useLocaleParser(false);

// ...
$intervention = $this->Interventions->patchEntity($intervention, $this->request->data);
// ...

$dateTimeType->useLocaleParser(true);
Run Code Online (Sandbox Code Playgroud)

应该注意,这将影响所有日期/时间输入,而不仅仅是你的starttimeendtime字段!

另一方面,jQuery小部件使用的格式应该是您希望在应用程序中使用的格式,那么更改默认格式也可以这样做,例如

use Cake\I18n\Time;
use Cake\I18n\FrozenTime;

// To affect date-only columns you'd configure `Date` and `FrozenDate`.
// For time-only columns, see the linked SO question below.
Time::setToStringFormat('yyyy/MM/dd HH:mm');
FrozenTime::setToStringFormat('yyyy/MM/dd HH:mm');
Run Code Online (Sandbox Code Playgroud)

在你的bootstrap.php.请注意,这里还有Time/FrozenTime::setJsonEncodeFormat()Time/FrozenTime::$niceFormat你可能想/需要修改了.

也可以看看

在编组之前转换输入

另一种选择是Time例如在编组过程之前将数据转换为实例.这将避免前面提到的可能影响所有输入的解决方案的可能问题.

在您的InterventionsTable课程中(也可以放入行为或外部监听器):

use Cake\Event\Event;
use Cake\I18n\Time;

...

public function beforeMarshal(Event $event, \ArrayObject $data, \ArrayObject $options)
{
    foreach (['starttime', 'endtime'] as $key) {
        if (isset($data[$key]) && is_string($data[$key])) {
            $data[$key] = Time::parseDateTime($data[$key], 'yyyy/MM/dd HH:mm');
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

也可以看看

Cookbook>数据库访问和ORM>保存数据>在构建实体之前修改请求数据

  • @Froggyp欢迎你...请注意我已经更新了我的答案并附加了一个建议. (2认同)