没有周末的日差
Posted
技术标签:
【中文标题】没有周末的日差【英文标题】:Day difference without weekends 【发布时间】:2012-09-04 03:10:59 【问题描述】:我想计算用户输入的总天差
例如当用户输入时
start_date = 2012-09-06
和 end-date = 2012-09-11
现在我正在使用此代码来查找差异
$count = abs(strtotime($start_date) - strtotime($end_date));
$day = $count+86400;
$total = floor($day/(60*60*24));
total 的结果是 6。但问题是我不想包括周末(周六和周日)的日子
2012-09-06
2012-09-07
2012-09-08 Saturday
2012-09-09 Sunday
2012-09-10
2012-09-11
所以结果将是 4
----更新---
我有一个包含日期的表格,表格名称是假期日期
例如表格包含2012-09-07
所以,总天数将是 3,因为它没有计算假期日期
如何将输入的日期等同于表格中的日期?
【问题讨论】:
所以现在任何正在寻找这个 Carbon API 的人都有这个carbon.nesbot.com/docs/#api-difference 【参考方案1】:很容易使用我的最爱:DateTime
、DateInterval
和 DatePeriod
$start = new DateTime('2012-09-06');
$end = new DateTime('2012-09-11');
// otherwise the end date is excluded (bug?)
$end->modify('+1 day');
$interval = $end->diff($start);
// total days
$days = $interval->days;
// create an iterateable period of date (P1D equates to 1 day)
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
// best stored as array, so you can add more than one
$holidays = array('2012-09-07');
foreach($period as $dt)
$curr = $dt->format('D');
// substract if Saturday or Sunday
if ($curr == 'Sat' || $curr == 'Sun')
$days--;
// (optional) for the updated question
elseif (in_array($dt->format('Y-m-d'), $holidays))
$days--;
echo $days; // 4
【讨论】:
我不能使用 diff 和 DatePeriod....因为 php 版本 5.2....我有办法更改 diff...但我不明白如何更改日期期... ..你能帮我吗? @Belajar 您可以通过每次迭代增加一天来模仿这种行为。请参阅此论坛帖子以供参考:DateInterval & DatePeriod alternative for PHP 5.2x 我相信在这段代码中,如果假期是周六或周日,那么会被扣除两次。应该有一个“elseif”。 我从最终计数中又删除了一天。我通过说直到今天(2016 年 9 月 1 日)还有多少个工作日来测试它,结果是 1。好吧,没有!因此,我可以多休息 1 天。 非常感谢@dan-lee。它像魔术一样工作。我所做的只是将它复制并粘贴到我的代码中,它工作了!!!【参考方案2】:在我的情况下,我需要与 OP 相同的答案,但想要更小的答案。 @Bojan 的答案有效,但我不喜欢它不适用于 DateTime
对象,需要使用时间戳,并且正在与 strings
进行比较,而不是与实际对象本身进行比较(感觉很hacky)......这是一个他的答案的修订版。
function getWeekdayDifference(\DateTime $startDate, \DateTime $endDate)
$days = 0;
while($startDate->diff($endDate)->days > 0)
$days += $startDate->format('N') < 6 ? 1 : 0;
$startDate = $startDate->add(new \DateInterval("P1D"));
return $days;
如果您希望这包括开始和结束日期,请根据@xzdead 的评论:
function getWeekdayDifference(\DateTime $startDate, \DateTime $endDate)
$isWeekday = function (\DateTime $date)
return $date->format('N') < 6;
;
$days = $isWeekday($endDate) ? 1 : 0;
while($startDate->diff($endDate)->days > 0)
$days += $isWeekday($startDate) ? 1 : 0;
$startDate = $startDate->add(new \DateInterval("P1D"));
return $days;
【讨论】:
【参考方案3】:在没有周末的情况下获得差异的最简单和最快的方法是使用Carbon 库。
这是一个如何使用它的示例:
<?php
$from = Carbon\Carbon::parse('2016-05-21 22:00:00');
$to = Carbon\Carbon::parse('2016-05-21 22:00:00');
echo $to->diffInWeekdays($from);
【讨论】:
【参考方案4】:使用DateTime
:
$datetime1 = new DateTime('2012-09-06');
$datetime2 = new DateTime('2012-09-11');
$interval = $datetime1->diff($datetime2);
$woweekends = 0;
for($i=0; $i<=$interval->d; $i++)
$datetime1->modify('+1 day');
$weekday = $datetime1->format('w');
if($weekday !== "0" && $weekday !== "6") // 0 for Sunday and 6 for Saturday
$woweekends++;
echo $woweekends." days without weekend";
// 4 days without weekends
【讨论】:
应该是$interval->days
而不是$interval->d
【参考方案5】:
date('N') 获取星期几(1 - 星期一,7 - 星期日)
$start = strtotime('2012-08-06');
$end = strtotime('2012-09-06');
$count = 0;
while(date('Y-m-d', $start) < date('Y-m-d', $end))
$count += date('N', $start) < 6 ? 1 : 0;
$start = strtotime("+1 day", $start);
echo $count;
【讨论】:
不能完全工作。试试这些日期: $start = strtotime('2015-12-01'); $end = strtotime('2015-12-15');结果为 10 天,但必须为 11。为什么,范围内的第一个星期一 (2015-12-07) 没有以正确的方式计算。也许是一个错误?【参考方案6】:这是@dan-lee函数的改进版:
function get_total_days($start, $end, $holidays = [], $weekends = ['Sat', 'Sun'])
$start = new \DateTime($start);
$end = new \DateTime($end);
$end->modify('+1 day');
$total_days = $end->diff($start)->days;
$period = new \DatePeriod($start, new \DateInterval('P1D'), $end);
foreach($period as $dt)
if (in_array($dt->format('D'), $weekends) || in_array($dt->format('Y-m-d'), $holidays))
$total_days--;
return $total_days;
使用它:
$start = '2021-06-12';
$end = '2021-06-17';
$holidays = ['2021-06-15'];
echo get_total_days($start, $end, $holidays); // Result: 3
【讨论】:
【参考方案7】:看看这篇文章: Calculate business days
(在您的情况下,您可以省略“假期”部分,因为您只是在工作/工作日之后)
<?php
//The function returns the no. of business days between two dates
function getWorkingDays($startDate,$endDate)
// do strtotime calculations just once
$endDate = strtotime($endDate);
$startDate = strtotime($startDate);
//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
$days = ($endDate - $startDate) / 86400 + 1;
$no_full_weeks = floor($days / 7);
$no_remaining_days = fmod($days, 7);
//It will return 1 if it's Monday,.. ,7 for Sunday
$the_first_day_of_week = date("N", $startDate);
$the_last_day_of_week = date("N", $endDate);
//---->The two can be equal in leap years when february has 29 days, the equal sign is added here
//In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
if ($the_first_day_of_week <= $the_last_day_of_week)
if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;
if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;
else
// (edit by Tokes to fix an edge case where the start day was a Sunday
// and the end day was NOT a Saturday)
// the day of the week for start is later than the day of the week for end
if ($the_first_day_of_week == 7)
// if the start date is a Sunday, then we definitely subtract 1 day
$no_remaining_days--;
if ($the_last_day_of_week == 6)
// if the end date is a Saturday, then we subtract another day
$no_remaining_days--;
else
// the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
// so we skip an entire weekend and subtract 2 days
$no_remaining_days -= 2;
//The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
$workingDays = $no_full_weeks * 5;
if ($no_remaining_days > 0 )
$workingDays += $no_remaining_days;
return $workingDays;
// This will return 4
echo getWorkingDays("2012-09-06","2012-09-11");
?>
【讨论】:
【参考方案8】:如果您不需要全天但需要准确的秒数,请尝试使用此代码。这接受 unix 时间戳作为输入。
function timeDifferenceWithoutWeekends($from, $to)
$start = new DateTime("@".$from);
$current = clone $start;
$end = new DateTime("@".$to);
$sum = 0;
while ($current<$end)
$endSlice = clone $current;
$endSlice->setTime(0,0,0);
$endSlice->modify('+1 day');
if ($endSlice>$end)
$endSlice= clone $end;
$seconds = $endSlice->getTimestamp()-$current->getTimestamp();
$currentDay = $current->format("D");
if ($currentDay != 'Sat' && $currentDay != 'Sun')
$sum+=$seconds;
$current = $endSlice;
return $sum;
【讨论】:
【参考方案9】:/**
* Getting the Weekdays count[ Excludes : Weekends]
*
* @param type $fromDateTimestamp
* @param type $toDateTimestamp
* @return int
*/
public static function getWeekDaysCount($fromDateTimestamp = null, $toDateTimestamp=null)
$startDateString = date('Y-m-d', $fromDateTimestamp);
$timestampTomorrow = strtotime('+1 day', $toDateTimestamp);
$endDateString = date("Y-m-d", $timestampTomorrow);
$objStartDate = new \DateTime($startDateString); //intialize start date
$objEndDate = new \DateTime($endDateString); //initialize end date
$interval = new \DateInterval('P1D'); // set the interval as 1 day
$dateRange = new \DatePeriod($objStartDate, $interval, $objEndDate);
$count = 0;
foreach ($dateRange as $eachDate)
if ( $eachDate->format("w") != 6
&& $eachDate->format("w") != 0
)
++$count;
return $count;
【讨论】:
【参考方案10】:请查看这个精确的 php 函数返回天数,不包括周末。
function Count_Days_Without_Weekends($start, $end)
$days_diff = floor(((abs(strtotime($end) - strtotime($start))) / (60*60*24)));
$run_days=0;
for($i=0; $i<=$days_diff; $i++)
$newdays = $i-$days_diff;
$futuredate = strtotime("$newdays days");
$mydate = date("F d, Y", $futuredate);
$today = date("D", strtotime($mydate));
if(($today != "Sat") && ($today != "Sun"))
$run_days++;
return $run_days;
试试看,真的很管用..
【讨论】:
【参考方案11】:使用 Carbon\Caborn 的一个非常简单的解决方案
这是从控制器存储函数调用的存储库文件
<?php
namespace App\Repositories\Leave;
use App\Models\Holiday;
use App\Models\LeaveApplication;
use App\Repositories\BaseRepository;
use Carbon\Carbon;
class LeaveApplicationRepository extends BaseRepository
protected $holiday;
public function __construct(LeaveApplication $model, Holiday $holiday)
parent::__construct($model);
$this->holiday = $holiday;
/**
* Get all authenticated user leave
*/
public function getUserLeave($id)
return $this->model->where('employee_id',$id)->with(['leave_type','approver'])->get();
/**
* @param array $request
*/
public function create($request)
$request['total_days'] = $this->getTotalDays($request['start_date'],$request['end_date']);
return $this->model->create($request->only('send_to','leave_type_id','start_date','end_date','desc','total_days'));
/**
* Get total leave days
*/
private function getTotalDays($startDate, $endDate)
$holidays = $this->getHolidays(); //Get all public holidays
$leaveDays = 0; //Declare values which hold leave days
//Format the dates
$startDate = Carbon::createFromFormat('Y-m-d',$startDate);
$endEnd = Carbon::createFromFormat('Y-m-d',$endDate);
//Check user dates
for($date = $startDate; $date <= $endEnd; $date->modify('+1 day'))
if (!$date->isWeekend() && !in_array($date,$holidays))
$leaveDays++; //Increment days if not weekend and public holidays
return $leaveDays; //return total days
/**
* Get Current Year Public Holidays
*/
private function getHolidays()
$holidays = array();
$dates = $this->holiday->select('date')->where('active',1)->get();
foreach ($dates as $date)
$holidays[]=Carbon::createFromFormat('Y-m-d',$date->date);
return $holidays;
控制器函数接收用户输入请求并在调用存储库函数之前进行验证
<?php
namespace App\Http\Controllers\Leave;
use App\Http\Controllers\AuthController;
use App\Http\Requests\Leave\LeaveApplicationRequest;
use App\Repositories\Leave\LeaveApplicationRepository;
use Exception;
class LeaveApplicationController extends AuthController
protected $leaveApplication;
/**
* LeaveApplicationsController constructor.
*/
public function __construct(LeaveApplicationRepository $leaveApplication)
parent::__construct();
$this->leaveApplication = $leaveApplication;
/**
* Store a newly created resource in storage.
*/
public function store(LeaveApplicationRequest $request)
try
$this->leaveApplication->create($request);
return $this->successRoute('leaveApplications.index','Leave Applied');
catch (Exception $e)
return $this->errorWithInput($request);
【讨论】:
【参考方案12】:这是计算两个日期之间的工作日的替代方法,并且还使用来自http://pear.php.net/package/Date_Holidays 的 Pear 的 Date_Holidays 排除美国假期。
$start_date 和 $end_date 应该是 DateTime 对象(您可以使用new DateTime('@'.$timestamp)
将时间戳转换为 DateTime 对象)。
<?php
function business_days($start_date, $end_date)
require_once 'Date/Holidays.php';
$dholidays = &Date_Holidays::factory('USA');
$days = 0;
$period = new DatePeriod($start_date, new DateInterval('P1D'), $end_date);
foreach($period as $dt)
$curr = $dt->format('D');
if($curr != 'Sat' && $curr != 'Sun' && !$dholidays->isHoliday($dt->format('Y-m-d')))
$days++;
return $days;
?>
【讨论】:
以上是关于没有周末的日差的主要内容,如果未能解决你的问题,请参考以下文章