'How to get same day values and calculate working hours for that day from php array
I got a big associative array I pull from that array user's full name and time. Now in that array, I don't have only one day but I got a full month date and time, it looks something like this
John Doe : 2022-04-01 08:00:00
John Doe : 2022-04-01 10:00:00
John Doe : 2022-04-01 14:00:00
John Doe : 2022-04-23 08:00:00
John Doe : 2022-04-23 10:00:00
John Doe : 2022-04-23 14:00:00
And now I want to pull from that array one single day for that user for example I want to pull just 2022-04-01 for John Doe and calculate his working hours, how much time he worked on that particular day and I want this for every day in a month to do that here is my script right now nothing much but it can help someone
foreach($xlsArr as $row){
// Getting user work single day
$fullName = $row['first-name'] . ' ' .$row['last-name']; // Example John Doe
$date = $row['time']; // Example 2022-04-01 08:00:00
echo $fullName . ' ' . $date . '<br>';
}
Solution 1:[1]
so basic steps are:
- group data by user
- group each user data by day
- calculations on grouped by day timestamps
/**
* helper function for data sample
* credits https://stackoverflow.com/a/24431558/6330083
* @param DateTime $start
* @param DateTime $end
* @return DateTime
*/
function randomDateInRange(DateTime $start, DateTime $end)
{
$randomTimestamp = mt_rand($start->getTimestamp(), $end->getTimestamp());
$randomDate = new DateTime();
$randomDate->setTimestamp($randomTimestamp);
return $randomDate;
}
/**
* provides basic raw data sample
* example output
* [
* [
* "first-name" => "0",
* "last-name" => "00",
* "time" => "2022-05-01 15:43:22",
* ],
* [
* "first-name" => "0",
* "last-name" => "00",
* "time" => "2022-05-02 13:43:06",
* ],
* [
* "first-name" => "1",
* "last-name" => "11",
* "time" => "2022-05-01 16:15:27",
* ],
* ...
* ]
* @return array
*/
function sampleData()
{
$dateStart = new DateTime('2022-05-01');
$dateEnd = (new DateTime())->setTimestamp($dateStart->getTimestamp());
$dateEnd->add(DateInterval::createFromDateString('2 days'));
$sample = [];
for ($i = 0; $i < 10; $i++) {
for ($k = 0; $k < random_int(0, 6); $k++) {
$time = randomDateInRange($dateStart, $dateEnd)->format('Y-m-d H:i:s');
array_push($sample, [
'first-name' => "$i",
'last-name' => "$i$i",
'time' => $time
]);
}
}
return $sample;
}
/**
* @param array
* @return array
*/
function calculateWorkingHours(array $data = [])
{
if (count($data) == 0) {
$data = sampleData();
}
/* at this step we're grouping data by user with subarray contains time column
sample output
[
"1 11" => [
"2022-05-02 13:44:10",
],
"2 22" => [
"2022-05-02 03:59:20",
"2022-05-02 17:50:01",
],
...
]
*/
$grouped = [];
foreach ($data as $row) {
$groupName = $row['first-name'] . " " . $row['last-name'];
$grouped[$groupName][] = $row['time'];
}
/*
next groping by day
actually this step probably might be changed to make final
summary instead of grouping,
but you didn't mention the way you should calculate working
hours from provided timestamps
sample output
[
"0 00" => [
"2022-05-01" => [
"2022-05-01 13:01:14",
"2022-05-01 19:02:24",
],
"2022-05-02" => [
"2022-05-02 07:54:44",
],
],
"1 11" => [
"2022-05-02" => [
"2022-05-02 05:10:19",
"2022-05-02 14:40:41",
],
"2022-05-01" => [
"2022-05-01 12:15:36",
"2022-05-01 23:26:19",
],
],
...
]
*/
$withGroupedTimes = array_map(function ($ungroupedTimes) {
$gropedTimes = [];
foreach ($ungroupedTimes as $time) {
$day = (new DateTime($time))->format('Y-m-d');
$gropedTimes[$day][] = $time;
}
return $gropedTimes;
}, $grouped);
// now we have structure grouped by user with subroups by day for
// each user and can provide calculations
$calculated = array_map(function ($user) {
return array_map(function ($day) {
// $day is array of timestamps
// here you should provide logic to sum hours and return it int $result variable
// as a basic example i return intervals count of that day
$result = count($day);
return $result;
}, $user);
}, $withGroupedTimes);
return $calculated;
}
Solution 2:[2]
I found some solutions by grouping them by card number, sorry because I didn't post the whole array of data but I will show a solution
$xlsArr = excel_to_array($fileTmpName); // Converted XLS to Associative Array
$employees = [];
$employees_daily_checks = [];
// Looping through array and pushing all employees to array sorting by card_number
foreach($xlsArr as $row){
$card_number = $row['card-number'];
if(isset($card_number) && !empty($card_number)){
if(!empty($employees[$card_number])){
array_push($employees[$card_number], $row);
}else{
$employees[$card_number] = [$row];
}
}else{
$errors[] = "Došlo je do greške prilikom u?itavanja podataka, nije mogu?e na?i 'Card Number' u dokumentu!";
break;
}
}
// Gettng employees daily checks
foreach($employees as $key => $checks_arr){
foreach($checks_arr as $value){
$date = new DateTime($value['time']);
$day = $date->format('d');
if(!empty($employees_daily_checks[$key][(int)$day])){
array_push($employees_daily_checks[$key][(int)$day], $value);
}else{
$employees_daily_checks[$key][(int)$day] = [$value];
}
}
}
$time_in_out_checks = [];
// Time check for each emplyee day
foreach($employees_daily_checks as $key => $value){
// Go inside of day array
foreach($value as $day => $data){
// Go inside of data array, and push all time in/out checks
foreach($data as $row){
if(isset($row['time']) && !empty($row['time']) && isset($row['first-name']) && !empty($row['first-name']) && isset($row['last-name']) && !empty($row['last-name'])){
// Calculate the hours of working
$first_check_in = min(array_column($data, 'time'));
$last_check_out = max(array_column($data, 'time'));
$hours_worked = (strtotime($last_check_out) - strtotime($first_check_in)) / 3600;
$hours_worked = round($hours_worked, 2);
$dayNumber = date('d', strtotime($row['time']));
$dayFullName = date('l', strtotime($row['time']));
$monthNumber = date('m', strtotime($row['time']));
$monthFullName = date('F', strtotime($row['time']));
$time_in_out_checks[$key][$day] = [
'first_check_in' => $first_check_in,
'last_check_out' => $last_check_out,
'hours_worked' => $hours_worked,
'day' => $dayFullName,
'dayNumber' => $dayNumber,
'month' => $monthFullName,
'monthNumber' => $monthNumber,
];
$time_in_out_checks[$key]['employee_data'] = [
'fullName' => $row['first-name'] . ' ' . $row['last-name'],
'firstName' => $row['first-name'],
'lastName' => $row['last-name'],
'cardNumber' => $row['card-number'],
];
}else{
$errors[] = "Došlo je do greške prilikom u?itavanja podataka, iz dokumenta nije mogu?e na?i potrebne podatke (Card Number, First Name, Last Name, Time) podatke!";
break 3;
}
}
}
}
// Check return values from array
if(empty($errors)){
if(isset($time_in_out_checks) && empty($time_in_out_checks)){
$errors[] = "Došlo je do greške prilikom u?itavanja podataka, iz dokumenta nije mogu?e na?i potrebne podatke (Card Number, First Name, Last Name, Time) podatke!";
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ol D. Castor |
| Solution 2 | Stefan Momcilovic |
