Hello Im just a beginner programmer but Im now building an app which gets the total hours of work.
Here I have a time_start array which the threshold for the customer to in and same as out for time_end
The logs here is where the person checks in.
$time_start = [
[0] => '22:00:00',
[1] => '03:00:00',
];
$time_end = [
[0] => '02:00:00',
[1] => '08:00:00',
];
$logs = [
[0] => '2019-07-09 22:00:00',
[1] => '2019-07-10 02:00:00',
[2] => '2019-07-10 03:00:00',
[3] => '2019-07-10 08:00:00',
];
So I'm trying to get the sum of their hours in night shift which has different date.
Im trying to get it in:
foreach( $logs as $check_time ){
$attendance_date_time = date("Y-m-d",strtotime($check_time));
$time_starts = date('Y-m-d H:i:s', strtotime("$attendance_date_time $time_start"));
$time_ends = date('Y-m-d H:i:s', strtotime("$attendance_date_time $time_end"));
if ( $check_time >= $time_starts && $check_time <= $time_ends )
{
$time[] = $check_time;
}else{
$time = null
}
}
Supposedly I will get all logs because it is between time_start and time_end and store it to $time
And summing the time i get.
Since I'm new at php is their any easiest idea to get the total work hours? Cuz I get a null because the time_end it gets was the date of check_in.
Here is your snippet,
$time_start = [
0 => '22:00:00',
1 => '03:00:00',
];
$time_end = [
0 => '02:00:00',
1 => '08:00:00',
];
$logs = [
0 => '2019-07-09 22:00:00',
1 => '2019-07-10 02:00:00',
2 => '2019-07-10 03:00:00',
3 => '2019-07-10 08:00:00',
];
$time = [];
$diff = 0;
for ($j = 0; $j < count($logs); $j = $j + 2) {
$attendance_start = date("Y-m-d", strtotime($logs[$j]));
$attendance_end = date("Y-m-d", strtotime($logs[$j + 1]));
for ($i = 0; $i < count($time_start); $i++) {
$time_starts = date('Y-m-d H:i:s', strtotime("$attendance_start " . $time_start[$i] . ""));
$time_ends = date('Y-m-d H:i:s', strtotime("$attendance_end " . $time_end[$i] . ""));
if ($logs[$j] >= $time_starts && $logs[$j + 1] <= $time_ends) {
array_push($time, $logs[$j], $logs[$j + 1]);
// calculating diff for two alternate days
$diff += (round((strtotime($logs[$j + 1]) - strtotime($logs[$j])) / 3600, 1));
break;
}
}
}
echo $diff . " Hours";die;
Demo
Output:-
9 Hours
The for loop is the easiest way to do this
$time_start = [
'22:00:00',
'03:00:00',
];
$time_end = [
'02:00:00',
'08:00:00',
];
$logs = [
'2019-07-09 22:00:00',
'2019-07-10 02:00:00',
'2019-07-10 03:00:00',
'2019-07-10 08:00:00',
];
$totalDiff = 0;
for($i =0 ; $i < count($logs); $i = $i + 2)
{
$startDate = strtotime($logs[$i]);
$endDate = strtotime($logs[$i+1]);
$diff = $endDate-$startDate;
$totalDiff += $diff;
}
$hourDiff = $totalDiff / 3600;
echo $hourDiff . ' hours';
Demo
Related
I am creating a function where you can give a starting year, month and end year, month and the function will print every month and year in between the two given points.
I've already created a function that works perfectly but I believe this is not a good practice and there might be better way to do this. Now I am seeking your help to find a better way.
P.S. I can't get full date as input. Only can get month number and year.
Here is my code -
function get_all_months($monthstart = null, $yearstart = null, $monthend = null, $yearend = null) {
if (($monthstart === null) || ($yearstart === null) || ($monthend === null) || ($yearend === null)) {
$monthend = date('m');
$yearend = date('Y');
if($monthend < 6) {
$yearstart = $yearend - 1;
$monthstart = (($monthend - 5) + 12);
} else {
$yearstart = $yearend;
$monthstart = $monthend - 5;
}
}
$month_array = array();
if ($yearstart > $yearend) {
for ($m=$monthend; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $yearend);
for ($y=$yearend+1; $y<$yearstart; $y++) for ($m=1; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $y);
for ($m=1; $m<=$monthstart; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
} elseif ($yearend > $yearstart) {
for ($m=$monthstart; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
for ($y=$yearstart+1; $y<$yearend; $y++) for ($m=1; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $y);
for ($m=1; $m<=$monthend; $m++) $month_array[] = array('month' => $m, 'year' => $yearend);
} else {
for ($m=$monthstart; $m<=$monthend; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
}
return $month_array;
}
EDIT: Based on Nigel Ren's answer, this is the best way I could think of -
function get_all_months($monthstart = null, $yearstart = null, $monthend = null, $yearend = null) {
if (($monthstart === null) || ($yearstart === null) || ($monthend === null) || ($yearend === null)) {
$monthend = date('m');
$yearend = date('Y');
if($monthend < 6) {
$yearstart = $yearend - 1;
$monthstart = (($monthend - 5) + 12);
} else {
$yearstart = $yearend;
$monthstart = $monthend - 5;
}
}
$output = [];
if ($yearstart > $yearend) {
$time = strtotime($yearend."-".$monthend);
$last = date('m-Y', strtotime($yearstart."-".$monthstart));
} else {
$time = strtotime($yearstart."-".$monthstart);
$last = date('m-Y', strtotime($yearend."-".$monthend));
}
do {
$cur_month_year = date('m-Y', $time);
$month = date('m', $time);
$year = date('Y', $time);
$output[] = array('month'=>$month,'year'=>$year);
$time = strtotime('+1 month', $time);
}
while ($cur_month_year != $last);
return $output;
}
You can use PHP's DateInterval class which is used for these purposes. Try this code
<?php
function getMonthsFromRange($start, $end, $format = 'M Y')
{
$array = array();
// Since you wanted 1 month it is Period = 1 Month
$interval = new DateInterval('P1M');
$realEnd = new DateTime($end);
$realEnd->add($interval);
$period = new DatePeriod(new DateTime($start), $interval, $realEnd);
// Use loop to store date into array
foreach ($period as $date)
$array[] = $date->format($format);
// Return the array elements
return $array;
}
// Function call with passing the start date and end date
$months = getMonthsFromRange('2010-10', '2011-11');
print_r($months);
It's output is:
Array ( [0] => Oct 2010 [1] => Nov 2010 [2] => Dec 2010 [3] => Jan 2011 [4] => Feb 2011 [5] => Mar 2011 [6] => Apr 2011 [7] => May 2011 [8] => Jun 2011 [9] => Jul 2011 [10] => Aug 2011 [11] => Sep 2011 [12] => Oct 2011 [13] => Nov 2011 )
Based on the answer here, it can be done simply by adding 1 month to the start date till you get to the end date...
function get_all_months($monthstart = null, $yearstart = null, $monthend = null, $yearend = null) {
$output = [];
$time = strtotime($yearstart."-".$monthstart);
$last = date('m-Y', strtotime($yearend."-".$monthend));
do {
$month = date('m-Y', $time);
$output[] = $month;
$time = strtotime('+1 month', $time);
}
while ($month != $last);
return $output;
}
So
print_r(get_all_months(4,2008,2,2010));
gives...
Array
(
[0] => 04-2008
[1] => 05-2008
[2] => 06-2008
[3] => 07-2008
[4] => 08-2008
[5] => 09-2008
[6] => 10-2008
[7] => 11-2008
[8] => 12-2008
[9] => 01-2009
[10] => 02-2009
[11] => 03-2009
[12] => 04-2009
[13] => 05-2009
[14] => 06-2009
[15] => 07-2009
[16] => 08-2009
[17] => 09-2009
[18] => 10-2009
[19] => 11-2009
[20] => 12-2009
[21] => 01-2010
[22] => 02-2010
)
probably you're looking for something like this:
function get_all_months($monthstart = null, $yearstart = null, $monthend = null, $yearend = null) {
$month_array = [];
if ($yearstart == $yearend)
for ($m=$monthstart; $m<=$monthend; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
else {
for ($m=$monthstart; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
for ($y=$yearstart+1; $y<$yearend; $y++) for ($m=1; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $y);
for ($m=1; $m<=$monthend; $m++) $month_array[] = array('month' => $m, 'year' => $yearend);
}
return $month_array;
}
If I understand correctly - you get the month as a number and the year as a number e.g 6 and 1997. If we assume that the start year is always less than the end year I would suggest going like this.
function distanceBetweenDates(int $sm, int $sy, int $em, int $ey) {
$monthsBetweenYears = ($ey - $sy + 1) * 12;
$distanceBetweenMonths = $monthsBetweenYears - $sm - (12 - $em);
$startMonth = $sm + 1;
$startYear = $sy;
while ($distanceBetweenMonths > 0) {
if ($startMonth <= 12) {
echo $startMonth . ' - ' . $startYear;
} else {
$startMonth = 1;
$startYear++;
echo $startMonth . ' - ' . $startYear;
}
echo "\n";
$startMonth++;
$distanceBetweenMonths--;
}
}
The only thing you might need to see is if the given months are included or excluded from the calculation.
The only thing missing here is the validation since it can be "skipped" of a sort if you use types inside the method.
With the DateTime class and DateInterval, you can create a generator of DateTime object of the specified range:
<?php
function get_all_months(int $monthstart, int $yearstart, int $monthend, int $yearend) {
$onemonth = new DateInterval('P1M'); // one month interval
$timeperiod = new DatePeriod(
DateTime::createFromFormat('Y-m', "{$yearstart}-{$monthstart}"),
$onemonth,
DateTime::createFromFormat('Y-m', "{$yearend}-{$monthend}")->add($onemonth)
);
foreach ($timeperiod as $pos) {
yield clone $pos;
}
}
foreach (get_all_months(12, 2009, 1, 2020) as $month) {
echo "{$month->format('Y-m')}\n";
}
DateTime should be more flexible to use than plain string or number array (see DateTime::format for more usage options).
Note: inspired by #keidakida, updated my answer.
I'm trying to separate the dates for example:
$arr=array(
"2018-06-27 20:30:20",
"2018-06-27 20:31:20",
"2018-06-27 20:37:20",
"2018-06-27 20:45:20",
"2018-06-27 20:48:20"
);
As you can see there are minutes with difference only of 1 minute or even seconds.
What I'm trying to accomplish is to force the dates to be 5 mins interval.
example output
2018-06-27 20:30:00
2018-06-27 20:35:00
2018-06-27 20:40:00
2018-06-27 20:45:00
2018-06-27 20:50:00
Here's my code
function roundToNearestMinuteInterval($time)
{
$time = (round(strtotime($time) / 300)) * 300;
return date('Y-m-d H:i:s', $time);
}
$temp="";
$wave=1;
foreach($arr as $a) {
if(empty($temp)) {
$temp= roundToNearestMinuteInterval($a);
}
$date= roundToNearestMinuteInterval($a);
if($temp==$date && $wave!=1){
$new=date('Y-m-d H:i:s',strtotime('+3 minutes',strtotime($a)));
$date= roundToNearestMinuteInterval($date);
$temp= $date;
}
$wave++;
echo $date."<br/>";
}
If you want to have an output array with all the 5 minute (or other interval) times between the earliest and latest times in the input array, you can just iterate between them, adding the interval in each loop:
$arr=array("2018-06-27 20:30:20","2018-06-27 20:31:20","2018-06-27 20:37:20","2018-06-27 20:45:20","2018-06-27 20:48:20");
function roundToNearestMinuteInterval($time, $interval) {
$timestamp = strtotime($time);
$rounded = round($timestamp / ($interval * 60), 0) * $interval * 60;
return $rounded;
}
$interval = 5; // minutes
$start = roundToNearestMinuteInterval(min($arr), $interval);
$end = roundToNearestMinuteInterval(max($arr), $interval);
for (; $start <= $end; $start += $interval * 60) {
$results[] = date('Y-m-d H:i:s', $start);
}
print_r($results);
Output:
Array
(
[0] => 2018-06-27 20:30:00
[1] => 2018-06-27 20:35:00
[2] => 2018-06-27 20:40:00
[3] => 2018-06-27 20:45:00
[4] => 2018-06-27 20:50:00
)
Demo on 3v4l.org
Solution with a DateTime extension dt (https://github.com/jspit-de/dt) returns an array with the date as a key. The value supplied is the number of rounded values from the input array. The algorithm can be implemented even without class extension with a few more commands.
$inputArr = array(
"2018-06-27 20:30:20",
"2018-06-27 20:31:20",
"2018-06-27 20:37:20",
"2018-06-27 20:45:20",
"2018-06-27 20:48:20"
);
$interval = "5 Minutes";
//create basis
$resArr = [];
$dt = dt::create(min($inputArr))->round($interval); //start
$endDate = dt::create(max($inputArr))->round($interval);
for(;$dt <= $endDate; $dt->modify($interval)){
$key = $dt->format("Y-m-d H:i:s");
$resArr[$key] = 0;
}
foreach($inputArr as $strDate){
$key = $dt::create($strDate)
->round($interval)
->format("Y-m-d H:i:s");
$resArr[$key]++;
}
The result $resArr
array (
'2018-06-27 20:30:00' => 2,
'2018-06-27 20:35:00' => 1,
'2018-06-27 20:40:00' => 0,
'2018-06-27 20:45:00' => 1,
'2018-06-27 20:50:00' => 1,
)
I am trying to calculate $work_in_daytime and $work_in_nighttime.
$nightStart = '22:00';
$nightEnd = '07:00';
$workers = array(
'0' => array(
'name' => 'Lyons',
'start' => '15:15',
'end' => '23:45'
),
'1' => array(
'name' => 'Santos',
'start' => '10:00',
'end' => '22:00'
),
'2' => array(
'name' => 'Montgomery',
'start' => '22:30',
'end' => '08:00'
)
);
I have tried following code.
foreach ($workers as $worker) {
$startTime = strtotime($em['start']);
$endTime = strtotime($em['end']);
$length = formattedTime($endTime - $startTime);
$nightTimeStart = strtotime($nightStart);
$nightTimeEnd = strtotime($nightEnd);
$dayTimeLength = 0;
$nightTimeLength = 0;
if ($startTime > $nightTimeStart) {
$nightTimeLength += $startTime - $nightTimeStart;
}
if ($startTime < $nightTimeStart) {
$dayTimeLength += $nightTimeStart - $startTime;
}
if ($endTime > $nightTimeStart) {
$nightTimeLength += $endTime - $nightTimeStart;
}
if ($endTime < $nightTimeStart) {
$dayTimeLength += $endTime - $nightTimeStart;
}
echo 'Day Time: '.$dayTimeLength.PHP_EOL;
echo 'Night Time: '.$nightTimeLength.PHP_EOL;
}
I am stuck with correct calculation.
Try This:
$nightStart = '22:00';
$nightEnd = '07:00';
$workers = array(
'0' => array(
'name' => 'Lyons',
'start' => '15:15',
'end' => '23:45'
),
'1' => array(
'name' => 'Santos',
'start' => '6:00',
'end' => '22:00'
),
'2' => array(
'name' => 'Montgomery',
'start' => '22:30',
'end' => '08:00'
)
);
function timetodate($time)
{
return date('H:i', $time);
}
foreach ($workers as $worker) {
$startTime = strtotime($worker['start']);
$endTime = strtotime($worker['end']);
$length = date('H:i',($endTime - $startTime));
$day = strtotime("24H");
$nightTimeStart = strtotime($nightStart);
$nightTimeEnd = strtotime($nightEnd);
$dayTimeLength = 0;
$nightTimeLength = 0;
/* Night Time Calculations */
if ($endTime <= $startTime) {
if ($startTime >= $nightTimeStart) {
$nightTimeLength += $day - $startTime;
if ($endTime <= $nightTimeEnd) {
$nightTimeLength += $nightTimeEnd - $endTime;
}
else
{
$nightTimeLength += $nightTimeEnd;
}
}
}
elseif ($endTime > $nightTimeStart) {
$nightTimeLength += $endTime - $nightTimeStart;
}
elseif ($startTime < $nightTimeEnd) {
$nightTimeLength += $nightTimeEnd - $startTime;
}
/* Day Time Calculations */
if ($startTime >= $nightTimeEnd) {
if ($endTime <= $nightTimeStart) {
if ($startTime < $endTime) {
$dayTimeLength += $endTime - $startTime;
}
else
{
$dayTimeLength += $endTime - $nightTimeEnd;
}
}
else
{
$dayTimeLength += $nightTimeStart - $startTime;
}
}
else
{
if ($endTime <= $nightTimeStart) {
$dayTimeLength += ($endTime - $nightTimeEnd);
}
else
{
$dayTimeLength += $nightTimeStart - $nightTimeEnd;
}
}
echo "Name:". $worker['name'].PHP_EOL;
echo 'Day Time: '.timetodate($dayTimeLength).PHP_EOL;
echo 'Night Time: '.timetodate($nightTimeLength).PHP_EOL.PHP_EOL;
}
https://www.tehplayground.com/CkZ53jjD1cyFEymB
earlier post:
Disregard ---- https://www.tehplayground.com/PohT0L7s35m9VKOe
Like this?
Although I haven't adjusted it, but i think i need to change it a bit more to get it correctly for the turn of the new day (it doesnt see it as a continous shift i dont think)
The variable $em is undefined.
Unsure of what your constants are for daytime and nighttime, but
assuming you calculate daytime from 6am to 6pm and night time from
6pm to 6am:
<?php
$start_nighttime = strtotime('18:00');
$end_nighttime = strtotime('05:59');
$start_daytime = strtotime('06:00');
$end_daytime = strtotime('17:59');
foreach($worker as $data){
$worker_start = strtotime($data['start']);
$worker_end = strtotime($data['end']);
if ($worker_start > $start_daytime && $worker_end < $start_nighttime) {
//Worked only during the day
$daytime = round(abs($worker_start - $worker_end) / 60, 2);
} elseif ($worker_start > $start_daytime && $worker_end > $end_nighttime) {
//Worked during the day and extended past defined night time
$daytime = round(abs($worker_start - $end_daytime) / 60, 2);
$nighttime = round(abs($start_nightime - $worker_end) / 60, 2);
} elseif ($worker_start > $start_nighttime && $worker_end < $end_nighttime){
//Worked only during the night
$nighttime = round(abs($worker_start - $worker_end));
} elseif ($worker_start > $start_nighttime && $worker_end > $end_nighttime){
//Worked only during the night up until the moring
$nighttime = round(abs($worker_start - $end_nighttime));
$daytime = round(abs($start_daytime - $worker_end));
}
}
?>
What is the most efficient way to get an array of months, from a specified date, up until the present day, grouped by year.
Eg getMonths("August 2012") would output
array(
array("Year"=>"2013", "months" = array(
"February", "January")
),
array("Year"=>"2012", "months" = array(
"December", "November","October", "September", "August")
)
)
So far I've got:
$start = strtotime('2012-08-01');
$end = time();
$month = $start;
$months[] = date('F', $start);
while($month <= $end) {
$month = strtotime("+1 month", $month);
$months[] = date('F', $month);
}
This is outputting the correct months, but not grouping them into years.
Thanks
You can try
function getMonths($month,$count = 1) {
$now = new DateTime();
$start = DateTime::createFromFormat("F Y", $month);
$list = array();
$interval = new DateInterval(sprintf("P%dM",$count));
while ( $start <= $now ) {
$list[$start->format("Y")][] = $start->format("F");
$start->add($interval);
}
return $list;
}
print_r(getMonths("August 2012"));
Output
Array
(
[2012] => Array
(
[0] => August
[1] => September
[2] => October
[3] => November
[4] => December
)
[2013] => Array
(
[0] => January
[1] => February
)
)
Since the answer posted here did not work for me (also tried online sandbox to be sure) i wrote a method that works with the very most versions of PHP:
function getMonths($monat, $year) {
$list = array();
for(;$monat <= 12;$monat++) {
if($year == date("Y") && $monat == date("m")) { // exit on current month+year
break;
}
if(!isset($list[ $year ])) {
$list[ $year ] = array();
}
$list[ $year ][ str_pad($monat, 2, '0', STR_PAD_LEFT) ] = date("F", strtotime('01.' . $monat . '.' . $year));
if($monat == 12) {
$monat = 0;
$year++;
}
}
return $list;
}
I want to determine if given interval doesn't fall inside other intervals (using 24-hour clock format), here is the example:
case1:
$startDate = '2021-04-05 08:05:00';
$endDate = '2021-04-05 10:05:00';
$intervals = [['startDate' => '2021-04-05 08:30:00', 'endDate' => '2021-04-05 11:05:00'], ['startDate' => '2021-04-05 12:30:00', 'endDate' => '2021-04-05 13:05:00']]
In this case we should set:
$flagCanSchedule = 0;
Because 2021-04-05 08:05:00 to 2021-04-05 10:05:00 falls between this interval:
'startDate' => '2021-04-05 08:30:00', 'endDate' => '2021-04-05
11:05:00'
But for this:
case 2:
$startDate = '2021-04-05 08:05:00';
$endDate = '2021-04-05 10:05:00';
$intervals = [['startDate' => '2021-04-05 10:05:00', 'endDate' => '2021-04-05 11:05:00'], ['startDate' => '2021-04-05 07:30:00', 'endDate' => '2021-04-05 08:05:00']]
In this case set:
$flagCanSchedule = 1;
Because we don't overlap any other interval, evan tho ('2021-04-05 08:05:00' == '2021-04-05 08:05:00').
I wanted to solve this using strtotime and transform the dates to unix format, but I'm not sure how to write my if statement.
$startDate = strtotime('2021-04-05 08:05:00');
$endDate = strtotime('2021-04-05 10:05:00');
foreach($intervals as $interval) {
if($startDate <= strtotime($interval['startDate']) && $endDate <=
strtotime($interval['endDate'])) {
$flagCanSchedule = 1;
} else {
$flagCanSchedule = 0;
}
}
You should add a break when a flagCanSchedule is found. Because, the next iterations overrides this value (from 1 to 0).
$intervals = [
['startDate' => '2021-04-05 10:05:00', 'endDate' => '2021-04-05 11:05:00'],
['startDate' => '2021-04-05 07:30:00', 'endDate' => '2021-04-05 08:05:00'],
];
$startDate = strtotime('2021-04-05 08:05:00');
$endDate = strtotime('2021-04-05 10:05:00');
foreach($intervals as $interval)
{
if ($startDate <= strtotime($interval['startDate']) &&
$endDate <= strtotime($interval['endDate']))
{
$flagCanSchedule = 1;
break; // << stop the test
}
else {
$flagCanSchedule = 0;
}
}
var_dump($flagCanSchedule); // int(1)
You also can remove the else statement by initializing the flag first.
$flagCanSchedule = 0;
foreach ($intervals as $interval)
{
if ($startDate <= strtotime($interval['startDate']) &&
$endDate <= strtotime($interval['endDate']))
{
$flagCanSchedule = 1;
break;
}
}
var_dump($flagCanSchedule); // int(1)