【问题标题】:Dynamic Timeslots with one hour intervals and dynamic intervals too具有一小时间隔和动态间隔的动态时隙
【发布时间】:2020-01-30 10:47:56
【问题描述】:

我有签入时间和签出时间,我已经有了动态时间段的代码,但我正在努力处理动态时间间隔。下面的代码 -

$attendance = Attendance::where('user_id', '=', $request->user()->id)->latest()->first();
if(!is_null($attendance) && !is_null($attendance->checkout)){
    $created = (string) $attendance->created_at;
    $timing = array($created);
    $main_diff = Carbon::parse($created)->diffInSeconds($attendance->checkout, false);

    $modul = $main_diff % 3600;
    $main_amount = $main_diff - $modul;
    $count = $main_amount/3600;

    if($count > 1){
        for($x=0; $x <= count($timing); $x++){
            $diff = Carbon::parse($timing[$x])->diffInSeconds($attendance->checkout, false);
            if($diff > 0){
                if($x==0){
                    array_push($timing, (string) Carbon::parse($timing[$x])->minute(0)->second(0)->addHour());
                }
                elseif($x>0 and $x<$count){
                    $var = Carbon::parse($timing[$x]);
                    array_push($timing, (string) $var->addHour());
                }
                elseif($x == $count){
                    array_push($timing, (string) $attendance->checkout);
                }
            }
            else{
                break;
            }
        }

        $timings = [];
        $last;
        foreach($timing as $edit){
            if(isset($last)){
                $timings[] = $last.' - '.Carbon::parse($edit)->format('h:i');
            }
            $last = Carbon::parse($edit)->format('h:i');
        }
        $variable['data'] = $timings;
        return response(json_encode($variable), 200);
    }
}

以上代码的输出-

10:15-11:00
11:00-12:00
12:00-12:18

现在有两个不同的事件 EventFirst,EventSecond - 我想要的是将事件的时间整合到主要时间中。 例如 -

10:15 - 11:00
11:00 - EventFirst->start_time
EventFirst->start_time - EventFirst->end_time
EventFirst->end_time - Next Nearest Hour
Next Nearest Hour - EventSecond->start_time
EventSecond->start_time - EventSecond->end_time
EventSecond->end_time - Next Nearest Hour
Next Nearest Hour - Checkout Time 

问题在于事件不是实例,而是从数据库中检索的集合。 所以我要做的是首先从一个数组中的事件中获取所有时间,并检查每次迭代。

我不认识,我的大脑已经熟了。


更好的解释

我有三张表,分别是-

出席,活动一,活动二

现在每个表中的相关列-

出席

|____checkout_time(碳时间戳)

|____created_at(碳时间戳)

活动一

|____event_start(碳时间戳)

|____event_duration(整数(秒))

事件二

|____event_time(碳时间戳)

|____event_end_time(碳时间戳)

现在主要要求是,基于出勤表应该有每小时的间隔,除了签到和结帐时间,所以格式应该是 -

checkin - Next Nearest Hour (e.g - 10:15-11:00)
Last Hour - Next Hour (e.g 11:00-12:00, 12:00-13:00, etc)
Nearest Hour Before Checkout - checkout (e.g - 18:00-18:22) 

上面的输出已经实现了。

现在,当我必须在主时隙中添加其他两个事件的时隙时,问题就出现了。

所以格式现在变成了 -

checkin - Nearest Hour (e.g 11:34 - 12:00)
(Assuming Event one exists)
(case 1) -
If eventOne start and end is between Nearest Hour and the Next Hour add it in between
(e.g - 12:00-12:06, **12:06-12:54**, 12:54-13:00) 
(case 2) - 
If eventOne end crosses the Next Hour, unset the normal interval
(e.g - 12:00-12:06, **12:06-13:28**, 13:28-14:00)
Same Goes for eventTwo

现在一切都清楚了吗?

【问题讨论】:

  • 您能提供更多信息吗?一般来说,变量和代码不是很容易解释。

标签: php laravel loops object php-carbon


【解决方案1】:

我将首先为事件添加插槽。 然后检查,然后结帐。 并且,仅在最后,计算每小时的时隙。

我还没有完成你已经完成的每小时时段。

这是一个例子。

但它仍然需要检查边缘情况,例如每小时的日期(事件、签到、签出)(例如:11:00)

class ComputeTimeSlots {
    /** @var Carbon */
    public $checkin;
    /** @var Carbon */
    public $checkout;
    /** @var \Illuminate\Support\Collection */
    public $events;
    /** @var \Illuminate\Support\Collection */
    public $slots;

    /**
     * ComputeTimeSlots constructor.
     * @param $checkin
     * @param $checkout
     * @param \Illuminate\Support\Collection $events
     */
    public function __construct(Carbon $checkin, Carbon $checkout, Collection $events)
    {
        $this->checkin = $checkin;
        $this->checkout = $checkout;
        $this->events = $events;
        $this->slots = collect();
    }

    public function handle()
    {
        // First the Events
        foreach ($this->events as $event) {
            /** @var EEvent $event */
            $this->slots->push(
                new Slot($event->start, $event->end)
            );
        }

        // Then Checking
        /** @var Carbon $earliest_event_start_date */
        $earliest_event_start_date = $this->events->pluck('start')->sort()->first();
        $hourAfterCheckin = $this->checkin->clone()->setMinute(0)->addHour();

        if($hourAfterCheckin < $earliest_event_start_date) {
            $this->slots->push(
                new Slot($this->checkin, $hourAfterCheckin)
            );
        } else {
            $this->slots->push(
                new Slot($this->checkin, $earliest_event_start_date)
            );
            $hourAfterEvent = $earliest_event_start_date->clone()->setMinute(0)->addHour();
            $this->slots->push(
                new Slot($earliest_event_start_date, $hourAfterEvent)
            );
        }

        // Then Checkout
        /** @var Carbon $earliest_event_start_date */
        $last_event_end_date = $this->events->pluck('end')->sort()->last();
        $hourBeforeCheckout = $this->checkout->clone()->setMinute(0);

        if($hourBeforeCheckout > $last_event_end_date) {
            $this->slots->push(
                new Slot($hourBeforeCheckout, $this->checkout)
            );
        } else {
            $this->slots->push(
                new Slot($last_event_end_date, $this->checkout)
            );
            $hourBeforeEvent = $last_event_end_date->clone()->setMinute(0);
            $this->slots->push(
                new Slot($hourBeforeEvent, $last_event_end_date)
            );
        }
        $this->slots = $this->slots->sortBy('start');

        // Then compute hourly intervals

        return $this;
    }
}

class Slot {
    /** @var \Carbon\Carbon */
    public $start;
    /** @var \Carbon\Carbon */
    public $end;

    /**
     * Slot constructor.
     * @param \Carbon\Carbon $start
     * @param \Carbon\Carbon $end
     */
    public function __construct(Carbon $start, Carbon $end)
    {
        $this->start = $start;
        $this->end = $end;
    }

    public function toArray()
    {
        return "{$this->start->format('H:i')}-{$this->end->format('H:i')}";
    }
}

class EEvent extends Slot{}

例子:

$c1 = new ComputeTimeSlots(
    Carbon::parse('10:15'),
    Carbon::parse('18:22'),
    collect([
        new EEvent(Carbon::parse('12:06'), Carbon::parse('12:54')),
        new EEvent(Carbon::parse('13:06'), Carbon::parse('14:30'))
    ])
);

var_dump($c1->handle()->slots->map->toArray()->all());

将输出:

【讨论】:

    【解决方案2】:

    如果我理解正确,您可以执行以下操作。 (值得注意的是我对代码做了一些其他的改进)

    $attendance = Attendance::query()
        ->where('user_id', '=', auth()->id())
        ->whereNotNull('checkout')
        ->latest()
        ->first()
    
    if ($attendance !== null) {
        $hours     = $attendance->created_at->diffInHours($attendance->checkout);
        $createdAt = $attendance->created_at->copy()->startOfHour();
        $data      = [];
    
        if ($hours) {
            for($i = 0; $i < $hours; $i++) {
                $data[] = $createdAt->format('h:i') . ' - ' . $createdAt->addHour()->format('h:i');
            }
    
            return response()->json(compact('data'));
        }
    }
    

    我将分解下面代码中的更改。

    Attendance::query()
    

    query() 方法只是所有返回查询构建器新实例的模型上的静态方法。您的原始代码在内部调用了它,但我更喜欢使用它,因为它很好地开始了它,所以我可以逐行格式化它。

    whereNotNull()
    

    这是 Laravel 神奇的 where 方法之一,它将在 SQL 中添加一个 WHERE column NOT NULL 子句。这意味着您只会得到结帐列不为空的结果,这意味着您不需要检查它。

    $hours = $attendance->created_at->diffInHours($attendance->checkout);
    

    在您的原始代码中,您是:

    • 将碳实例转换为字符串,
    • 将其解析为碳实例
    • 以秒为单位计算差异
    • 计算小时数后剩余的秒数
    • 以秒为单位减去额外的秒数
    • 计算以秒为单位的小时数

    只使用碳法diffInHours()会容易得多。

    $createdAt = $attendance->created_at->copy()->startOfHour();
    

    Carbon 实例是可变的,因此您所做的每次修改都会更改对象,而不是返回一个新对象。这将创建一个副本并将时间戳设置为该小时的开始。

    下一位是最简单的。与其在循环中使用所有这些条件使事情变得过于复杂,不如根据小时差进行迭代更简单。

    $data[] = $createdAt->format('h:i') . ' - ' . $createdAt->addHour()->format('h:i');
    

    由于 Carbon 实例是可变的,该字符串的第二部分将增加一个小时,这意味着 carbon 实例在下次需要运行第一部分时更新。

    return response()->json(compact('data'));
    

    Laravel 响应有一个 json() 方法,允许您返回一个 json 响应而无需手动编码。

    希望我已经正确理解了这个问题,并希望这会有所帮助。

    【讨论】:

    • 感谢我将实现它们的代码改进,但这并不是我想要的。在帖子中添加了更多信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多