I have a list of baby logs, and I've tried to auto calculate the time difference between the previous ones, subtract the feeding interval.
feedingInterval = 3h
Ex.
If I fed my baby at 5PM, and if I fed him again at 7:50 PM.
He's early 10 mins.
More than 3h, it's green(+) means the baby sleep well
Less than 3h, it's red(-) means the baby will feed early, and we shouldn't do too often.
I have this block of code
if($baby){
$dateTime = new \DateTime();
$date = $dateTime->format('Y-m-d');
if(Request::get('date') != null) {
$date = Request::get('date');
}
$yesterday = date('Y-m-d',strtotime("-1 days"));
$logFromYesterday = BabyLog::where('type', $type)->whereDate('created_at', $yesterday )->orderBy('created_at', 'desc')->where('babyId',$baby->id)->get()->first();
$babyLogs = BabyLog::where('type', $type)->whereDate('created_at', '=', $date)->orderBy('created_at', 'desc')->where('babyId',$baby->id)->get();
$logDetail = [];
$lastFeedStatus = 'n/a';
foreach ($babyLogs as $i => $feed) {
$id = $babyLogs[$i]->id;
$t1 = $babyLogs[$i]->updated_at;
if($i >= (count($babyLogs)-1)){
if($logFromYesterday){
$t2 = $logFromYesterday->updated_at;
} else {
$t2 = $date.' 00:00:00';
}
}else {
$t2 = $babyLogs[$i+1]->updated_at;
}
// dd($t1,$t2);//
$diffTime = abs(strtotime($t1) - strtotime($t2));
$diffTime = $diffTime / ( 60 * 60 );
if($type == 'feed'){
$diffTime = $diffTime - $baby->feedingInterval;
$diffTime = round($diffTime,2);
$diffTime = $diffTime*60;
$logDetailStatus = ($diffTime>0) ? "+" : "-";
$diffTime = $logDetailStatus.str_replace('-', '', $diffTime). "m ";
} else {
$diffTime = round($diffTime,2);
$diffTime = $diffTime*60;
$diffTime = str_replace('0', '',date('H\h', mktime(0,$diffTime))) . '';
}
$logDetail[$i]['id'] = $id;
$logDetail[$i]['msg'] = $diffTime;
if($i == 0){
$lastFeedStatus = $diffTime;
}
}
return $logDetail;
}
I want to round to minutes only.
Ex. 10.2 m --> 10 m
I tried
round($diffTime,2);
to
round($diffTime,1);
I got
Ex. 10.2 m --> 12 m
Try using number_format():
<?php
echo number_format("100.1234");
echo number_format("100.50");
echo number_format("100.890");
?>
Result will be:
100
101
101
Related
Have time slots which are in ascending order:
// 1st slot
$timeslot[] = '07:00-08:00';
// total = 1 hr
// 2nd slot
$timeslot[] = '07:15-07:30'; // not considered since it lies between the first slot ie 7 to 8
// total = 1 hr
// 3rd slot
$timeslot[] = '07:30-08:30'; // 1 hr of the first slot + remaining 30 minutes of this slot = 1:30 hrs
// total = 1:30 hrs
// 4rth slot
$timeslot[] = '10:45-11:45'; // 1:30 hrs + 1 hr
// total = 2:30 hrs
so far i have tried like this but no hope; what i'm trying to get is the time passed between the slots. for example we have two time slots 07:00-08:00 and 07:30-08:30, the time travelled in these two time slot is 1:30 hours. so something like this i'm calculating. My code goes like this:-
function addtimespend($dumparray = '', $i, $diff)
{
$arr1 = explode("-", $dumparray[0]);
if (isset($dumparray[$i])) {
$arr2 = explode("-", $dumparray[$i]);
if (strtotime($arr2[1]) > strtotime($arr1[1]) && strtotime($arr2[0]) < strtotime($arr1[1])) {
$diff = $diff + (strtotime($arr2[1]) - strtotime($arr1[1]));
return $diff;
} else {
$diff = $diff + (strtotime($arr1[1]) - strtotime($arr1[0]));
}
$i++;
return addtimespend($dumparray, $i, $diff);
} else {
$diff = $diff + (strtotime($arr1[1]) - strtotime($arr1[0]));
return $diff;
}
}
$flag = $diff = 0;
$diff = addtimespend($event, 1, 0);
function convertToHoursMins($time, $format = '%02d:%02d')
{
if ($time < 1) {
return;
}
$hours = floor($time / 60);
$minutes = ($time % 60);
return sprintf($format, $hours, $minutes);
}
echo convertToHoursMins($diff / 60, '%02d hours %02d minutes');
<?php
$timeslot = [];
$timeslot[] = '07:00-08:00';
$timeslot[] = '07:15-07:30';
$timeslot[] = '07:30-08:30';
$timeslot[] = '10:45-11:45';
$min_time = -1;
$max_time = -1;
$total_minutes = 0;
foreach($timeslot as $slot){
list($start_time,$end_time) = explode("-",$slot);
$start_time = explode(":",$start_time);
$start_time = intval($start_time[0]) * 60 + intval($start_time[1]); // converting to minutes
$end_time = explode(":",$end_time);
$end_time = intval($end_time[0]) * 60 + intval($end_time[1]);// converting to minutes
if($min_time == -1){// or max time for that matter (just basic initialization of these 2 variables)
$min_time = $start_time;
$max_time = $end_time;
$total_minutes += $max_time - $min_time;
}else{
if($start_time >= $max_time) $total_minutes += $end_time - $start_time;
else if($start_time < $max_time && $end_time > $max_time) $total_minutes += $end_time - $max_time;
$min_time = min($min_time,$start_time);
$max_time = max($max_time,$end_time);
}
}
echo intval($total_minutes / 60),":",($total_minutes % 60)," hrs";
Demo: https://3v4l.org/nvjDq
Algorithm:
Since your data is sorted according to start times, we can just keep track of min and max times of timeslots.
For simplicity, we can convert the timeslot in minutes.
We add to our total only under these 2 conditions:
If the current slot collides with the time range we maintain.
If the current slot is completely out of bounds of the current time range.
In the end, we print the answer in hours format.
i made a little script to calculate your timeslots, which works also fine with UNSORTED timeslots:
<?php
$timeslots = [];
// 2nd slot
$timeslots[] = '07:00-08:00'; // not considered since it lies between the first slot ie 7 to 8 // total = 1 hr
$timeslots[] = '07:15-08:00'; // 1st slot
$timeslots[] = '07:30-08:00'; // 1st slot
$timeslots[] = '07:30-08:30'; // 3rd slot
$timeslots[] = '07:45-08:45'; // 1 hr of the first slot + remaining 30 minutes of this slot = 1:30 hrs // total = 1:30 hrs // remove duplicate one's
// // 4rth slot
$timeslots[] = '10:45-11:45';
$test = new test;
foreach ($timeslots as $timeslot) {
$test->checkInBetween($timeslot);
}
$totalDiff = 0;
foreach ($test->sequences as $key => $sequence) {
$sequenceDifference = strtotime($sequence['latestEnd']) - strtotime($sequence['earliestStart']);
$totalDiff += $sequenceDifference;
}
echo "<pre>";
var_dump($totalDiff);
die();
class test {
public $sequences = [
0 => [
'earliestStart' => '',
'latestEnd' => '',
],
];
public function checkInBetween($timeslot) {
$exploded = explode('-', $timeslot);
$isEarliest = false;
$isLatest = false;
$isBetweenFirst = false;
$isBetweenSecond = false;
$sequenceFound = false;
foreach ($this->sequences as $key => $sequence) {
// Check if the first number is the earliest
if (($exploded[0] < $sequence['earliestStart'])) {
$isEarliest = true;
}
// Check if the last number is the latest
if (($exploded[1] > $sequence['latestEnd'])) {
$isLatest = true;
}
if ($exploded[0] > $sequence['earliestStart'] && $exploded[0] < $sequence['latestEnd']) {
$isEarliest = false;
$isBetweenFirst = true;
}
if ($exploded[1] > $sequence['earliestStart'] && $exploded[1] < $sequence['latestEnd']) {
$isLatest = false;
$isBetweenSecond = true;
}
if (($isEarliest && $isLatest) || ($isEarliest && $isBetweenSecond)) {
$this->sequences[$key]['earliestStart'] = $exploded[0];
$sequenceFound = true;
}
if (($isEarliest && $isLatest) || ($isLatest && $isBetweenFirst)) {
$this->sequences[$key]['latestEnd'] = $exploded[1];
$sequenceFound = true;
}
}
if (!$sequenceFound) {
$this->sequences[] = [
'earliestStart' => $exploded[0],
'latestEnd' => $exploded[1],
];
}
}
}
Feel free to ask questions. Please mind that the output (totalDiff) contains seconds!
A few words to the script:
The script checks every value inside the timeslots array and tries to merge it into a sequence if the starting time is in between an existing sequence or the ending time is in between an existing sequence. If one of those conditions are met, the sequence is updated with the new value.
If none of those conditions are met, the script adds a new sequence, as the current values are not matching any existing conditions.
After iterating every value inside the timeslot, the sequences will be calculated in terms of difference in seconds, which will be added to the totalDiff.
This code will work if the time slots are shorted by their start time in ascending order.
<?php
$timeslots[] = '07:00-08:00';
$timeslots[] = '07:15-07:30';
$timeslots[] = '07:30-08:30';
$timeslots[] = '10:45-11:45';
$slots=array();
foreach($timeslots as $timeslot){
$timeslot=explode("-",$timeslot);
$start=toMinutes($timeslot[0]);
$end=toMinutes($timeslot[1]);
$slots[]=["start"=>$start,"end"=>$end];
$starts[]=$start;
$ends[]=$end;
}
function toMinutes($time){
$arr= explode(":",$time);
return ($arr[0] * 60) + $arr[1];
}
function toTime($minutes){
return floor($minutes / 60) .":". $minutes % 60;
}
function totalGapMinutes($slots){
$count=count($slots);
$i=0;
$gap=0;
for($i; $i<$count-1; $i++){
if($slots[$i]['end']<$slots[$i+1]['start']){
$gap+=$slots[$i+1]['start']-$slots[$i]['end'];
}
}
return $gap;
}
var_dump(toTime(max($ends)-min($starts) - totalGapMinutes($slots)));
I have project built using laravel and a I have to build a function that counts all the complete quarters that are in the selected date range - the dates used are inserted via input.
Here are the quarters(i used numerical representations for the months)
01 - 03 first quarter
04 - 06 second quarter
07 - 09 third quarter
10 - 12 forth quarter
I would really appreciate your help,because I've been at it for an entire day now and basically have nothing to show for it,i thing I've been trying so hard i'm actually at the point where i'm so tired, i can t think straight.
I do have some code but it;s worthless, because it doesn't work, and any kind of idea or snippet of code is welcomed.
Thanks for your help in advance.
I managed to do this using multiple functions; basically, if this is needed for chart statistics, then a more specific approach might be the case.
I have done this in Laravel with timestamp dates as input (this code can be adapted for getting semesters also :) , it works and is already tested):
public static function getQuartersBetween($start_ts, $end_ts)
{
$quarters = [];
$months_per_year = [];
$years = self::getYearsBetween($start_ts, $end_ts);
$months = self::getMonthsBetween($start_ts, $end_ts);
foreach ($years as $year) {
foreach ($months as $month) {
if ($year->format('Y') == $month->format('Y')) {
$months_per_year[$year->format('Y')][] = $month;
}
}
}
foreach ($months_per_year as $year => $months) {
$january = new Date('01-01-' . $year);
$march = new Date('01-03-' . $year);
$april = new Date('01-04-' . $year);
$june = new Date('01-06-' . $year);
$july = new Date('01-07-' . $year);
$september = new Date('01-09-' . $year);
$october = new Date('01-10-' . $year);
$december = new Date('01-12-' . $year);
if (in_array($january, $months) && in_array($march, $months)) {
$quarter_per_year['label'] = 'T1 / ' . $year;
$quarter_per_year['start_day'] = $january->startOfMonth();
$quarter_per_year['end_day'] = $march->endOfMonth()->endOfDay();
array_push($quarters, $quarter_per_year);
}
if (in_array($april, $months) && in_array($june, $months)) {
$quarter_per_year['label'] = 'T2 / ' . $year;
$quarter_per_year['start_day'] = $april->startOfMonth();
$quarter_per_year['end_day'] = $june->endOfMonth()->endOfDay();
array_push($quarters, $quarter_per_year);
}
if (in_array($july, $months) && in_array($september, $months)) {
$quarter_per_year['label'] = 'T3 / ' . $year;
$quarter_per_year['start_day'] = $july->startOfMonth();
$quarter_per_year['end_day'] = $september->endOfMonth()->endOfDay();
array_push($quarters, $quarter_per_year);
}
if (in_array($october, $months) && in_array($december, $months)) {
$quarter_per_year['label'] = 'T4 / ' . $year;
$quarter_per_year['start_day'] = $october->startOfMonth();
$quarter_per_year['end_day'] = $december->endOfMonth()->endOfDay();
array_push($quarters, $quarter_per_year);
}
}
return $quarters;
}
and getting the years between:
public static function getYearsBetween($start_ts, $end_ts, $full_period = false)
{
$return_data = [];
$current = mktime(0, 0, 0, date('m', $start_ts), date('d', $start_ts), date('Y', $start_ts));
while ($current < $end_ts) {
$temp_date = $current;
$year = new Date($temp_date);
$return_data[] = $year;
$current = strtotime("+1 year", $current); // add a year
}
if ($full_period) {
$return_data[] = $end_ts;
}
return $return_data;
}
, also getting the months needed
public static function getMonthsBetween($start_ts, $end_ts, $full_period = false)
{
$return_data = $month_list = [];
$current = mktime(0, 0, 0, date('m', $start_ts), date('d', $start_ts), date('Y', $start_ts));
while ($current <= $end_ts) {
$temp_date = $current;
$date = new Date($temp_date);
$month_list[] = $date;
$current = strtotime("+1 month", $current); // add a month
}
$start_date_last_month = new Date(array_first($month_list));
$start_date_last_month = $start_date_last_month->startOfMonth()->format('m-d');
$temp_end_date = new Date($start_ts);
$temp_end_date = $temp_end_date->format('m-d');
if ($start_date_last_month < $temp_end_date) {
array_shift($month_list);
}
$end_date_last_month = new Date(end($month_list));
$current_day_month = $end_date_last_month->endOfMonth()->format('m-d');
$temp_end_date = new Date($end_ts);
$end_day_of_month = $temp_end_date->format('m-d');
if ($end_day_of_month < $current_day_month) {
array_pop($month_list);
}
if (count($month_list) == 0) {
$month_list[] = $end_date_last_month->subMonth();
}
$return_data = $month_list;
if ($full_period) {
$return_data[] = $end_ts;
}
return $return_data;
}
You can do something like in this example:
$February = 2;
$October = 10;
$completedQuarters = ceil($October/3) - ceil($February/3); // = 3
What about the quarter in which the date range starts, should it also count? If it should only count if it begins in the first month of a quarter you can check for it like this:
$completedQuarters = ceil($October/3) - ceil($February/3) -1; // = 2
if($February-1%3 == 0) $completedQuarters += 1;
You´re description is not very clear, let me know if that´s what you had in mind.
Not sure if the following is what you are meaning but might be useful
$date_start='2015/03/12';
$date_end='2017/11/14';
$timezone=new DateTimeZone('Europe/London');
$start=new DateTime( $date_start, $timezone );
$end=new DateTime( $date_end, $timezone );
$difference = $end->diff( $start );
$months = ( ( $difference->format('%y') * 12 ) + $difference->format('%m') );
$quarters = intval( $months / 3 );
printf( 'Quarters between %s and %s is %d covering %d months', $start->format('l, jS F Y'), $end->format('l, jS F Y'), $quarters, $months );
/*
This will output
----------------
Quarters between Thursday, 12th March 2015 and Tuesday, 14th November 2017 is 10 covering 32 months
*/
Something like this in the function and you should be set.
use Carbon\Carbon;
$first = Carbon::parse('2012-1-1'); //first param
$second = Carbon::parse('2014-9-15'); //second param
$fY = $first->year; //2012
$fQ = $first->quarter; //1
$sY = $second->year; //2014
$sQ = $second->quarter; //3
$n = 0; //the number of quarters we have counted
$i = 0; //an iterator we will use to determine if we are in the first year
for ($y=$fY; $y < $sY; $y++, $i++) { //for each year less than the second year (if any)
$s = ($i > 0) ? 1 : $fQ; //determine the starting quarter
for ($q=$s; $q <= 4; $q++) { //for each quarter
$n++; //count it
}
}
if ($sY > $fY) { //if both dates are not in the same year
$n = $n + $sQ; //total is the number of quarters we've counted plus the second quarter value
} else {
for ($q=$fQ; $q <= $sQ; $q++) { //for each quarter between the first quarter and second
$n++; //count it
}
}
print $n; //the value to return (11)
Let's say that I have two dates:
$initialDate = '08/10/2015 09:30:24 am';
$finalDate = '15/10/2015 15:47:38 pm';
$holiday = '12/10/2015';
I have to consider the hour of these days.
Hours to consider : 8 hours per day;
Start : 8 pm
End: 18 pm (24 hours format )
Lunch break start: 12:00 pm
Lunch break end: 14:00 pm
Example 1 : From 08/10/2015 10:00:00 to 09/10/2015 17:00:00 results 13 working hours. ( excludes lunch break )
Example 2 : From 08/10/2015 14:00:00 to 09/10/2015 18:00:00 results 12 working hours. ( Do not exclude 2 hours from begin date, because starts after 14:00 pm, lunch break )
Example 3 : From 08/10/2015 16:00:00 to 09/10/2015 18:00:00 results 10 working hours. ( Do not exclude 2 hours from begin date, because starts after 14:00 pmm lunch break )
Exampld 4 : From 08/10/2015 08:00:00 to 09/10/2015 11:00:00 results 14 working hours. ( Exclude 2 hours from begin date, and do not exclude 2 hours from end date, because isn't after 14:00 pm )
And I have to calculate the working hours and working days between those two dates, excluding weekends and Holidays, how can I do that ? I'm using PHP.
PS: I Already have something, but without lunch break... I made a research here on StackOverFlow.
Code:
function get_workdays($dataInicial,$dataFinal){
// arrays
$days_array = array();
$skipdays = array("Saturday", "Sunday");
$skipdates = get_feriados();
// other variables
$i = 0;
$current = $dataInicial;
if($current == $dataFinal) // same dates
{
$timestamp = strtotime($dataInicial);
if (!in_array(date("l", $timestamp), $skipdays)&&!in_array(date("Y-m-d", $timestamp), $skipdates)) {
$days_array[] = date("Y-m-d",$timestamp);
}
}
elseif($current < $dataFinal) // different dates
{
while ($current < $dataFinal) {
$timestamp = strtotime($dataInicial." +".$i." day");
if (!in_array(date("l", $timestamp), $skipdays)&&!in_array(date("Y-m-d", $timestamp), $skipdates)) {
$days_array[] = date("Y-m-d",$timestamp);
}
$current = date("Y-m-d",$timestamp);
$i++;
}
}
return $days_array;
}
function get_feriados(){
$dateAno = Date('Y');
$days_array = array(
$dateAno.'-10-12', // Padroeira do Brasil/ Dias das Crianças
$dateAno.'-11-02', // Finados
$dateAno.'-12-25' // Finados
);
return $days_array;
}
date_default_timezone_set('America/Sao_Paulo');
$dateAno = Date('Y');
$dataInicial = Date('08/10/2015 H:i');
$dataFinal = Date('13/10/2015 H:i');
// timestamps
$from_timestamp = strtotime(str_replace('/', '-', $dataInicial));
$to_timestamp = strtotime(str_replace('/', '-', $dataFinal));
// work day seconds
$workday_start_hour = 9;
$workday_end_hour = 17;
$workday_seconds = ($workday_end_hour - $workday_start_hour)*3600;
// work days beetwen dates, minus 1 day
$from_date = date('Y-m-d',$from_timestamp);
$to_date = date('Y-m-d',$to_timestamp);
$workdays_number = count(get_workdays($from_date,$to_date))-1;
$workdays_number = $workdays_number<0 ? 0 : $workdays_number;
// start and end time
$start_time_in_seconds = date("H",$from_timestamp)*3600+date("i",$from_timestamp)*60;
$end_time_in_seconds = date("H",$to_timestamp)*3600+date("i",$to_timestamp)*60;
// final calculations
$working_hours = ($workdays_number * $workday_seconds + $end_time_in_seconds - $start_time_in_seconds) / 86400 * 24;
print_r('<br/> Horas úteis '.$working_hours);
}
But don't consider two hours of break lunch. Can somebody please help me ?
If you use PHP 5.3 or higher, you can do this:
$datefrom = DateTime::createFromFormat('d/m/Y', '08/10/2015');
$dateto = DateTime::createFromFormat('d/m/Y', '15/10/2015');
$interval = $datefrom->diff($dateto);
$days = intval($interval->format('%a'));
Also you can remove holidays with if:
if ($datetime1->getTimestamp() < $holiday->getTimestamp() and $datetime2->getTimestamp() > $holiday->getTimestamp()) $days--;
Calculate hours between two days:
$datefrom = DateTime::createFromFormat('d/m/Y H:i:s', '08/10/2015 12:51:34');
$dateto = DateTime::createFromFormat('d/m/Y H:i:s', '15/10/2015 13:14:56');
$hours = intval($interval->format('%a')) * 24 + $interval->format('%h');
You can calculate hours of launches sum and then subtract it.
How to ignore weekends or calculate ignore days:
while($dateto->getTimestamp() > $datefrom->getTimestamp()) {
if (in_array($datefrom->format('w'), array('0','6'))) $ignore_days += 1;
$datefrom->modify('+1 day');
}
I expect this will do all you want. But I changed the datetime format as follows. Check it. Used less comments. If any query, please ask. Holidays are arrays, add and remove as required.
Times between 12:00 - 14:00 is handled.
Times below 08:00 is handled.
Times above 18:00 is handled.
<?php
$initialDate = '2015-10-13 08:15:00'; //start date and time in YMD format
$finalDate = '2015-10-14 11:00:00'; //end date and time in YMD format
$holiday = array('2015-10-12'); //holidays as array
$noofholiday = sizeof($holiday); //no of total holidays
//create all required date time objects
$firstdate = DateTime::createFromFormat('Y-m-d H:i:s',$initialDate);
$lastdate = DateTime::createFromFormat('Y-m-d H:i:s',$finalDate);
if($lastdate > $firstdate)
{
$first = $firstdate->format('Y-m-d');
$first = DateTime::createFromFormat('Y-m-d H:i:s',$first." 00:00:00" );
$last = $lastdate->format('Y-m-d');
$last = DateTime::createFromFormat('Y-m-d H:i:s',$last." 23:59:59" );
$workhours = 0; //working hours
for ($i = $first;$i<=$last;$i->modify('+1 day') )
{
$holiday = false;
for($k=0;$k<$noofholiday;$k++) //excluding holidays
{
if($i == $holiday[$k])
{
$holiday = true;
break;
} }
$day = $i->format('l');
if($day === 'Saturday' || $day === 'Sunday') //excluding saturday, sunday
$holiday = true;
if(!$holiday)
{
$ii = $i ->format('Y-m-d');
$f = $firstdate->format('Y-m-d');
$l = $lastdate->format('Y-m-d');
if($l ==$f )
$workhours +=sameday($firstdate,$lastdate);
else if( $ii===$f)
$workhours +=firstday($firstdate);
else if ($l ===$ii)
$workhours +=lastday($lastdate);
else
$workhours +=8;
}
}
echo $workhours; //echo the hours
}
else
echo "lastdate less than first date";
function sameday($firstdate,$lastdate)
{
$fmin = $firstdate->format('i');
$fhour = $firstdate->format('H');
$lmin = $lastdate->format('i');
$lhour = $lastdate->format('H');
if($fhour >=12 && $fhour <14)
$fhour = 14;
if($fhour <8)
$fhour =8;
if($fhour >=18)
$fhour =18;
if($lhour<8)
$lhour=8;
if($lhour>=12 && $lhour<14)
$lhour = 14;
if($lhour>=18)
$lhour = 18;
if($lmin == 0)
$min = ((60-$fmin)/60)-1;
else
$min = ($lmin-$fmin)/60;
return $lhour-$fhour + $min;
}
function firstday($firstdate) //calculation of hours of first day
{
$stmin = $firstdate->format('i');
$sthour = $firstdate->format('H');
if($sthour<8) //time before morning 8
$lochour = 8;
else if($sthour>18)
$lochour = 0;
else if($sthour >=12 && $sthour<14)
$lochour = 4;
else
{
$lochour = 18-$sthour;
if($sthour<=14)
$lochour-=2;
if($stmin == 0)
$locmin =0;
else
$locmin = 1-( (60-$stmin)/60); //in hours
$lochour -= $locmin;
}
return $lochour;
}
function lastday($lastdate) //calculation of hours of last day
{
$stmin = $lastdate->format('i');
$sthour = $lastdate->format('H');
if($sthour>=18) //time after 18
$lochour = 8;
else if($sthour<8) //time before morning 8
$lochour = 0;
else if($sthour >=12 && $sthour<14)
$lochour = 4;
else
{
$lochour = $sthour - 8;
$locmin = $stmin/60; //in hours
if($sthour>14)
$lochour-=2;
$lochour += $locmin;
}
return $lochour;
}
?>
Check the bellow code, that will return the number of Working days
function number_of_working_days($from, $to) {
$workingDays = [1, 2, 3, 4, 5];// date format = (1 = Monday,2 = Tue, ...)
$holidayDays = ['*-12-25', '*-02-14', '2015-12-23']; // variable and fixed holidays
$from = new DateTime($from);
$to = new DateTime($to);
$to->modify('+1 day');
$interval = new DateInterval('P1D');
$days = new DatePeriod($from, $interval, $to);
$no_of_working_days = 0;
foreach ($days as $day) {
if (!in_array($day->format('N'), $workingDays)||in_array($day->format('Y-m-d'), $holidayDays)||in_array($day->format('*-m-d'), $holidayDays)) {continue;}
$working_days++;
}
return $no_of_working_days;
}
echo number_of_working_days('2015-12-01', '2015-09-10');
From that you can easily calculate the Number of Working Hours.
I have created for you this nice class you can use. It requires the nesbot/carbon library (http://carbon.nesbot.com/) and you use it like so:
$calc = new HoursCalculator(
Carbon::createFromFormat("Y-m-d H:i", "2015-10-7 09:00"),
Carbon::createFromFormat("Y-m-d H:i", "2015-10-14 18:00"),
[
"2015-10-13"
]
);
echo $calc->getHours();
Heres the class:
class HoursCalculator {
const LUNCH_HOURS = 2;
protected $start;
protected $end;
protected $holidays;
protected $hoursTotal;
public function __construct(Carbon $start, Carbon $end, $holidays = [])
{
$this->start = $start;
$this->end = $end;
$this->holidays = $holidays;
}
public function getHours()
{
$dayHours = $this->getHoursInADay();
return $this->calculateHours($dayHours);
}
protected function getHoursInADay()
{
$start = $this->start;
$end = Carbon::createFromFormat("Y-m-d H:i", $this->start->format("Y-m-d") . " " . $this->end->format("H:i"));
return $start->diffInHours($end) - self::LUNCH_HOURS;
}
protected function getStartDate()
{
return $this->start->format('Y-m-d');
}
protected function calculateHours($hoursInDay)
{
$start = $this->start->copy()->startOfDay();
$end = $this->end->copy()->endOfDay();
$days = 0;
while($start->lt($end)) {
if (!$this->isHoliday($start) && !$this->isWeekend($start)) {
$days++;
}
$start->addDay(1);
}
return $days * $hoursInDay;
}
protected function isHoliday(Carbon $date)
{
$date->startOfDay();
foreach($this->holidays as $holiday) {
$holiday = Carbon::createFromFormat("Y-m-d", $holiday)->startOfDay();
if ($date->eq($holiday)) {
return true;
}
}
return false;
}
protected function isWeekend(Carbon $date)
{
return $date->isWeekend();
}
}
Hope this helps!
This code is used to take values inputted from a form but this does not take a year entered as 0100 as 0100 but as 1915, this is then used with the JS seen in one of my other questions any help here would be very good, I think the issue is something to do where the year is taken but I just can't get this to work correctly. Is this a limitation of php?
<?php
$year = "";
$month = "";
$day = "";
if (isset($_GET['year']) && !empty($_GET['year'])) {
$year = $_GET['year'];
}
if (isset($_GET['month']) && !empty($_GET['month'])) {
$month = $_GET['month'];
$monthNumber = date('m', strtotime("$month 1 Y"));
}
if (isset($_GET['day']) && !empty($_GET['day'])) {
$day = $_GET['day'];
}
if ($year != "" && $monthNumber != "" && $day != "") {
$fullUrlDate = $year . "-" . $monthNumber . "-" . $day;
$urlDate = new DateTime(date($fullUrlDate));
$today = new DateTime(date("Y-m-d H:i:s"));
$interval = $urlDate->diff($today);
$gapYears = $interval->y;
$gapMonths = $interval->m;
$gapDays = $interval->d;
$gapDaysTotal = $interval->days;
$gapWeeksTotal = round($interval->days/7);
$gapHours = $interval->h;
$gapMinutes = $interval->i;
$gapSeconds = $interval->s;
if ($gapWeeksTotal == 1) {
$gapWeeksSuffix = "";
} else {
$gapWeeksSuffix = "s";
}
if ($gapDays == 1) {
$gapDaysSuffix = "";
} else {
$gapDaysSuffix = "s";
}
$ordinalSuffix = date("S", strtotime($fullUrlDate));
if (strtotime($fullUrlDate) < strtotime(date("Y-m-d H:i:s")) ) {
$dateInThePast = true;
} else {
$dateInThePast = false;
}
// Months gap
$monthsInterval = date_diff($urlDate, $today);
$monthsGap = $monthsInterval->m + ($monthsInterval->y * 12);
$gapMonthsSuffix = ($monthsGap == 1 ? "" : "s");
DateTime has no such limitation, but the date function you use to initialise it, does. You can use DateTime::setDate to set any year you want:
php > $a = new DateTime("2015-08-24");
php > echo $a->format(DateTime::ISO8601);
2015-08-24T00:00:00+0000
php > $a->setDate(90, 8, 24);
php > echo $a->format(DateTime::ISO8601);
0090-08-24T00:00:00+0000
php > $a->setDate(90090, 8, 24);
php > echo $a->format(DateTime::ISO8601);
90090-08-24T00:00:00+0000
How to convert military time like this?
07:03 --> 07:30
06:45 --> 07:00
07:36 --> 08:00
19:15 --> 19:30
18:35 --> 19:00
19:35 --> 20:00
Basically the thing is, if the time is in the interval of 30 mins, you will add up the remaining minutes to make it a whole time.
In my database, I have to compare time like this where:
function check_range($get_shift, $date, $time, $id, $mode) {
$sql = "SELECT * FROM tbl_employee WHERE id = '$id'";
$result = mysql_query($sql);
$row_check_range = mysql_fetch_assoc($result);
$getShift = $row_check_range['shift'];
$sql2 = "SELECT * FROM tbl_shift WHERE shift = '$getShift'";
$result2 = mysql_query($sql2);
$row_check_range2 = mysql_fetch_assoc($result2);
$getTimeShift = $row_check_range2['timeIn'];
$actual_time_in_mode = explode(':', $time); //split time into (e.g 07, 11)
if ($mode == 'AM') {
$time_in_actual = $actual_time_in_mode[0];
} else {
$time_in_actual = $actual_time_in_mode[0];
$time_shift = explode(':', $getTimeShift);
$getTimeShift = $time_shift[0] + 12; //convert to military time
}
$getTimeShift = mktime($getTimeShift);
$actual_in_mode = mktime($time);
if ($actual_in_mode > $getTimeShift) // LATE
{
return $date.' '.$time_in_actual.':30:00';
} else {
$time_in_actual += 1;
return $date.' '.$time_in_actual.':00:00';
}
}
Something like this should do.
list($hour, $minute) = explode(':', $time);
if ($minute > 30) {
$hour++;
$minute = 0;
} elseif ($minute > 0) {
$minute = 30;
}
if ($hour == 24) $hour = 0;
printf('%02d:%02d', $hour, $minute);
function military_time($x){
$y=split(':',$x);
$y[0] =(((int)$y[1]) >30) ? ((int)$y[0])+1 : $y[0];
$y[0] =((int) $y[0] == 24) ? '00':$y[0];
$y[0]=(strlen($y[0]) == 1) ? '0'.$y[0] : $y[0];
$y[1] =(((int)$y[1]) >30) ? '00':'30';
echo $y[0].':'.$y[1];
}
military_time('23:35');
Just add 30 minutes and then round the number DOWN to the closest :30 or :00.