没有周末的时差


Day difference without weekends

我想计算与用户输入的总时差

例如,当用户输入时

start_date = 2012-09-06end-date = 2012-09-11

目前,我正在使用此代码来查找差异

$count = abs(strtotime($start_date) - strtotime($end_date));
$day   = $count+86400;
$total = floor($day/(60*60*24));

合计结果为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,因为它没有计算假期日期

如何将输入的日期等同于表中的日期?

使用我最喜欢的:DateTimeDateIntervalDatePeriod 非常简单

$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

在我的情况下,我需要与OP相同的答案,但想要更小的答案@Bojan的答案有效,但我不喜欢它不适用于DateTime对象,需要使用时间戳,并且与strings而不是实际对象本身进行比较(这感觉很糟糕)。。。这是他答案的修订版。

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;
}

根据@xzead的评论,如果你希望这包括开始结束日期:

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;
}

在没有周末的情况下获得差异的最简单、最快的方法是使用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);

使用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

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;

这是@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

看看这篇文章:计算营业日

(在你的情况下,你可以省略"假期"部分,因为你只在工作/营业日之后)

<?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");
?>

如果您不需要全天,而是需要精确的秒数,请尝试以下代码。这接受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;
}
/**
 * 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;
}

请查看这个精确的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;
}

试试看,真的很管用。。

使用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);
        }
    }
}
  

这里有一个计算两个日期之间的工作日的替代方案,也不包括使用Pear的Date_holidayshttp://pear.php.net/package/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;
}
?>