深入研究CarbonPeriod:为报告和日历制作日期时间数组

202 阅读4分钟

Laravel 开箱即用,带有著名的 Carbon 类,用于操作日期和时间。但是,有一个鲜为人知的 gem 称为 CarbonPeriod,它对于创建 DateTime 数组非常有用。这些数组通常用于填充报表和日历。在本指南中,我们深入探讨了 CarbonPeriod 的七个实际应用。

示例 1:生成时间间隔 — 按小时或分钟

假设您的目标是捕获正常工作时间的数组,由特定的开始和结束时间分隔,例如:

  • 9:00
  • 10:00
  • 11:00
  • 18:00

考虑这个示例 CarbonPeriod 片段:


use Carbon\Carbon;  
use Carbon\CarbonPeriod;  
$startPeriod = Carbon::parse('9:00');  
$endPeriod = Carbon::parse('18:00');  
$period = CarbonPeriod::create($startPeriod, '1 hour', $endPeriod);  
$hours = [];  
foreach ($period as $date) {  
$hours[] = $date->format('H:i');  
}  
// Resulting Array  
[  
"09:00", "10:00", "11:00", "12:00",  
"13:00", "14:00", "15:00", "16:00",  
"17:00", "18:00"  
]

可以观察到,CarbonPeriod 中的每个实体都是 Carbon 类的实例化,让您可以根据需要灵活地对其进行格式化。 如果你无法选择每小时间隔,则可以将间隔重新校准为更短的间隔,例如 45 分钟:

$period = CarbonPeriod::create($startPeriod, '45 minutes', $endPeriod);  
// Resulting Array  
[  
"09:00", "09:45", "10:30", "11:15", "12:00",  
"12:45", "13:30", "14:15", "15:00", "15:45",  
"16:30", "17:15", "18:00"  
]

您可能希望避开初始或结束条目。excludeStartDate 和 excludeEndDate 方法是为此量身定制的:

$period = CarbonPeriod::create($startPeriod, '45 minutes', $endPeriod)  
->excludeStartDate()  
->excludeEndDate();  
// Resulting Array  
[  
"09:45", "10:30", "11:15", "12:00",  
"12:45", "13:30", "14:15", "15:00",  
"15:45", "16:30", "17:15"  
]

想要更休闲的 12 小时格式吗?方法如下:

foreach ($period as $date) {  
$hours[] = $date->format('h:i A');  
}  
// Resulting Array  
[  
"09:45 AM", "10:30 AM", "11:15 AM", "12:00 PM",  
"12:45 PM", "01:30 PM", "02:15 PM", "03:00 PM",  
"03:45 PM", "04:30 PM", "05:15 PM"  
]

示例 2.按工作日划分的日期列表

假设您正在安排会议,并且您决定仅将会议安排在当月的星期一。这是使用 Laravel 的 Carbon 获取所有星期一的简单方法。

首先,包括 CarbonPeriod:

use Carbon\CarbonPeriod;

然后,获取月初和月末之间的日期。我们将筛选这些内容以仅包含星期一:


$period = CarbonPeriod::between(now()->startOfMonth(), now()->endOfMonth())  
->filter(function ($date) {  
return $date->isMonday();  
});  
$mondaysList = [];  
foreach ($period as $date) {  
$mondaysList[] = $date->format('M j, l, Y');  
}

结果将为你提供该月所有星期一的数组,例如:

[  
"Jul 3, Monday, 2023",  
"Jul 10, Monday, 2023",  
// ... and so on  
]

很酷的是 Carbon 提供了许多其他功能,而不仅仅是周一。您可以检查日期是否在工作日、周末、星期二等。以下是 Carbon 文档中的一些便捷功能:

$dt->isWeekday();  
$dt->isWeekend();  
// ... and many more!

例 3.周列表

假设您正在制定一个时间表或计划器,并且希望查看周数的细分。具体来说,您需要列出从 2023 年 6 月 15 日到 2023 年 7 月 15 日的几周。对于每周,您想知道周数以及开始日期和结束日期。 以下是使用 Laravel 的 Carbon 轻松执行此操作的方法:

首先,您需要包含 CarbonPeriod:

use Carbon\CarbonPeriod;

$period = CarbonPeriod::create('2023-06-15', '1 week', '2023-07-15');  
$weekList = [];  
$dateFormat = 'F j, Y';  
foreach ($period as $date) {  
$weekList[] = [  
'weekNumber' => $date->format('W'),  
'startDate' => $date->startOfWeek()->format($dateFormat),  
'endDate' => $date->endOfWeek()->format($dateFormat),  
];  
}

当你运行这个时,你会得到一个数组,里面有周数以及相应的开始和结束日期:


[ [ "weekNumber" => "24", "startDate" => "June 12, 2023", "endDate" => "June 18, 2023" ],  
[ "weekNumber" => "25", "startDate" => "June 19, 2023", "endDate" => "June 25, 2023" ],  
// ... and the list continues  
]

有了这个,您可以轻松查看指定时间段内哪些日期属于哪一周!

示例 4:根据 Order Date 创建 Pickup Date 列表

让我们简化方案:

假设您在线下订单。订单发货后,您有一个时间范围从邮局取货。最初,您有 5 天的期限,从订单发货之日起计算。

以下是在 Laravel 中设置的方法:

使用 shipped_at date 属性定义 Order 模型:

class Order extends Model  
{  
protected $fillable = ['shipped_at'];  
protected $casts = ['shipped_at' => 'date'];  
}

如果创建的订单具有发货日期(例如“2023–07–13”),我们可以获取接下来的 5 天作为可能的取货日期:

use App\Models\Order;  
$order = Order::create(['shipped_at' => '2023-07-13']);  
$pickupDates = $order->shipped_at->toPeriod($order->shipped_at->copy()->addDays(5), '1 day')  
->excludeEndDate();  
$dates = [];  
foreach ($pickupDates as $date) {  
$dates[] = $date->format('Y-m-d');  
}  
/

但是,如果有新政策,并且您只想在工作日取货,并且总共有 7 个工作日可供选择,该怎么办?方法如下: 将期限延长至自发货日期起 1 个月。

将总日期限制为 7 个。

$order = Order::create(['shipped_at' => '2023-07-13']);  
$pickupDates = $order->shipped_at->toPeriod($order->shipped_at->copy()->addMonth(), '1 day')  
->setRecurrences(7)  
->filter(function ($date) {  
return $date->isWeekday();  
});  
$dates = [];  
foreach ($pickupDates as $date) {  
$dates[] = $date->format('Y-m-d');  
}  
// This will give seven weekdays starting from '2023-07-13'

示例 5:跟踪与期间重叠的员工休假

假设您管理一个团队,并且想知道未来 30 天内哪些员工将休假。这将有助于分配任务并确保工作流程顺畅。 以下是一些员工及其休假日期的示例数据:

Employee::insert([  
['name' => 'Helmer Wilkinson', 'vacation_start' => '2023-01-01', 'vacation_end' => '2023-02-01'],  
['name' => 'Kaya Lowe', 'vacation_start' => '2023-07-05', 'vacation_end' => '2023-07-14'],  
['name' => 'Royal Yundt', 'vacation_start' => '2023-07-20', 'vacation_end' => '2023-08-01'],  
['name' => 'Willow Stark', 'vacation_start' => '2023-09-01', 'vacation_end' => '2023-09-15'],  
]);

现在,要找出这些员工中哪些员工的假期与从 “2023–07–13” 开始的接下来的 30 天重叠,我们可以执行以下操作: 定义我们感兴趣的 30 天期限。

检查员工的休假是否与此期间重叠。

$startOfCheck = Carbon::parse('2023-07-13');  
$checkPeriod = CarbonPeriod::create($startOfCheck, $startOfCheck->copy()->addMonth());  
$vacationingEmployees = [];  
Employee::get()->each(function ($employee) use ($checkPeriod, &$vacationingEmployees) {  
$employeeVacation = $employee->vacation_start->toPeriod($employee->vacation_end);  
  
if ($employeeVacation->overlaps($checkPeriod)) {  
$vacationingEmployees[] = $employee->name;  
}  
});  
// The result will show employees on vacation during this period:  
// ["Kaya Lowe", "Royal Yundt"]

示例 6:检查日期是否在给定时间段内

想知道哪些客户在某个月过生日吗?让我们使用一个易于理解的示例来分解它。

以下是我们的客户生日列表:

$customers = [  
['name' => 'Helmer Wilkinson', 'birthday' => '1982-09-27'],  
//... other customers ...  
['name' => 'Nyasia Senger', 'birthday' => '1993-07-06'],  
];

现在,如果您对哪些客户的生日(比如说 7 月)感到好奇,您可以执行以下操作:

定义月份的开始日期和结束日期。

浏览每个客户,看看他们的生日是否在该月。

use Carbon\Carbon;  
use Carbon\CarbonPeriod;  
  
// Setting the date range for July  
$monthRange = CarbonPeriod::create(now()->startOfMonth(), now()->endOfMonth());  
$celebrants = [];  
foreach ($customers as $customer) {  
$birthdayDate = Carbon::parse($customer['birthday']);  
  
// Adjusting the birthday year to the current year  
$thisYearBirthday = $birthdayDate->copy()->year(now()->format('Y'));  
// If the birthday is in July  
if ($monthRange->contains($thisYearBirthday)) {  
$celebrants[] = sprintf(  
'%s celebrates their %dth birthday this month.',  
$customer['name'],  
$birthdayDate->diffInYears($thisYearBirthday)  
);  
}  
}  
// The result for July will show:  
// ["Willow Stark celebrates their 35th birthday this month.", "Nyasia Senger celebrates their 30th birthday this month."]

示例 7:查找一天的空预约空档

假设您正在为特定日期的约会选择时间。为了帮助您选择,我们可以根据之前预订的时段显示哪些时间仍然开放。这是一个简单的细分: 我们有 2023 年 7 月 13 日的预订时段:

  • 10:00 AM 晚上 10:00
  • 2:00 PM 下午 2:00
  • 3:00 PM 下午 3:00

我们从上午 9:00 开始接受预约,并在当天下午 4:00 结束。因此,要找出可用的时段,我们可以将一整天的时间与预订的时间进行比较。

这是执行此操作的代码:

$bookedSlots = [  
'2023-07-13 10:00',  
'2023-07-13 14:00',  
'2023-07-13 15:00',  
];  
$startHour = Carbon::parse('2023-07-13 9:00');  
$endHour = Carbon::parse('2023-07-13 16:00');  
$allSlots = CarbonPeriod::create($startHour, '1 hour', $endHour)  
->filter(function ($time) use ($bookedSlots) {  
return ! in_array($time->format('Y-m-d H:i'), $bookedSlots);  
});  
$freeSlots = [];  
foreach ($allSlots as $slot) {  
$freeSlots[] = $slot->format('Y-m-d H:i');  
}

基于此,2023 年 7 月 13 日的预约免费时间为:

  • 9:00 AM 上午 9:00
  • 11:00 AM 上午 11:00
  • 12:00 PM 中午 12:00
  • 1:00 PM 下午 1:00
  • 4:00 PM 下午 4:00