5
\$\begingroup\$

I'm calculating now the total garnered hours student get in school using php.

(Same concept in getting the total work hours in employee for timesheets)

So I have an array $attendance where the student check in and out in school.

$attendance = [
  "2019-07-01 08:03:00",
  "2019-07-01 12:12:00",
  "2019-07-01 13:03:00",
  "2019-07-01 17:00:00",
];

$schedules is on what time the student should check in and out.

$schedules = [
  [
    "time_start" => "08:00:00",
    "time_end" => "12:00:00",
    "in_threshold" => 15,
    "out_threshold" => 15
  ],
  [
    "time_start" => "13:00:00",
    "time_end" => "17:00:00",
    "in_threshold" => 15,
    "out_threshold" => 15
  ]
];

The threshold is a minute the student should check in/out if the student check in above threshold it will result to late. (Eg. 08:16:00 checks in. He/she is late )

Code below is for storing time_start and time_end to array which is the basis for time_in and out:

foreach($schedules as $schedule){

    // Set time_start and time_end with threshold
    $mytime_start[] = date( "H:i:s",
        strtotime('+'. $schedule[ 'in_threshold' ] .' minutes',
            strtotime ( $schedule[ 'time_start' ]
            )));
    $mytime_end[] = date( "H:i:s",
        strtotime('+'. $schedule[ 'out_threshold' ] .' minutes',
            strtotime( $schedule[ 'time_end' ]
            )));
    // Get time_start and time_end to array
    $sched_starts[] = ( $schedule[ 'time_start' ] );
    $sched_ends[] = ( $schedule[ 'time_end' ] );
}

Note: The schedule time_start and time_end can be change. Function getClosestTime will get the closest time of each attendance. It will identify if the logs is for schedule time_start or time_end.

function getClosestTime( $array, $date ){
    foreach( $array as $day ){
        $interval[] = abs(strtotime($date) - strtotime($day));

    }
    asort($interval);
    $closest = key($interval);

    return $array[$closest];
}

Get $attendance by 2. for Punch IN and OUT

for ($index = 0; $index < count($attendance); $index += 2)

Expected the two element of array is in and out.

$date_start = $attendance[$index]; // Punch In
$date_end = $attendance[$index + 1]; // Punch Out

Get only date in $attendance (If the schedule cross midnights)

$to_date_start = date("Y-m-d", strtotime($date_start));
$to_date_end = date("Y-m-d", strtotime($date_end));

Get closest Time for each element in $attendance

$time_start = getClosestTime($mytime_start, date('H:i:s',strtotime($date_start)));
$time_end = getClosestTime($mytime_end, date('H:i:s',strtotime($date_end)));

If there's an instance if the student check in late and the closest time is not the exact time_start for its time_end.

if ($time_start > $time_end) {
    $time_start = date("Y-m-d", strtotime($date_start));
}

Add dates in schedule time start and time_end

$time_start = date('Y-m-d H:i:s', strtotime("$to_date_start $time_start"));
$time_end = date('Y-m-d H:i:s', strtotime("$to_date_end $time_end"));

Set the exact datetime when the student should check in/out

$time_minus_start = date("Y-m-d H:i:s", strtotime("-15 minutes $time_start"));
$time_minus_end = date("Y-m-d H:i:s", strtotime("-15 minutes $time_end"));

Check check in if it is above the threshould same logic for check out

if ($date_start > $time_start) {
    $start = $late;
    $total_late += 1;

}else {
    $start = $exact_in;
}

If $attendace is exact time_start and time_end return its date

if (isBetween($time_minus_start, $time_start, $date_start)
    && isBetween($time_minus_end, $time_end, $date_end)) {
    $start = $within_in;
    $end = $within_out;

} else if (isBetween($time_minus_start, $time_start, $date_start) && $date_end > $time_end) {
    $start = $within_in;
    $end = $late_out;
}

Sum check in and check out result

$total_garner_hours += ($end - $start);

In my algorithm:

Student check in early and check out late then $start/$end return the exact time student should check in/out.

Student check in late and check out early $start/$end return the real-time data.

Here is my live code: https://3v4l.org/9MaEc

I would like to make the code more efficient and reliable. I'm a beginner and I admit it, my code is so messed up.

\$\endgroup\$
  • \$\begingroup\$ So is this just a repost of the same question after your first post gathered no reviews? Do you want to delete the first one? I don't know why CodeReview would want the redundance. \$\endgroup\$ – mickmackusa Jul 23 '19 at 22:42
  • \$\begingroup\$ Its not. Its different. \$\endgroup\$ – Rubics Jul 23 '19 at 22:53
  • \$\begingroup\$ Are you not asking for a review of the same script, duplicating lots of the same question body content, and sharing the same 3v4l demo link? Looks rather similar at a glance. Do explain the difference please, because it is not instantly obvious to me. \$\endgroup\$ – mickmackusa Jul 24 '19 at 2:16
  • \$\begingroup\$ A lot of difference but have same function. In previous I only modify the attendance if it is early or out but here It calculate the total hours \$\endgroup\$ – Rubics Jul 24 '19 at 4:52
  • 1
    \$\begingroup\$ That's okay, I just wanted to be clear about the difference. I intend to review your scripts, but have been too busy at work. When I find time, I didn't want to do the same review twice. \$\endgroup\$ – mickmackusa Jul 24 '19 at 4:59
2
\$\begingroup\$

The algorithm does not allow for the possibility of a transition from daylight time to standard time or vice versa.

Without knowing the mechanism for obtaining the date and time, it's impossible to say if the algorithm needs to be aware of time zones. In principle, the student could be attending by video conference and be in a different time zone.

If the time and date is obtained from a device belonging to the student, the student may prefer to operate the device on a time zone different from the school. For example, both the student and the school could be located in New York but the student corresponds with people all over the world, so keeps her laptop set to UTC.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Adding to what Gerard has answered, there are some PHP libraries that deal with time very well which you could implement. One example is Carbon.

I would separate out your date comparisons into its own function. May be useful elsewhere and is a little clearer. Everything in your for loop up to your first if statement could be its own function.

You could improve your formatting a little (don't know if copy and pasting into Stack Exchange has caused it) but you can take a look at PSR-2. Naming variables a little clearer will be helpful to you, those reviewing your code and to anybody who may now/in the future work on this code, e.g. mytime_start doesn't make it clear what time you are talking about, and index could simply be referred to as the standard i.

Remember to type hint your parameters and give return values.

Hope this helps a bit!

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.