具有一小时间隔和动态间隔的动态时隙

Dynamic Timeslots with one hour intervals and dynamic intervals too

我有入住时间和退房时间,我已经有了动态时间段的代码,但我正在为动态时间间隔而苦苦挣扎。下面的代码 -

$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 

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

不识人,脑子坏了


更好的解释

我有3个table,分别是-

出勤率,事件一,事件二

现在每个table-

中的相关列

出席人数

|____checkout_time(碳时间戳)

|____created_at(碳时间戳)

事件一

|____event_start(碳时间戳)

|____event_duration(整数(秒))

活动二

|____event_time(碳时间戳)

|____event_end_time(碳时间戳)

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

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

现在一切都清楚了吗?

如果我没理解错的话,你可以像下面这样操作。 (值得注意的是我对代码做了一些其他的改进)

$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() 方法只是所有模型上的静态方法,return 查询生成器的新实例。您的原始代码在内部调用了它,但我更喜欢使用它,因为它可以很好地启动它,因此我可以逐行格式化它。

whereNotNull()

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

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

在你的原始代码中你是:

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

只用碳法就容易多了diffInHours()

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

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

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

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

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

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

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

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

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

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

举个例子。

但它仍然需要对边缘情况进行一些检查,例如每小时一次的日期(事件、签到、签出)(例如: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());

将输出: