views:

818

answers:

5

This is the one thing I could never get to work.
My problem is to detect the end of one day and the start of the next and then splitting the diff into each day.

Imagine you want to calculate a pay rate but it has to span across midnight.

It also applies to calculating time to run on timed system, or time diff it should've run.

+8  A: 

I prefer to record all times in Unix Epoch, that way it's as simple as

hoursWorked = ((stopTime - startTime)/60)/60

Here is a full solution it's in PHP but should be easy enough to build to any language:

<?php
$startTime = "12/31/2008 22:02"; //No AM/PM we'll use 24hour system
$endTime = "01/01/2009 06:27"; //Again no AM/PM and we spaned the midnight time gap.
/*
Use this to test for a normal shift not ocurring durring midnight.
$startTime = "01/01/2008 06:02"; //No AM/PM we'll use 24hour system
$endTime = "01/01/2008 14:27"; //Again no AM/PM and we spaned the midnight time gap.
*/
$startTime = split(' ', $startTime);
$endTime = split(' ', $endTime);
$startTime[1] = split(':', $startTime[1]);
$endTime[1] = split(':', $endTime[1]);
/*
$startTime[0] contains the date
$startTime[1][0] contains the hours
$startTime[1][1] contains the minutes
same is true for endTime
*/
if($startTime[0] != $endTime[0])
 {
    if(date2epoch($endTime[0]) > date2epoch($startTime[0]))
     {
     $minutesWorked1 = (59 - $startTime[1][1]); //Calculate how many minutes have occured from begining of shift to midnight
     $minutesWorked2 = $endTime[1][1]; //Number of minute from midnight to end of shift
     $hoursWorked1 = (23 - $startTime[1][0]);//Number of hours from start of shift to midnight
     $hoursWorked2 = $endTime[1][0];//Number of minutes from midnight to end of shift
     echo 'Before midnight you worked ' . $hoursWorked1 . ':' . $minutesWorked1 . "\nAfter midnight you worked " . $hoursWorked2 . ':' . $minutesWorked2 . '.';
     }
    else 
     {
     //SOMETHING MAJOR BAD HAS HAPPENED WHILE LOGGING THE CLOCKINS AND CLOCKOUTS
     }
 }
else 
 {
    echo 'Today you worked ' . ($endTime[1][0] - $startTime[1][0]) . ':' . ($endTime[1][1] - $startTime[1][1]);
 }
function date2epoch($date, $format='m/d/Y')
 {
    $date = split('/', $date);
    return mktime('0', '0', '0', $date[0], $date[1], $date[2]);
 }
?>
Unkwntech
I've edited my question to clarify on the problem. Could you reformulate your answer?
Gustavo Carreno
Tested, and working.
Unkwntech
BTW: PHP is only bad when built by bad programmers.
Unkwntech
+1  A: 

If you have a date available, you should be working with the combination of date+time, and it won't be a problem.

If you know the time span will be less than 24 hours:

if endtime < starttime then endtime = endtime + 24 hours
Mark Ransom
Even if you don't have date, this still works fine. A time after midnight can be treated as "Plus 24 hours". From 11:30 PM (23:30) to 5:30 AM (5:30 + 24:00 = 29:30) is easy to calculate.
S.Lott
+2  A: 

In most languages, the Date/DateTime/etc. classes have methods for things like this. When using these, it's best-practice to convert all dates to UTC before performing arithmetic.

e.g., C#:

// In UTC, preferably
DateTime ClockIn;
DateTime ClockOut;

ClockIn = ...;
ClockOut = ...;

TimeSpan TimeWorked = ClockOut.Subtract(ClockIn);
float HoursWorked = TimeWorked.TotalHours();
Michael Haren
+4  A: 

This is obviously a trivial problem in systems where the starting and ending times are data structures that contain both date and time. But there are plenty of systems that don't do this. It's very common for timekeeping systems to have a single record that contains a date, a start time, and an end time. In this case, the problem is less trivial.

There are, I think, two questions you're asking:

  1. How can I tell if a time span crosses midnight?
  2. If a time span crosses midnight, how much of the time happened on the first day, and how much on the second?

The first question is easily answered: if the end time is before the start time, the time span has crossed midnight.

If this is the case, then you have two amounts to calculate. The amount of the time span that occurred on the date is the time between the start time and midnight. The amount of the time span that occurred on the next date is the time between midnight and the end time (i.e. just the end time).

Robert Rossney
Thank you for clarifying my own question, but that exactly what I was looking for !!
Gustavo Carreno
A: 

and if both times are not in the same time zone you'll need to convert them to UTC before doing the calculation :) May not be applicable here but it's a common issue.

ShayH