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.
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
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.
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.
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.
Hi -
I suppose you have found a solution by now
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 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
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
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)
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
Oops. I forgot those extra files.
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)