subtracting time duration

G

Guest

Hi,

Why is it so difficult to subtract time durations eg: (hours/min) 4:30 -
2:00 should equal 2:30.

My start duration is automatically calculated and my end duration is
manually entered but both are formated as "Short Time".

The expression for the difference in duration is a simple
endduration-startduration

Please help?
 
G

Guest

There is actually no such thing in Access as a Time value, only a Date/time
value. Date/time values are implemented as a 64 floating point number with
an origin at 30 December 1899 00:00:00. The integer part represents the
days, the fractional part the times of day. When you enter or compute a
'time' you in fact enter or compute that time on 30 December 1899. If you
do arithmetic on these values the date part is irrelevant as they are the
same day, but what you get when you do the arithmetic is the underlying
floating point number. To express this as time you need to format it, so:

Format(#4:30# - #2:00#,"h:nn") returns 2:30.

This is fine so long as the times are all within the same day, but it gets
trickier when dealing with times on different days. You might find the
following which I wrote for a magazine column some years ago of interest:

Using Access take a simple timesheet table :

CREATE TABLE TimeSheet
(EmployeeID LONG NOT NULL,
DateTimeIn DATETIME NOT NULL,
DateTimeOut DATETIME NOT NULL);

With rows covering one week:

INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#09/30/2002 08:45:00#, #09/30/2002 13:00:00#);
INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#09/30/2002 13:45:00#, #09/30/2002 18:00:00#);
INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#10/01/2002 08:30:00#, #10/01/2002 12:45:00#);
INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#10/01/2002 14:00:00#, #10/01/2002 18:05:00#);
INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#10/02/2002 09:00:00#, #10/02/2002 13:10:00#);
INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#10/02/2002 13:55:00#, #10/02/2002 17:40:00#);
INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#10/03/2002 08:30:00#, #10/03/2002 13:00:00#);
INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#10/03/2002 13:30:00#, #10/03/2002 17:20:00#);
INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#10/04/2002 08:40:00#, #10/04/2002 13:05:00#);
INSERT INTO TimeSheet (EmployeeID, DateTimeIn, DateTimeOut) VALUES(1,
#10/04/2002 13:55:00#, #10/04/2002 17:25:00#);

Most Access users realize that date/time values are actually stored as a
double precision floating point number and its thus possible to to date/time
arithmetic very easily. They reason that simply subtracting the
DateTimeInValue from the DateTimeOut value in each row will give the time
worked. If the resulting value is formatted "hh:nn:ss" this will display the
result in hours, minutes and seconds (the seconds will always be zero of
course with every time-keeping system I've encountered, but could come into
play with a telephone billing system for instance). A query like this seems
to give the correct results:

SELECT EmployeeID,
FORMAT(DateTimeIn,"dddd dd mmmm yyyy AM/PM") AS DateWorked,
FORMAT(DateTimeOut - DateTimeIn,"hh:nn:ss") AS TimeWorked
FROM TimeSheet
ORDER BY DateTimeIn;

Producing:

EmployeeID DateWorked TimeWorked
--------------------------------------------------------------------------------------------------------------------
1 Monday 30 September 2002 AM 04:15:00
1 Monday 30 September 2002 PM 04:15:00
1 Tuesday 01 October 2002 AM 04:15:00
1 Tuesday 01 October 2002 PM 04:05:00
1 Wednesday 02 October 2002 AM 04:10:00
1 Wednesday 02 October 2002 PM 03:45:00
1 Thursday 03 October 2002 AM 04:30:00
1 Thursday 03 October 2002 PM 03:50:00
1 Friday 04 October 2002 AM 04:25:00
1 Friday 04 October 2002 PM 03:30:00

It would seem logical that to get the hours worked for the whole week. all
that's necessary is to SUM the half-daily time differences and format the
result in the same way:

SELECT EmployeeID,
FORMAT(DateTimeIn,"ww") AS WeekNumber,
FORMAT(SUM(DateTimeOut - DateTimeIn),"hh:nn:ss") AS TimeWorked
FROM TimeSheet
GROUP BY EmployeeID, FORMAT(DateTimeIn,"ww");

which produces:

EmployeeID WeekNumber TimeWorked
------------------------------------------------------------------------------------
1 40 17:00:00

Now this employee is not going to be too happy when they get their pay
cheque for week 40 as they only seem to have worked 17 hours. How come?
What many people don't realize is that there is no such thing in Access as a
time value independent of a date. Every date/time value is a unique point in
time. If the TimeWorked column was formatted as a full date/time it would be
31/12/1899 17:00:00. The date part has simply been lost in the formatting as
"hh:nn:ss". When the differences between the underlying floating point
numbers are summed they give the correct total time for the week in days
worked. If the formatting of the TimeWorked column is omitted this can be
seen:

SELECT EmployeeID,
FORMAT(DateTimeIn,"ww") AS WeekNumber,
SUM(DateTimeOut - DateTimeIn) AS TimeWorked
FROM TimeSheet
GROUP BY EmployeeID, FORMAT(DateTimeIn,"ww");

produces:

EmployeeID WeekNumber TimeWorked
------------------------------------------------------------------------------------
1 40 1.70833333332848

i.e. approx 1.7 days have been worked in the week ( that's 1.7 * 24 hours,
not 1.7 * 7.5 or whatever the nominal working day for the organisation is).

How then do we get the total time worked in the week expressed as hours,
minutes and seconds? What I usually do, however, when working with large
units (of any kind, not just time) which have to be broken down into smaller
units is to first convert the value into the smallest unit required and then
calculate the larger units and remainders from that. In this case the
following function is used , which takes the value in seconds as its argument
and returns a string in the format "hh:nn:ss":

Function SecsToHours(lngSecs As Long) As String

Const SECONDS_IN_DAY As Long = 86400

Dim lngWholeDays As Long, lngSeconds As Long

If lngSecs < SECONDS_IN_DAY Then
SecsToHours = Format(lngSecs / SECONDS_IN_DAY, "hh:nn:ss")
Else
lngWholeDays = Int(lngSecs / SECONDS_IN_DAY)
lngSeconds = lngSecs Mod SECONDS_IN_DAY

SecsToHours = ((lngWholeDays * 24) + Format(lngSeconds /
SECONDS_IN_DAY, "hh")) & _
Format(lngSeconds / SECONDS_IN_DAY, ":nn:ss")
End If

End Function

In a query the DateDiff function is used to get the times in seconds and
this value is passed into the function:

SELECT EmployeeID,
FORMAT(DateTimeIn,"ww") AS WeekNumber,
SecsToHours(SUM(DateDiff("s",DateTimeIn, DateTimeOut))) AS
TimeWorked
FROM TimeSheet
GROUP BY EmployeeID, FORMAT(DateTimeIn,"ww");

to give:

EmployeeID WeekNumber TimeWorked
------------------------------------------------------------------------------------
1 40 41:00:00



Ken Sheridan
Stafford, England
 
J

John Vinson

Hi,

Why is it so difficult to subtract time durations eg: (hours/min) 4:30 -
2:00 should equal 2:30.

Because Access date/time values ARE NOT DURATIONS.

They are points in time; a Date/Time value is stored as a Double Float
number, a count of days since midnight, December 30, 1899. For
example, 4:30 is actually stored as 0.1875, and corresponds to
#12/30/1899 04:30:00#.
My start duration is automatically calculated and my end duration is
manually entered but both are formated as "Short Time".

The expression for the difference in duration is a simple
endduration-startduration

I'd suggest storing times of day as date/time values; if you need to
span midnight, it's best to store the date and the time together (the
Now() function will store the system clock date and time for you). You
can use DateDiff to calculate the time elapsed between two date/time
values: DateDiff("n", [StartTime], [EndTime]) will give the number of
miNutes ("m" is Months).

To store durations I'd recommend storing minutes (or seconds, or
hours, or whatver precision you need) in a Long Integer field. You can
format this for display with an expression like

[Duration] \ 60 & Format([Duration] MOD 60, ":00")

John W. Vinson[MVP]
 
G

Guest

Ken,

Thanks very much for this information. Mein its so much to think about. I
never though it was so complicated.

I will use it and see how much it helps me.

Thanks again
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top