How can I create arrays of suitable candidates based on certain criteria? - php

So to brief you on the question:
I have a number of employees field in a form.
Employees have a salary and the day rate is calculated using (salary / 260)
Assuming employees work a fixed standard day
A task has a certain budget and a date range (start to end - e.g. 29/03/2017 to 31/03/2017)
A task also requires a fixed amount of employees (i.e. 3)
Now with those details in mind, I want to get a list of x employees (the fixed amount, i.e. 3) for which those employee's salaries match the date range of the project, and also slot into the budget.
I started doing this as follows, but have no idea how to continue further:
$employees = array(
0 => array(
'id' => 1,
'salary' => 22000
);
);
$startDate = some_date_here;
$endDate = some_date_here;
foreach($employees as &$user) {
$dayRate = round($user['salary'] / 260, 2);
}
EDIT:
Using http://php.net/manual/en/function.date-diff.php#117691, I managed to find the days between the dates of a project as follows (code update):
function days_diff($d1, $d2) {
$x1 = days($d1);
$x2 = days($d2);
if ($x1 && $x2) {
return abs($x1 - $x2);
}
}
function days($x) {
if (get_class($x) != 'DateTime') {
return false;
}
$y = $x->format('Y') - 1;
$days = $y * 365;
$z = (int)($y / 4);
$days += $z;
$z = (int)($y / 100);
$days -= $z;
$z = (int)($y / 400);
$days += $z;
$days += $x->format('z');
return $days;
}
$startDate = DateTime::createFromFormat('Y-m-d', $startDate);
$endDate = DateTime::createFromFormat('Y-m-d', $endDate);
$projectDays = days_diff($startDate, $endDate);

I think you can do this by the following code.
$startDate = some_date_here;
$endDate = some_date_here;
$noOfDays = calculate_using_end-start;
$employeeRate = [];
$noOfEmployeesRequired = 3;
foreach($employees as $index=>$user) {
$dayRate = round($user['salary'] / 260, 2);
$totalRate = $dayRate*$noOfDays;
$employeeRate[$user['id']] = $totalRate;
}
Now I have all employees Cost hence i sort it and find the cheapest solution
sort($employeeRate);
$output = array();
$counter = 0;
foreach($employeeRate as $id=>$emp) {
array_push($output, $id);
$counter++;
if($counter == $noOfEmployeesRequired) {
break;
}
}

Related

How to calculate the time passed in an array of time slots in PHP

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

Counting the (year)quarters between two dates

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)

Correct way to make a schedule

I've been debating whether to use Date functions or just whether there is a cleaner way to make an array of a given day's minutes at the moment my code reads like this;
function emptySchedule()
{
$emptySchedule = [];
for ($h = 0; $h < 24; ++$h) {
for ($m = 0; $m < 60; ++$m) {
$emptySchedule[str_pad($h, 2, '0', STR_PAD_LEFT).':'.str_pad($m, 2, '0', STR_PAD_LEFT)] = [];
}
}
return $emptySchedule;
}
But it just feels dirty, is there a better way to achieve the same result or maybe a better way to handle the minutes in the day with a date object or even better a globally accepted correct way? I'd prefer not to use a package, but if there is a good one I'm open to it.
EDIT; for some context, I will be putting arrays into each minute of the day.
EDIT2: for the purpose of what this will be used for there is no need for any input, my final function was;
public function emptySchedule()
{
$startDate = date_create("today"); //Any start date works
$endDate = date_create("tomorrow"); //Any end date works
$step = new \DateInterval("PT1M"); //1 minute, can change
$date = $startDate;
$times = [];
while ($date <= $endDate) {
$times[$date->format("H:i")] = [];
$date = $date->add($step);
}
return $times;
}
This is what I'd do:
$startDate = date_create("today"); //Any start date works
$endDate = date_create("tomorrow"); //Any end date works
$step = new DateInterval("PT1M"); //1 minute, can change
$date = $startDate;
$times = [];
while ($date <= $endDate) {
$times[$date->format("H:i")] = [];
$date = $date->add($step);
}
print_r($times);
http://sandbox.onlinephpfunctions.com/code/dd91a8f3f1707ca20aae93f70969275d5fb8dedd
Well, a more elegant approach of your code is:
<?php
function emptySchedule($hoursInit = date('G'), $hoursActive = 24)
{
$emptySchedule = [];
for ($h = $hoursInit; $h < $hoursActive; ++$h) {
for ($m = 0; $m < 60; ++$m) {
$emptySchedule[sprintf('%02d:%02d', $h, $m)] = [];
}
}
return $emptySchedule;
}
You can use interval too, working with lunch hours in your schedule and stuff:
<?php
function emptySchedule($hoursInit = date('G'), $hoursActive = 24, $interval = false)
{
$emptySchedule = [];
for ($h = $hoursInit; $h < $hoursActive; ++$h) {
if ($interval && ($h < $interval['start'] || $h > $interval['end'])) {
for ($m = 0; $m < 60; ++$m) {
$emptySchedule[sprintf('%02d:%02d', $h, $m)] = [];
}
}
}
return $emptySchedule;
}
But, like #deceze said, using date functions is a must, it's not simple to do right now, I'll try to figure out a better way;

Get number of weekdays in a given month

I want to calculate the number of weekdays days in a give month and year. Weekdays means monday to friday. How do i do it ?
You don't need to count every day in the month. You already know the first 28 days contain 20 weekdays no matter what. All you have to do is determine the last few days. Change the start value to 29. Then add 20 weekdays to your return value.
function get_weekdays($m,$y) {
$lastday = date("t",mktime(0,0,0,$m,1,$y));
$weekdays=0;
for($d=29;$d<=$lastday;$d++) {
$wd = date("w",mktime(0,0,0,$m,$d,$y));
if($wd > 0 && $wd < 6) $weekdays++;
}
return $weekdays+20;
}
Some basic code:
$month = 12;
$weekdays = array();
$d = 1;
do {
$mk = mktime(0, 0, 0, $month, $d, date("Y"));
#$weekdays[date("w", $mk)]++;
$d++;
} while (date("m", $mk) == $month);
print_r($weekdays);
Remove the # if your PHP error warning doesn't show notices.
try this one
function getWeekdays($m, $y = NULL){
$arrDtext = array('Mon', 'Tue', 'Wed', 'Thu', 'Fri');
if(is_null($y) || (!is_null($y) && $y == ''))
$y = date('Y');
$d = 1;
$timestamp = mktime(0,0,0,$m,$d,$y);
$lastDate = date('t', $timestamp);
$workingDays = 0;
for($i=$d; $i<=$lastDate; $i++){
if(in_array(date('D', mktime(0,0,0,$m,$i,$y)), $arrDtext)){
$workingDays++;
}
}
return $workingDays;
}
This is the simplest code I could come up with.
You really would need to create an array or a database table to hold the holidays to get a true, "Working Days" count, but that wasn't what was asked, so here you go, hope this helps someone.
function get_weekdays($m,$y) {
$lastday = date("t",mktime(0,0,0,$m,1,$y));
$weekdays=0;
for($d=1;$d<=$lastday;$d++) {
$wd = date("w",mktime(0,0,0,$m,$d,$y));
if($wd > 0 && $wd < 6) $weekdays++;
}
return $weekdays;
}
Get the number of working days without holidays between two dates :
Use example:
echo number_of_working_days('2013-12-23', '2013-12-29');
Output:
3
Link to the function
DateObject method:
function getWorkingDays(DateTime $date) {
$month = clone $date;
$month->modify('last day of this month');
$workingDays = 0;
for ($i = $month->format('t'); $i > 28; --$i) {
if ($month->format('N') < 6) {
++$workingDays;
}
$month->modify('-1 day');
}
return 20 + $workingDays;
}
Calculate working days in a month from any date:
public function getworkd($mday)
{
$dn = new DateTime($mday);
$dfrom = $dn->format('Y-m-01');
$dtill = $dn->format('Y-m-t');
$df = new DateTime($dfrom);
$dt = new DateTime($dtill);
$wdays = 0;
while($df<=$dt)
{
$dof= $df->format('D') ;
if( $dof == 'Sun' || $dof == 'Sat' ) ; else $wdays++;
$df->add(new DateInterval('P1D'));
}
return $wdays;
}
Find the last day and the weekday for the given month
then do a simple while loop like :-
$dates = explode(',', date('t,N', strtotime('2013-11-01')));
$day = $dates[1];
$tot = $dates[0];
$cnt = 0;
while ($tot>1)
{
if ($day < 6)
{
$cnt++;
}
if ($day == 1)
{
$day = 7;
}
else
{
$day--;
}
$tot--;
}
$cnt = total of weekday (Monday to Friday) for a given month
I've come up with a non-loop function. Much better in terms of performance. It might seem messy but it just needs to ask PHP the first day's weekday and the month's number days: the rest are arithmetical operations based on logic.
function countWorkDays($year, $month)
{
$workingWeekdays = 5;
$firstDayTimestamp = mktime(0, 0, 0, $month, 1, $year);
$firstDayWeekDay = (int)date("N", $firstDayTimestamp); //1: monday, 7: saturday
$upToDay = (int)date("t", $firstDayTimestamp);
$firstMonday = 1 === $firstDayWeekDay ? 1 : 9 - $firstDayWeekDay;
$wholeWeeks = $firstMonday < $upToDay ? (int)floor(($upToDay - $firstMonday + 1) / 7) : 0;
$extraDays = ($upToDay - $firstMonday + 1) % 7;
$initialWorkdays = $firstMonday > 1 && $firstDayWeekDay <= $workingWeekdays ? $workingWeekdays - $firstDayWeekDay + 1 : 0;
$workdaysInWholeWeeks = $wholeWeeks * $workingWeekdays;
$extraWorkdays = $extraDays <= $workingWeekdays ? $extraDays : $workingWeekdays;
return $initialWorkdays + $workdaysInWholeWeeks + $extraWorkdays;
}
These functions work Without Loops.
The functions calculate the number of weekdays using:
day-number of first monday in month
number of days in month
// main functions
// weekdays in month of year
function calculateNumberOfWeekDaysAtDate($month, $year)
{
// I'm sorry, I don't know the right format for the $month and $year, I hope this is right.
// PLEASE CORRECT IF WRONG
$firstMondayInCurrentMonth = (int) date("j", strtotime("first monday of 01-$month-$year")); //get first monday in month for calculations
$numberOfDaysOfCurrentMonth = (int) date("t", strtotime("01-$month-$year")); // number of days in month
return calculateNumberOfWeekDaysFromFirstMondayAndNumberOfMonthDays($firstMondayInCurrentMonth, $numberOfDaysOfCurrentMonth);
}
// week days in current month
function calculateNumberOfWeekDaysInCurrentMonth()
{
$firstMondayInCurrentMonth = (int) date("j", strtotime("first monday of this month")); //get first monday in month for calculations
$numberOfDaysOfCurrentMonth = (int) date("t"); // number of days in this month
return calculateNumberOfWeekDaysFromFirstMondayAndNumberOfMonthDays($firstMondayInCurrentMonth, $numberOfDaysOfCurrentMonth);
}
// helper functions
function calculateNumberOfWeekDaysFromFirstMondayAndNumberOfMonthDays($firstMondayInCurrentMonth, $numberOfDaysOfCurrentMonth)
{
return $numberOfWeekDays = (($start = ($firstMondayInCurrentMonth - 3)) < 0 ? 0 : $start) + floor(($numberOfDaysOfCurrentMonth - ($firstMondayInCurrentMonth - 1)) / 7) * 5 + (($rest = (($numberOfDaysOfCurrentMonth - ($firstMondayInCurrentMonth - 1)) % 7)) <= 5 ? $rest : 5);
}
function workingDays($m,$y) {
$days = cal_days_in_month(CAL_GREGORIAN, $m, $y);
$workig_days = 0;
$days_rest = array(5,6); //friday,saturday
for ( $d=1 ; $d < $days+1 ; $d++ ) {
if ( !in_array(date("w",strtotime("{$d}-{$m}-{$y}")),$days_rest) ) {
$workig_days++;
}
}
return $workig_days;
}
I created a simple function that takes the $first_day_of_month (week day like Sunday/Monday etc). You can find out the first day of month like this:
date('N', strtotime(date("01-m-Y")));
And using the $month_last_date which can be procured like this:
date("t");
Here is the function:
function workingDaysInMonth(int $first_day_of_month, int $month_last_date) : array
{
$working_days = [];
$day = $first_day_of_month;
$working_day_count = 0;
for ($i = 1; $i <= $month_last_date; $i++) {
if ($day == 8) {
$day = 1;
}
if (!($day == 6 || $day == 7)) {
$working_day_count++;
$working_days[$i] = $working_day_count;
}
$day++;
}
return $working_days;
}
this will work
// oct. 2013
$month = 10;
// loop through month days
for ($i = 1; $i <= 31; $i++) {
// given month timestamp
$timestamp = mktime(0, 0, 0, $month, $i, 2012);
// to be sure we have not gone to the next month
if (date("n", $timestamp) == $month) {
// current day in the loop
$day = date("N", $timestamp);
// if this is between 1 to 5, weekdays, 1 = Monday, 5 = Friday
if ($day == 1 OR $day <= 5) {
// write it down now
$days[$day][] = date("j", $timestamp);
}
}
}
// to see if it works :)
print_r($days);

Get Difference Between Two Times (Unix Epoch)

You know when it's late in the night and your brain is fried? I'm having one of those nights right now, and my function so far is not working as it should, so please take a look at it:
(I should note that I'm using the PHP 5.2.9, and the function / method DateTime:Diff() is not available until PHP 5.3.0.
<?php
function time_diff($ts1, $ts2) {
# Find The Bigger Number
if ($ts1 == $ts2) {
return '0 Seconds';
} else if ($ts1 > $ts2) {
$large = $ts1;
$small = $ts2;
} else {
$small = $ts1;
$large = $ts2;
}
# Get the Diffrence
$diff = $large - $small;
# Setup The Scope of Time
$s = 1; $ss = 0;
$m = $s * 60; $ms = 0;
$h = $m * 60; $hs = 0;
$d = $h * 24; $ds = 0;
$n = $d * 31; $ns = 0;
$y = $n * 365; $ys = 0;
# Find the Scope
while (($diff - $y) > 0) { $ys++; $diff -= $y; }
while (($diff - $n) > 0) { $ms++; $diff -= $n; }
while (($diff - $d) > 0) { $ds++; $diff -= $d; }
while (($diff - $h) > 0) { $hs++; $diff -= $h; }
while (($diff - $m) > 0) { $ms++; $diff -= $m; }
while (($diff - $s) > 0) { $ss++; $diff -= $s; }
# Print the Results
return "$ys Years, $ns Months, $ds Days, $hs Hours, $ms Minutes & $ss Seconds.";
}
// Test the Function:
ediff(strtotime('December 16, 1988'), time());
# Output Should be:
# 20 Years, 11 Months, 8 Days, X Hours, Y Minutes & Z Seconds.
?>
This isn't an answer to your question, but I just wanted to point out...
while (($diff - $y) > 0) { $ys++; $diff -= $y; }
is a very inefficient way of writing
$ys = $diff / $y;
$diff = $diff % $y;
Also, this
else if ($ts1 > $ts2) {
$large = $ts1;
$small = $ts2;
} else {
$small = $ts1;
$large = $ts2;
}
# Get the Diffrence
$diff = $large - $small;
can easily be rewritten as
$diff = abs($ts1 - $ts2);
I have a feeling that the problem in your code would be more apparent if it was less verbose. :)
how about simplifying the first part with a simple
$diff = abs($ts2 - $ts1);
Then, when you do this:
$n = $d * 31; $ns = 0;
$y = $n * 365; $ys = 0;
you are actually saying that a year is composed of 365 31 day long months. which is actually about 36 year long years. Probably not what you want.
Finally, we are all grown ups here. Please use grown up variable names i.e. $YEAR_IN_SECONDS instead of $ys. As you can clearly see, you may write code once, but 20 other schmucks are going to have to read it a lot of times.
In the case of needed all months during the given times-stamp then we have use of the following coding in php :
function MonthsBetweenTimeStamp($t1, $t2) {
$monthsYear = array();
$lastYearMonth = strtotime(gmdate('F-Y', $t2));
$startYearMonth = strtotime(gmdate('F-Y', $t1));
while ($startYearMonth < $lastYearMonth) {
$monthsYear[] = gmdate("F-Y", $startYearMonth);
//Increment of one month directly
$startYearMonth = strtotime(gmdate("F-Y", $startYearMonth) . ' + 1 month');
}
if (empty($monthsYear)) {
$monthsYear = array($startYearMonth));
}
return $monthsYear;
How about this:
function time_diff($t1, $t2)
{
$totalSeconds = abs($t1-$t2);
$date = getdate($totalSeconds);
$firstYear = getdate(0);
$years = $date['year']-$firstYear['year'];
$months = $date['mon'];
$days = $date['mday'];
$hours = $date['hour'];
$minutes = $date['minutes'];
$seconds = $date['seconds'];
return "$years Years, $months Months, $days Days, $hours Hours, $minutes Minutes & $seconds Seconds.";
}
This uses the difference of the given times as a date. Then you can let the "getdate" do all the work for you. The only challenge is the number years - which is simply the getdate year (of the difference) minus the Unix epoch year (1970).
If you don't like using an actual month, you could also divide the "year" day by the number of days in 12 equal months
$months = $date['yday'] / (365/12);
Similarly days could be figured out the remaining days with modulus
$days = $date['yday'] % (365/12);

Categories