我有一个函数返回两个日期之间的差别,但是我需要计算出的差异在工作时间, 周一假设至周五(上午9:00至下午5:30):
//DATE DIFF FUNCTION
// Set timezone
date_default_timezone_set("GMT");
// Time format is UNIX timestamp or
// PHP strtotime compatible strings
function dateDiff($time1, $time2, $precision = 6) {
// If not numeric then convert texts to unix timestamps
if (!is_int($time1)) {
$time1 = strtotime($time1);
}
if (!is_int($time2)) {
$time2 = strtotime($time2);
}
// If time1 is bigger than time2
// Then swap time1 and time2
if ($time1 > $time2) {
$ttime = $time1;
$time1 = $time2;
$time2 = $ttime;
}
// Set up intervals and diffs arrays
$intervals = array('year','month','day','hour','minute','second');
$diffs = array();
// Loop thru all intervals
foreach ($intervals as $interval) {
// Set default diff to 0
$diffs[$interval] = 0;
// Create temp time from time1 and interval
$ttime = strtotime("+1 " . $interval, $time1);
// Loop until temp time is smaller than time2
while ($time2 >= $ttime) {
$time1 = $ttime;
$diffs[$interval]++;
// Create new temp time from time1 and interval
$ttime = strtotime("+1 " . $interval, $time1);
}
}
$count = 0;
$times = array();
// Loop thru all diffs
foreach ($diffs as $interval => $value) {
// Break if we have needed precission
if ($count >= $precision) {
break;
}
// Add value and interval
// if value is bigger than 0
if ($value > 0) {
// Add s if value is not 1
if ($value != 1) {
$interval .= "s";
}
// Add value and interval to times array
$times[] = $value . " " . $interval;
$count++;
}
}
// Return string with times
return implode(", ", $times);
}
日期1 = 2012-03-24 3点58分58秒
日期2 = 2012-03-22 11点29分16秒
是否有这样做,即一个简单的方法 - 计算的工作时间在一个星期的比例和使用上述功能划分的区别 - 我有这个想法发挥各地,并得到了一些很奇怪的数字...
还是有更好的办法....?
本例中使用PHP的内置的DateTime类来完成的日期数学。 我是如何处理,这是通过计算两个日期之间的完全工作天数开始,然后乘上8(见注)。 然后,它会在部分天工作时间,并将它们添加到工作总时间。 谈到这为功能将是相当简单的事情。
笔记:
- 没有考虑时间戳考虑。 不过你已经知道该怎么做。
- 不处理假期。 (这可以通过使用假期的阵列,并且将其添加到你滤除周六和周日很容易地添加)。
- 需要PHP 5.3.6+
- 假定一个8小时工作日。 如果员工不采取午餐变化
$hours = $days * 8;
至$hours = $days * 8.5;
。
<?php
// Initial datetimes
$date1 = new DateTime('2012-03-22 11:29:16');
$date2 = new DateTime('2012-03-24 03:58:58');
// Set first datetime to midnight of next day
$start = clone $date1;
$start->modify('+1 day');
$start->modify('midnight');
// Set second datetime to midnight of that day
$end = clone $date2;
$end->modify('midnight');
// Count the number of full days between both dates
$days = 0;
// Loop through each day between two dates
$interval = new DateInterval('P1D');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt) {
// If it is a weekend don't count it
if (!in_array($dt->format('l'), array('Saturday', 'Sunday'))) {
$days++;
}
}
// Assume 8 hour workdays
$hours = $days * 8;
// Get the number of hours worked on the first day
$date1->modify('5:30 PM');
$diff = $date1->diff($start);
$hours += $diff->h;
// Get the number of hours worked the second day
$date1->modify('8 AM');
$diff = $date2->diff($end);
$hours += $diff->h;
echo $hours;
看到它在行动
参考
- DateTime类
- DatePeriod类
- DateInterval类
下面是我想出。
我的解决办法检查原始日期的开始和结束时间,并根据每天的工作实际开始和结束时间(如果原来的开始时间是工作的开标时间之前,将其设置为后者)对其进行调整。
完成此操作后双方开始和结束时间,时间比较检索DateInterval
差异,计算总天数,小时等的日期范围,然后检查是否有周末两天,如果发现,一个总天减少从差异。
最后,作为评论的时间进行计算。 :)
干杯约翰对振奋一些该解决方案,特别是中DatePeriod
检查周末。
黄金星的人谁打破了这一点; 我会很高兴,如果有人发现了一个漏洞更新!
金星对自己说,我把它弄坏了! 是啊,周末仍越野车(尝试开始于上周六下午4点和下午1点结束星期一)。 我会征服你,工作时间的问题!
忍者编辑#2:我觉得我通过恢复的开始和结束时间到最近各工作日,如果他们落在周末照顾周末的bug。 测试日期范围屈指可数后取得了良好的效果(并开始在同一个周末barfs结束,如预期)。 我并不完全相信这是优化/简单,因为它可能是,但至少它现在更好的作品。
// Settings
$workStartHour = 9;
$workStartMin = 0;
$workEndHour = 17;
$workEndMin = 30;
$workdayHours = 8.5;
$weekends = ['Saturday', 'Sunday'];
$hours = 0;
// Original start and end times, and their clones that we'll modify.
$originalStart = new DateTime('2012-03-22 11:29:16');
$start = clone $originalStart;
// Starting on a weekend? Skip to a weekday.
while (in_array($start->format('l'), $weekends))
{
$start->modify('midnight tomorrow');
}
$originalEnd = new DateTime('2012-03-24 03:58:58');
$end = clone $originalEnd;
// Ending on a weekend? Go back to a weekday.
while (in_array($end->format('l'), $weekends))
{
$end->modify('-1 day')->setTime(23, 59);
}
// Is the start date after the end date? Might happen if start and end
// are on the same weekend (whoops).
if ($start > $end) throw new Exception('Start date is AFTER end date!');
// Are the times outside of normal work hours? If so, adjust.
$startAdj = clone $start;
if ($start < $startAdj->setTime($workStartHour, $workStartMin))
{
// Start is earlier; adjust to real start time.
$start = $startAdj;
}
else if ($start > $startAdj->setTime($workEndHour, $workEndMin))
{
// Start is after close of that day, move to tomorrow.
$start = $startAdj->setTime($workStartHour, $workStartMin)->modify('+1 day');
}
$endAdj = clone $end;
if ($end > $endAdj->setTime($workEndHour, $workEndMin))
{
// End is after; adjust to real end time.
$end = $endAdj;
}
else if ($end < $endAdj->setTime($workStartHour, $workStartMin))
{
// End is before start of that day, move to day before.
$end = $endAdj->setTime($workEndHour, $workEndMin)->modify('-1 day');
}
// Calculate the difference between our modified days.
$diff = $start->diff($end);
// Go through each day using the original values, so we can check for weekends.
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
foreach ($period as $day)
{
// If it's a weekend day, take it out of our total days in the diff.
if (in_array($day->format('l'), ['Saturday', 'Sunday'])) $diff->d--;
}
// Calculate! Days * Hours in a day + hours + minutes converted to hours.
$hours = ($diff->d * $workdayHours) + $diff->h + round($diff->i / 60, 2);
正如那句老话:“如果你想要的东西做对自己做”。 不是说这是最佳的,但它的ATLEAST返回的时间正确的金额给我。
function biss_hours($start, $end){
$startDate = new DateTime($start);
$endDate = new DateTime($end);
$periodInterval = new DateInterval( "PT1H" );
$period = new DatePeriod( $startDate, $periodInterval, $endDate );
$count = 0;
foreach($period as $date){
$startofday = clone $date;
$startofday->setTime(8,30);
$endofday = clone $date;
$endofday->setTime(17,30);
if($date > $startofday && $date <= $endofday && !in_array($date->format('l'), array('Sunday','Saturday'))){
$count++;
}
}
//Get seconds of Start time
$start_d = date("Y-m-d H:00:00", strtotime($start));
$start_d_seconds = strtotime($start_d);
$start_t_seconds = strtotime($start);
$start_seconds = $start_t_seconds - $start_d_seconds;
//Get seconds of End time
$end_d = date("Y-m-d H:00:00", strtotime($end));
$end_d_seconds = strtotime($end_d);
$end_t_seconds = strtotime($end);
$end_seconds = $end_t_seconds - $end_d_seconds;
$diff = $end_seconds-$start_seconds;
if($diff!=0):
$count--;
endif;
$total_min_sec = date('i:s',$diff);
return $count .":".$total_min_sec;
}
$start = '2014-06-23 12:30:00';
$end = '2014-06-27 15:45:00';
$go = biss_hours($start,$end);
echo $go;