我必须在工作时间内(周一至周五,上午 09:00 至下午 5:00)确定两个日期之间的持续时间,公共假期除外。 此外,我需要考虑业务间隔内的暂停。 我已经使用两个库成功处理了程序的初始部分:https://github.com/briannesbitt/Carbon和https://github.com/spatie/opening-hours现在我需要考虑考虑暂停时间。
下面是我的代码:
<?php
require 'opening-hours-master/vendor/autoload.php';
require 'carbon-master/vendor/autoload.php';
use Spatie\OpeningHours\OpeningHours;
use Carbon\CarbonInterval;
//Initiate the working hours and exlude public hollidays
$openingHours = OpeningHours::create([
'monday' => ['09:00-17:00'],
'tuesday' => ['09:00-17:00'],
'wednesday' => ['09:00-17:00'],
'thursday' => ['09:00-17:00'],
'friday' => ['09:00-17:00'],
'saturday' => [],
'sunday' => [],
'exceptions' => [
'2023-04-10' => [],
'2023-05-08' => [],
'2023-05-18' => [],
'2023-05-29' => [],
'2023-08-15' => [],
'2023-11-01' => [],
'2023-11-11' => [],
'07-14' => [], // Recurring on each 14 of July
'05-01' => [], // Recurring on each 1st of May
'01-01' => [], // Recurring on each 1st of January
'12-25' => [] // Recurring on each 25th of December
],
'timezone' => [
'input' => 'Europe/Paris',
'output' => 'Europe/Paris',
]
]);
//Date to calculate interval
$data = '[
{"entity_id":1,"start_phase":"2023-12-04T10:00:00.973+01:00","end_phase":"2023-12-05T12:01:01.973+01:00"},
{"entity_id":2,"start_phase":"2023-11-30T08:00:00.973+01:00","end_phase":"2023-12-07T16:31:01.973+01:00"},
{"entity_id":2,"start_phase":"2023-12-12T14:35:51.973+01:00","end_phase":"2023-12-12T16:31:01.973+01:00"}
]';
//Pause per entity_id
$data_pause = '[
{"entity_id":1,"start_pause":"2023-12-04T09:00:00.973+01:00","end_pause":"2023-12-04T12:00:00.973+01:00"},
{"entity_id":1,"start_pause":"2023-12-05T12:00:00.973+01:00","end_pause":"2023-12-05T14:00:00.973+01:00"}
]';
$report_data = json_decode($data, true);
$data_pause = json_decode($data_pause, true);
$result = array();
//Calculate the durations in business time between two dates
foreach($report_data as $row){
foreach($data_pause as $pause){
if($row['entity_id'] == $pause['entity_id']){
//TO DO
//Remove pause duration inside the specified start and end phases, ensuring it falls within the designated business time interval.
var_dump($pause);
}
}
$diffInSeconds = round($openingHours->diffInOpenSeconds(new DateTime($row['start_phase']), new DateTime($row['end_phase'])));
$human_readable = CarbonInterval::seconds($diffInSeconds)->cascade()->forHumans();
$data_diff[] = array(
'entity_id' => $row['entity_id'],
'start_phase' => $row['start_phase'],
'end_phase' => $row['end_phase'],
'difference_in_seconds' => $diffInSeconds,
'human_readable' => $human_readable
);
}
var_dump($data_diff);
输出:
array(3) {
[0]=>
array(5) {
["entity_id"]=>
int(1)
["start_phase"]=>
string(29) "2023-12-04T10:00:00.973+01:00"
["end_phase"]=>
string(29) "2023-12-05T12:01:01.973+01:00"
["difference_in_seconds"]=>
float(36061)
["human_readable"]=>
string(26) "10 hours 1 minute 1 second"
}
[1]=>
array(5) {
["entity_id"]=>
int(2)
["start_phase"]=>
string(29) "2023-11-30T08:00:00.973+01:00"
["end_phase"]=>
string(29) "2023-12-07T16:31:01.973+01:00"
["difference_in_seconds"]=>
float(171062)
["human_readable"]=>
string(35) "1 day 23 hours 31 minutes 2 seconds"
}
[2]=>
array(5) {
["entity_id"]=>
int(2)
["start_phase"]=>
string(29) "2023-12-12T14:35:51.973+01:00"
["end_phase"]=>
string(29) "2023-12-12T16:31:01.973+01:00"
["difference_in_seconds"]=>
float(6910)
["human_readable"]=>
string(28) "1 hour 55 minutes 10 seconds"
}
}
如何排除阶段间隔内和营业时间内的暂停时长? 我可以使用
$openingHours->isOpenAt($date);
来确定日期是否在工作时间内,但如何继续处理剩余的逻辑?
例如,对于entity_id 1,我有以下间隔:
暂停是:
第一次暂停:
第二次暂停:
在这种情况下,初始暂停需要排除10:00到12:00的时间,总共2小时。至于第二次暂停,我们应该扣除从12:00到12:01:01的持续时间,相当于1分1秒。因此,累计结果应为 8 小时。
或者简化一下:我必须计算开始阶段和结束阶段之间的持续时间(由绿线表示)。持续时间必须在指定的工作时间内(红线所示),并且暂停时间(蓝线所示)应排除在总体计算之外。
编辑:
用户可以在一天中进行多次暂停,并且暂停的启动由用户完成。暂停可以随时发生,并且可以在一天中多次进行。暂停时间可能随时出现,包括周末和公共假期。
使用
cmixin/business-time中的
\BusinessTime\Schedule
,您可以减去暂停时间的差异与营业时间的差异(不考虑毫秒,这是第二精确的):
$tz = 'Europe/Paris';
$schedule = \BusinessTime\Schedule::create([
'monday' => ['09:00-17:00'],
'tuesday' => ['09:00-17:00'],
'wednesday' => ['09:00-17:00'],
'thursday' => ['09:00-17:00'],
'friday' => ['09:00-17:00'],
'saturday' => [],
'sunday' => [],
'exceptions' => [
'2023-04-10' => [],
'2023-05-08' => [],
'2023-05-18' => [],
'2023-05-29' => [],
'2023-08-15' => [],
'2023-11-01' => [],
'2023-11-11' => [],
'07-14' => [], // Recurring on each 14 of July
'05-01' => [], // Recurring on each 1st of May
'01-01' => [], // Recurring on each 1st of January
'12-25' => [] // Recurring on each 25th of December
],
'timezone' => [
'input' => $tz,
'output' => $tz,
]
]);
$pauses = json_decode('[
{"entity_id":1,"start_pause":"2023-12-04T09:00:00.973+01:00","end_pause":"2023-12-04T12:00:00.973+01:00"},
{"entity_id":1,"start_pause":"2023-12-05T12:00:00.973+01:00","end_pause":"2023-12-05T14:00:00.973+01:00"}
]', true);
$exceptions = [];
foreach ($pauses as $pause) {
$start = \Carbon\CarbonImmutable::parse($pause['start_pause'])->tz($tz);
$end = \Carbon\CarbonImmutable::parse($pause['end_pause'])->tz($tz);
$days = $start->startOfDay()->daysUntil($end->startOfDay())->toArray();
$lastIndex = count($days) - 1;
foreach ($start->startOfDay()->daysUntil($end->startOfDay()) as $index => $date) {
$isFirstDay = ($index === 0);
$isLastDay = ($index === $lastIndex);
$day = $date->format('Y-m-d');
$exceptions[$day] ??= [];
$exceptions[$day][] = ($isFirstDay ? $start->format('H:i') : '00:00') . '-' .
($isLastDay ? $end->format('H:i') : '24:00');
}
}
$pauses = \BusinessTime\Schedule::create([
'exceptions' => $exceptions,
]);
$start = \Carbon\CarbonImmutable::parse('2023-12-04 10:00:00', $tz);
$end = \Carbon\CarbonImmutable::parse('2023-12-05 12:01:01', $tz);
$seconds = $schedule->diffInBusinessSeconds($start, $end) - $pauses->diffInBusinessSeconds($start, $end);
$diff = \Carbon\CarbonInterval::seconds($seconds)->cascade();
echo $diff->forHumans();