Laravel Carbon - 计算数据库条目之间的时间差

3

我正在尝试计算两个日期时间之间的差异。

我有两个模型,taskstask_interactions,它们的关系如下:tasks包含多个task_interactions,而task_interactions属于tasks

用户可以将任务状态更改为以下之一:“进行中”,“已暂停”和“已完成”。用户在“进行中”和“已暂停”之间多次更改状态,但一旦完成,用户就无法再更改任务状态。

所有交互都保存在task_interactions表中,其中created_by为user_id,created_at为日期时间。该表具有以下列:id; task_id; status; comments; created_by; created_at

这是任务ID = 1的示例:

# id, task_id, status, comments, created_by, created_at
144, 1, In Progress, , 1, 2017-11-14 09:42:20
145, 1, Paused, , 1, 2017-11-14 09:45:53
146, 1, In Progress, , 1, 2017-11-14 09:46:57
147, 1, Paused, , 1, 2017-11-14 09:49:57
148, 1, In Progress, , 1, 2017-11-14 10:00:10
149, 1, Paused, , 1, 2017-11-14 10:06:25
150, 1, In Progress, , 1, 2017-11-14 10:07:26
151, 1, Paused, , 1, 2017-11-14 10:08:11
153, 1, Paused, , 1, 2017-11-14 11:27:04
154, 1, In Progress, , 1, 2017-11-14 11:27:21
155, 1, Paused, , 1, 2017-11-14 11:57:38

事实上,我需要确定在一个任务中花费的总时间,需要确定In ProgressPaused之间的时间。而PausedIn Progress之间的时间并不重要。
我正在苦恼这个问题。有人可以帮助我吗?
提前感谢。
还有一件事,我经验不太丰富,所以如果我的问题听起来有点愚蠢,请原谅。我认为我应该通过一个@foreach循环遍历所有task_interactions(其中task_id = X),这就是我所知道的。
如所请求,这里是我传递给视图的数据:
public function mytasks()
    {
        $users = User::all();
        $mytasks = Task::where('assigned_to','=', Auth::id())->where('status','!=','Finished')->get(); 
        $mytaskscount = Task::where('assigned_to','=', Auth::id())->count();
        $tasksinprogress = Task::where('status','=','In Progress')->where('assigned_to','=', Auth::id())->get();
        $tasksinprogresscount = Task::where('status','=','In Progress')->where('assigned_to','=', Auth::id())->count();
        $taskspaused = Task::where('status','=','Paused')->where('assigned_to','=', Auth::id())->get();
        $taskspausedcount = Task::where('status','=','Paused')->where('assigned_to','=', Auth::id())->count();
        $tasksfinished = Task::where('status','=','Finished')->where('assigned_to','=', Auth::id())->get();
        $tasksfinishedcount = Task::where('status','=','Finished')->where('assigned_to','=', Auth::id())->count();
        $tasktypes = Tasktype::all();
        $chapters = Chapter::all();

        return view('pages.tasks_my', compact('mytasks','tasktypes','chapters','tasksinprogress','taskspaused','tasksfinished','mytaskscount','tasksinprogresscount','taskspausedcount','tasksfinishedcount'));
    }

还有一件事,就是我目前所知道的

@foreach ($tasks as $task)
    @foreach ($task->interactions as $interactions)
{{ In here, every time my loop returns a status = "In progress" i should mark that time, and if that the next loop returns a "Paused", i should count the difference between these two. And sum all other equal cases in the loop. }}
    @endforeach
@endforeach

我真的不知道如何做到这一点


你能推动你的控制器吗? - Jems
我也想知道这个问题的答案。 - lewis4u
你个人负责让数据库查询处理这个吗?用 PHP 迭代结果是我想到的方法。 - Chay22
2个回答

1
这是严格的 Mysql 代码,但应该可以解决问题。你可以使用原始 SQL 指令直接在 Laravel 中调用它,或者你可能需要将其改写为 Laravel 代码。
select SEC_TO_TIME(
    sum( 
        timediff(
            if(task_end.created_at is null, 
               NOW(), 
               task_end.created_at), 
            task_start.created_at)))
from task_interactions task_start
left join task_interactions task_end
    ON task_end.task_id = task_start.task_id
    AND task_end.status IN ('Pause', 'Finished')
    AND task_end.created_at = (
        SELECT min(created_at)
        FROM task_interactions
        WHERE status = task_end.status
        AND created_at >= task_start.created_at
    )
WHERE task_start.task_id = 1
AND task_start.status = 'In Progress'

这就是我喜欢Laravel的主要原因... PHP和SQL的原始代码太丑陋难以阅读了... 如果你能花点时间将其转换为Laravel Eloquent,那就太好了。 - lewis4u
那么难读的是什么呢? 这是基本的SQL...你获取所有状态为'In Progress'的task_interactions;我称它们为task_start;然后我与具有相同task_id的其他任务进行左连接(并将其别名为task_end);对于该连接,我只想要已暂停或已完成的任务。此外 - 我想要在该结束中的第一个任务...Laravel很好,但如果您想使用Eloquent实现此目的,它仍然会很复杂。 Laravel是一个伟大的工具,但您仍然需要知道自己在做什么... - David Heremans
好吧 - 如果你想把那个负载放在数据库上,你的laravel逻辑同样会很“复杂”。另一种选择是在laravel中循环遍历记录,然后从那里开始... - David Heremans
抱歉 - 我用自己设置的表进行了测试,那个表使用了status_id,所以在发布之前我必须更新查询以反映您的实体和属性 - 我可能错过了那个;-) - David Heremans
只是想补充一下,当最后一个启动事件没有被暂停或完成事件跟随时,我会计算该最终步骤的持续时间直到NOW(),因为我认为这意味着任务目前正在进行中 :-) 如果这不是您的用例,您可能需要稍微修改一下。 - David Heremans
显示剩余2条评论

1
我建议使用David的答案。如果你不熟悉MySQL,可能需要这样做:
计算任务开始时间和暂停时间之间的差异:
$start = Carbon::parse($startTask->created_at);
$pause = Carbon::parse($endTask->created_at);

$diffInSeconds = $pause->diffInSeconds($start)

这将为您提供任务开始和暂停的总秒数差异。现在,您需要重复此方法,以获取任务再次开始和暂停时的数据。

这可能听起来有点奇怪,我理解你的方法,但我不知道如何将其放入foreach循环中。我经验不太丰富,通常我会在控制器中过滤所需的数据,然后在视图中处理该信息。我知道这是错误的。 - Marco Assunção
这很容易,因为您只需要将任务的所有暂停和启动条目作为数组获取。然后,您只需解析任务的启动条目即可。 - Raza Mehdi
我会尝试一下。非常感谢。 - Marco Assunção

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