How to Calculate the Time Lapsed Between Two Dates & Times?

The exercise records the date and time a user logs onto a program, and at a later time logs off. The exercise is to measure the time lapsed.
The lapsed time may extend over multiple days, and needs to return days, hours and minutes. Any assistance or direction would be appreciated.

image

I haven’t tested this at all, but something like this seems like what you’re looking for.

TIME:Tick   EQUATE(  1)
TIME:Second EQUATE(100 * TIME:Tick)
TIME:Minute EQUATE( 60 * TIME:Second)
TIME:Hour   EQUATE( 60 * TIME:Minute)
TIME:Day    EQUATE( 24 * TIME:Hour  )

Dates.Span PROCEDURE(LONG xDateA, LONG xTimeA, LONG xDateB, LONG xTimeB, *LONG xOutSpanDays, *LONG xOutSpanTime)
FirstDate  LONG,AUTO 
FirstTime  LONG,AUTO 
SecondDate LONG,AUTO 
SecondTime LONG,AUTO 

    CODE 
    IF (xDateA < xDateB) OR (xDateA = xDateB AND xTimeA < xTimeB)
       FirstDate  = xDateA 
       FirstTime  = xTimeA 
       SecondDate = xDateB
       SecondTime = xTimeB
    ELSE 
       FirstDate  = xDateB 
       FirstTime  = xTimeB 
       SecondDate = xDateA
       SecondTime = xTimeA
    END 

    xOutSpanDays = SecondDate - FirstDate 

    IF FirstTime <= SecondTime 
       xOutSpanTime = SecondTime - FirstTime 
    ELSE 
       xOutSpanDays -= 1
       xOutSpanTime  =  FirstTime - ( SecondTime - TIME:Day )
    END
2 Likes

You have the Duration class that was done as part of a series of Clarion Live Webinars.

Open the Clarion Live Search and type Duration. Part 1 was #491 on Dec 7 2018, Part 2 was #495 on Jan 4 2019, Part 3 was #497 on Jan 18.

1 Like

You should read the help on Clarion Standard Date so you understand a Date in a LONG is stored as the number of Days since 12/28/1800. To get Days between dates you can simply subtract the 2 dates. It harder to use human understandable forms for Day, Month, Year. For that use FORMAT(, @d#) or functions Day(), Month(), Year(), Date().

Also read about Clarion Standard Time so you understand a Time in a LONG is stored as the number of Hundredths of Seconds since midnight … Plus 1 … that +1 is important.

TimeHMS  PROCEDURE(SHORT H, SHORT M, SHORT S=0, SHORT Hundredths=0)!,LONG 
!This allows out of range HMS values, e.g. you can pass 90 minutes. This can produce an invalid time beyond 23:59:59. 
    CODE
    RETURN (H * 60*60*100) + |
           (M *    60*100) + |
           (S *       100) + |
           Hundredths + 1

The DATE and TIME types are different with the Internal Format as YYYYMMDD and HHMMSShh. Anytime they are used in code they are converted to Standard versions i.e. YMD becomes Days since 12/28/1800.

These can be used in code like below to split a DATE or TIME into parts. For dates you have functions for this. Time does not have these so this type of function can be used, or FORMAT(,@T05) that’s HHMMSS.

DateSplit        PROCEDURE(LONG Date2Split, *? OutMonth, *? OutDay, *? OutYear)
!==============================================================================
DateSplit PROCEDURE(LONG D, *? OutMonth, *? OutDay, *? OutYear)
!This is much faster than calling MONTH() DAY() YEAR()
D1 DATE
DG GROUP, OVER(D1)
D BYTE
M BYTE
Y USHORT
  END
    CODE
    D1=D
    OutMonth=DG.M
    OutDay=DG.D
    OutYear=DG.Y
    RETURN
!--------------------------------------------------------------------

TimeSplit PROCEDURE(LONG T, *? OutHour, *? OutMin, <*? OutSec>, <*? OutHund>)
!This is faster than using HOUR() MINUTE() SECOND()
T1 TIME
TG GROUP, OVER(T1)
F BYTE
S BYTE
M BYTE
H BYTE
  END
    CODE
    T1=T
    OutHour=TG.H
    OutMin =TG.M
    IF ~OMITTED(OutSec) THEN OutSec =TG.S.
    IF ~OMITTED(OutHund) THEN OutHund=TG.F.
    RETURN

Many thanks for your detailed response.

Outlook-1484646882.png

Likely irrelevant and late, but I do not see it explicitly stated that topspeed files are being used. For SQL users, calculating an interval with Clarion code is probably not necessary.

Here is something I use on signing out of a time clock. It’s a bit different and doesn’t care much about seconds.

First when clicking the signout button:
HOU:SIGNOUT=clock()
HOU:OUTDATE=today()
do figmins
HOU:TOTAL_HRS=(minutes * 6000) + 1

DISPLAY

figmins routine
set:round_time=0
hou:signin=deformat(format(hou:signin,@t3),@t3)
hou:signout=deformat(format(hou:signout,@t3),@t3)

if hou:outdate-hou:indate > 0

  !**** get time for first day
  td$ = 8640000 - hou:signin  !8640000 = # of 100ths of a sec in one day
  minutes = round(td$/6000,1) !*** num of minutes

  !**** get time for days inbetween day 0 and last day
  if hou:outdate - hou:indate > 1
    minutes = minutes + (((hou:outdate-hou:indate)-1)*1440)
  .

  !**** get time for last day
  minutes+=round(hou:signout/6000,1)

else
  !**** if the days are the same
  minutes = round((hou:signout - hou:signin) / 6000,1) 
  minutes = round(minutes,1)
.

!***** round to nearest minutes here ***
if set:round_time>0
  if minutes => SET:ROUND_TIME
    rem$ = (minutes/set:round_time) - int(minutes/SET:ROUND_TIME) !remainder of minutes
    if rem$ >= .5
      minutes = (int(minutes/SET:ROUND_TIME) * SET:ROUND_TIME) + SET:ROUND_TIME  !round up
    else
      minutes = (int(minutes/SET:ROUND_TIME) * SET:ROUND_TIME)  !round down
    .
  else
    minutes=SET:ROUND_TIME !if less then the round time is equal to the round time
  .
.
exit

set:round_time is a local byte variable and I think its to round to the nearest 5 minutes or 15 minutes or whatever you change it to. Here I think it’s just a zero.

Hope that helps someone.

1 Like

Hi -

I suppose you have found a solution by now :slight_smile:

I have been struggling with this exact challenge for a long while . It is quite surprising how few solutions for this are available for Clarion.

I could only find one, and that is @MarkGoldberg’s code snippet in this post.

Mike Hanson’s (@BoxSoft ) elaborate webinar recordings (that @CarlBarnes refers to below) only does formatting of a duration, but does not calculate a duration per sé (as I understand it).

@MarkGoldberg for not being tested - I find this code quite good!

It seems to work really well. The ONLY solution I found on the whole web :slight_smile: after many weeks of searching!

Perhaps one correction: in this line I had to change the second minus to a plus. Not 100% sure about this, but my tests then seems to deliver “more” correct results:

xOutSpanTime = FirstTime - ( SecondTime - TIME:Day ) should be
xOutSpanTime = FirstTime - ( SecondTime + TIME:Day )

… I think…

Hi Carl - after many hours with the three recordings, it seems these do NOT cover calculating a duration. Only formatting the display of it.

There is a template for dates calculations (fsDates). You can find it here: Download Clarion Templates and Tools from Icetips Alta LLC

1 Like

Hi Fred

I haven’t tested anything but I think I would have done:

instead as:

    IF FirstTime > SecondTime
        SecondDate -= 1
        SecondTime += TIME:Day
    END
    xOutSpanDays = SecondDate - FirstDate
    xOutSpanTime = SecondTime - FirstTime 

to me that seems clearer, but of course everyone is different!

there should also be lots of other solutions floating around using “star dates” or “StarDate”. It is a simple and effective scheme where one uses a REAL or DECIMAL and “with Clarion standard date on the left side of the decimal point and Clarion standard time on the right side, by dividing it by 8640000. (number of 1/100th of seconds in one day.)” Some people adjust the standard time by 1 to reflect that midnight is 1 not 0 but it probably doesn’t matter as long as you are consistent.

anyway hth

1 Like

Here’s a StarDate class, which can convert a Date+Time into a REAL that represents the date as the integer and time as the fraction of the day (via the CalcStarDate method).

Given two StarDates, you can do basic math to calculate the difference between them. That calculated difference is also a StarDate. If its value is less than 1, then the duration between the two original StarDates was less than 1 whole day. For example, 12 hours is 0.5 as a StarDate.

To convert from a StarDate back to Clarion Date+Time, you use the SplitStarDate method. This will give you the number of days difference (0, if it’s less than one day), as well as any remaining time beyond the number of whole days.

StarDate.clw (2.7 KB)
StarDate.inc (832 Bytes)

1 Like

Hi Mike,
Where might one find ‘DateTime.equ’ referenced in StarDate.inc ?

Probably Time.Equ in Mark’s GitHub LiibSrc folder

   OMIT('*** IFDEF ***', TIME:Second)
TIME:Tick   EQUATE(  1)
TIME:Second EQUATE(100 * TIME:Tick)
TIME:Minute EQUATE( 60 * TIME:Second)
TIME:Hour   EQUATE( 60 * TIME:Minute)
TIME:Day    EQUATE( 24 * TIME:Hour  )
 !END-OMIT('*** IFDEF ***', TIME:Second)

Above is the original code from Mark’s Repo. Below I added a comment with the numeric values of the equates to help grasp what they are:

TIME:Tick   EQUATE(  1)                !1/100th Second
TIME:Second EQUATE(100 * TIME:Tick)    !100
TIME:Minute EQUATE( 60 * TIME:Second)  !6,000            60*100
TIME:Hour   EQUATE( 60 * TIME:Minute)  !360,000       60*60*100
TIME:Day    EQUATE( 24 * TIME:Hour  )  !8,640,000  24*60*60*100

Edit: I see there is no Equate for TIME:Midnight that is used in the class. The Help says 1 = Midnight. The Clarion way the day ends at 11:59:59pm 23:59:59 (8640000) and begins at Midnight (1) which is 12:00:00am. That’s not quite intuitive to me, but it is how it is.

The valid range is from 1 (defined as midnight) to 8,640,000 (defined as 11:59:59.99 PM). A standard time of one is exactly equal to midnight to allow a zero value to be used to detect no time entered.

So maybe TIME:Midnight EQUATE(1) which looks correct for the below code to subtract 1 from the time to calculate the ratio as Clarion standard Time is +1. I would prefer that code simply be - 1.

StarDate.CalcStardate         PROCEDURE(LONG D,LONG T)!,REAL
  CODE
  RETURN D + (T - TIME:Midnight) / TIME:Day

I have a Date Time tool on Github that does Date Calculations but not Time … yet

1 Like

Oops. I forgot those extra files. :blush:

DateTime.equ (87 Bytes)
Date.equ (879 Bytes)
Time.equ (442 Bytes)

Or as a single ZIP with a bunch of stuff:

StarDate.zip (5.8 KB)

3 Likes