Laravel Carbon数据丢失

40

在我的模型中,我有以下内容:

protected $dates = [
    'start',
    'end',
    'created_at',
    'updated_at'
];

我正在使用一个日期时间选择器来插入开始和结束日期,格式如下:

2016-01-23 22:00

没有秒数。我这样做时,会出现以下错误:

InvalidArgumentException in Carbon.php line 425:
Data missing
at Carbon::createFromFormat('Y-m-d H:i:s', '2016-01-23 22:00') in Model.php line 3015

如果我包括了秒数,它会起作用。对我来说,秒不重要,我不想在我的日期时间选择器字段中包括它们。是否有任何方法可以解决这个问题,以便我仍然可以使用这些字段作为日期字段?

7个回答

99

简述

你的日期字符串和日期格式不同,你需要更改格式字符串或修改日期字符串使它们匹配。

解释

问题

当Carbon的createFromFormat函数接收到与传递的格式字符串不匹配的日期字符串时,就会出现此错误。更准确地说,这来自于DateTime::createFromFormat函数,因为Carbon只是调用该函数:

public static function createFromFormat($format, $time, $tz = null)
{
    if ($tz !== null) {
        $dt = parent::createFromFormat($format, $time, static::safeCreateDateTimeZone($tz));
    } else {
        $dt = parent::createFromFormat($format, $time); // Where the error happens.
    }

    if ($dt instanceof DateTime) {
        return static::instance($dt);
    }

    $errors = static::getLastErrors();
    throw new InvalidArgumentException(implode(PHP_EOL, $errors['errors'])); // Where the exception was thrown.
}

数据不足

如果您的日期字符串“长度”比格式字符串短,就像在这种情况下:

Carbon::createFromFormat('Y-m-d H:i:s', '2017-01-04 00:52');

Carbon会抛出以下异常:

在Carbon.php的第425行抛出无效参数异常:
数据缺失

数据过多

如果您的日期字符串比格式字符串“长”,就像在这种情况下一样:

 Carbon::createFromFormat('Y-m-d H:i', '2017-01-02 00:27:00');

Carbon会抛出以下异常:

在Carbon.php的第425行发生InvalidArgumentException:
尾随数据

内部原理

根据变换器文档,默认日期格式为:'Y-m-d H:i:s'。日期处理发生在模型的asDateTime函数中。在最后一个条件中,调用了getDateFormat函数,这就是自定义格式的来源。默认格式在数据库的Grammar类中定义

解决方案

您必须确保日期字符串与格式字符串匹配。

更改格式字符串

您可以像这样覆盖默认的格式字符串:

class Event extends Model {
    protected $dateFormat = 'Y-m-d H:i';
}

这种方法存在两个问题:
  • 这将应用于模型中定义的$dates数组中的每个字段。
  • 您必须以这种格式存储数据在数据库中。

编辑和格式化日期字符串

我推荐的解决方案是,日期格式应保持默认的'Y-m-d H:i:s',并且您应该完成日期中缺失的部分,例如:

public function store(Request $request) {
    $requestData = $request->all();
    $requestData['start_time'] .= ':00';
    $requestData['end_time'] .= ':00';
    $event = new Event($requestData);
    $event->save();
}

当您想使用日期时,应对其进行格式化:
public function show(Request request, $eventId) {
    $event = Event::findOrFail($eventId);
    $startTime = $event->start_time->format('Y-m-d H:i');
    $endTime = $event->end_time->format('Y-m-d H:i');
}

当然,这些字段应该被改变为日期:
class Event extends Model {
    protected $dates = [
        'start_time',
        'end_time',
        'created_at',
        'updated_at',
        'deleted_at',
    ];
}

7
好的回答。如此高质量的回答。我忍不住要评论这个无生产力的评论。 :) - Bhargav Nanekalva
我有同样的问题,这个解决方案对我没有帮助,你能看一下吗? - user9025311
这对于日期和时间很好,但对于仅限日期的字段来说有些麻烦。在这些字段上添加时间是没有意义的,它们也不能以这种方式存储。然而,在命名上存在很大的歧义,因为它们在最真实的意义上是“日期”。 - Jonas D.
当我使用Postgresql时,有时会保存一些时间值,没有毫秒部分(当它只是零的时候)。然后日期格式将始终出现错误。所以最后,我只能使用特定的访问器来修复该字段。但是这种解决方案忽略了原始数据格式。 - mytharcher
答案很完美,但是根据Laravel的文档,我认为这不应该是必需的: 当一个列被认为是日期时,你可以将它的值设置为UNIX时间戳、日期字符串(Y-m-d)、日期时间字符串或DateTime/Carbon实例。日期的值将被正确转换并存储在你的数据库中 请参见此处。现实情况是,它不按照文档工作,我们必须采取像这样的hack方法。 - Karsai Péter

6

4
你可以像Christian所说,在模型中设置$dateFormat,但如果你不想将updated_at和created_at字段隐含到操作中,你可以使用事件在保存到数据库之前“修正”datetime对象。

这里有官方文档:https://laravel.com/docs/5.2/eloquent#events


接受这个选项,因为它给了我更多的选择,完全忽略了$dateFormat选项。 - Hardist

2

0

对我来说,问题出在位于供应商(vendor\laravel\framework\src\Illuminate\Database\Query\Grammars\SqlServerGrammar.php)中的 SQLServerGrammar。 SQLServerGrammar 的默认格式为 Y-m-d H:i:s.v

我们扩展了该类并移除了 .v


0
请确保您的数据库中没有省略"created_at"或"updated_at"字段的某些行,这是必需的;如果是这种情况,请删除具有这些空字段的记录或输入有效时间戳格式的值,例如'2018-09-01 15:18:53'。

0

这是一种可能性

您需要检查结果数据的列。如果您的列名“created_at”或“updated_at”为空,则会出现此错误。

如何解决? 首先,您需要使用Laravel Carbon将数据存储在这两个列中。 例如:

$user = new User();
$user->created_at = Carbon::now()->setTime(0,0)->format('Y-m-d H:i:s');
$user->updated_at = Carbon::now()->setTime(0,0)->format('Y-m-d H:i:s');
$user->save();

就这样,希望它能够正常工作

编程愉快....


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接