You are on page 1of 8

MC Press Online

The CL Corner: More Granular Date and Time Support


Contributed by Bruce Vining Friday, 13 June 2008

Date addition is nice, but what about hours?

By Bruce Vining

In response to the recent articles on working with date durations, I received a note from Lori N. asking if similar support exists for smaller time frames. Specifically, Lori says, "Thanks for the articles; they are very helpful. I have a monitoring job that checks a data area to make sure we have sent updates to another system within a specific time frame. I used CEEDATE to get today and yesterday, but I'd also like to use a time interval so I can say 'If we have not sent anything in the last 6 hours, send an alert.' Is there something that takes the current time and subtracts a specific interval so I can compare the last times? If not, I'll have to be satisfied with checking dates. Thank you for your help with this." To which I respond, "Be satisfied with checking dates rather than hours? We should never compromise on such a basic need when working on i!"

Date addition is nice, but what about hours?

In response to the recent articles on working with date durations, I received a note from Lori N. asking if similar support exists for smaller time frames. Specifically, Lori says, "Thanks for the articles; they are very helpful. I have a monitoring job that checks a data area to make sure we have sent updates to another system within a specific time frame. I used CEEDATE to get today and yesterday, but I'd also like to use a time interval so I can say 'If we have not sent anything in the last 6 hours, send an alert.' Is there something that takes the current time and subtracts a specific interval so I can compare the last times? If not, I'll have to be satisfied with checking dates. Thank you for your help with this."

To which I respond, "Be satisfied with checking dates rather than hours? We should never compromise on such a basic need when working on i!"

There are many ways to satisfy this requirement, and in today's article we'll examine one approach based on the CEELOCT API. In future articles, we'll also look at some of the many alternatives that exist for the CL developer. Back in "So You're Looking for a Date?," we introduced the Get Current Local Time (CEELOCT) API, which returns the local time. The API documentation can be found here, and I've repeated the API's parameter list below:

http://www.mcpressonline.com

Powered by Joomla!

Generated: 29 August, 2008, 00:16

MC Press Online

Required Parameters:

output_Lilian

Output

INT4

output_seconds

Output

FLOAT8

output_Gregorian

http://www.mcpressonline.com

Powered by Joomla!

Generated: 29 August, 2008, 00:16

MC Press Online

Output

CHAR23

Omissible Parameter:

fc

Output

FEEDBACK

In that article, we concentrated on the first parameter, output_Lilian, which is a 4-byte signed integer representing the current local date in Lilian format. At that time, we briefly discussed the other parameters but effectively ignored them. Today we'll take a closer look at the second parameter, output_seconds.

Output_seconds is an 8-byte floating point value that represents the number of seconds since 00:00:00 October 14, 1582. That is, an output_seconds value of 86 401 represents 00:00:01 October 15, 1582; a value of 13 431 693 600 represents 10:00:00 June 1, 2008; and 13 431 693 601 is equivalent to 10:00:01 June 1, 2008. Similar to how output_Lilian allows us to easily add and subtract durations involving days, output_seconds allows us to easily add and subtract seconds. In our example program, we'll use a duration of 21 600 seconds, the number of seconds in six hours.

http://www.mcpressonline.com

Powered by Joomla!

Generated: 29 August, 2008, 00:16

MC Press Online

The one minor hurdle we have to overcome is that CL doesn't support floating point variables. But we won't let a little problem like that deter us from our mission! We will define output_seconds as an 8-byte character variable and then use the Copy Numeric Value (CPYNV) API (actually a Machine Interface instruction) to convert the 8-byte floating point value to a 15-digit decimal value. We won't go into the details of the Copy Numeric Value API, but the API basically allows us to convert a numeric value from one format to another. In our case, we will convert from a floating point format to a decimal (*DEC) format. The Copy Numeric Value API documentation can be found here and is briefly discussed a bit later in this article.

First, we need a program to perform some action--for instance, sending updates, as in Lori's note, and then updating a data area with the time the send was complete. The following program, Send Update (SNDUPD, performs such a function:

Pgm

Dcl

Var(&Snd_Float) Type(*Char) Len(8)

Dcl

Var(&CurLilDt) Type(*Int)

Dcl

Var(&CurGregDt) Type(*Char) Len(23)

/* Send the updates and then:

*/

CallPrc

Prc('CEELOCT') Parm((&CurLilDt) (&Snd_Float) +

(&CurGregDt) (*Omit))

ChgDtaAra DtaAra(QGPL/LSTSNDTIME) Value(&Snd_Float)

EndPgm

The above program sends the updates (shown as a comment), calls the CEELOCT API to retrieve the current date and time, and then stores the returned floating point value for the current date and time (the variable &Snd_Float) in the data area QGPL/LSTSNDTIME. This data area is created with the following command:

http://www.mcpressonline.com

Powered by Joomla!

Generated: 29 August, 2008, 00:16

MC Press Online

CRTDTAARA DTAARA(QGPL/LSTSNDTIME) TYPE(*CHAR) LEN(8)

The following program, Check Last Send (CHKLSTSND), retrieves the value of the data area QGPL/LSTSNDTIME, determines if more than six hours have elapsed since the last send operation, and then takes appropriate action.

Pgm

Dcl

Var(&Snd_Float) Type(*Char) Len(8)

Dcl

Var(&Snd_Dec)

Type(*Dec) Len(15 0)

Dcl

Var(&Cur_Float) Type(*Char) Len(8)

Dcl

Var(&Cur_Dec)

Type(*Dec) Len(15 0)

Dcl

Var(&Alert_Time) Type(*Dec) Value(21600)

Dcl

Var(&Delay_Time) Type(*Dec)

Dcl

Var(&Float_Dfn) Type(*Char) Len(7) +

Value(X'01000800000000')

Dcl

Var(&Dec_Dfn)

Type(*Char) Len(7) +

Value(X'03000F00000000')

Dcl

Var(&CurLilDt) Type(*Int)

Dcl

Var(&CurGregDt) Type(*Char) Len(23)

Loop:

RtvDtaAra DtaAra(QGPL/LSTSNDTIME) RtnVar(&Snd_Float)


Powered by Joomla! Generated: 29 August, 2008, 00:16

http://www.mcpressonline.com

MC Press Online

CallPrc

Prc('_LBCPYNV') Parm((&Snd_Dec) (&Dec_Dfn) +

(&Snd_Float) (&Float_Dfn))

CallPrc

Prc('CEELOCT') Parm((&CurLilDt) (&Cur_Float) +

(&CurGregDt) (*Omit))

CallPrc

Prc('_LBCPYNV') Parm((&Cur_Dec) (&Dec_Dfn) +

(&Cur_Float) (&Float_Dfn))

If

Cond((&Cur_Dec - &Snd_Dec) > &Alert_Time) +

Then(Do)

SndPgmMsg Msg('Time to send alert') +

ToPgmQ(*Ext)

ChgVar Var(&Delay_Time) Value(300)

EndDo

Else

Cmd(ChgVar Var(&Delay_Time) +

Value(&Alert_Time - (&Cur_Dec - &Snd_Dec) +

+ 1))

DlyJob

Dly(&Delay_Time)

GoTo

CmdLbl(Loop)

EndPgm
http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:16

MC Press Online

Within CHKLSTSND, we first declare the variables we will be using. &Snd_Float is an 8-byte character field that will contain the floating point value stored by the SNDUPD program. Note that there is an assumption that the SNDUPD program has run at least one time prior to calling program CHKLSTSND. &Snd_Dec is defined as TYPE(*DEC) with 15 digits and no decimal positions. This declared size for &Snd_Dec is sufficient to hold a number of seconds since October 14, 1582, that exceeds the year 9999 (which should be sufficient for our needs) and will be used to hold the decimal equivalent of &Snd_Float. &Cur_Float is an 8-byte character field that will store the floating point value of the number of seconds since October 14, 1582, and the current local date and time. &Cur_Dec is the 15-digit decimal equivalent of &Cur_Float. &Alert_Time is a decimal value used to store the number of seconds in a duration of six hours (21 600 seconds), and &Delay_Time is a decimal value used to control how often the CHKLSTSND program runs.

&Float_Dfn is a 7-byte character field that defines the type of numeric value the Copy Numeric Value API is converting from. The initialized value x' 01000800000000' defines an 8-byte floating point value. &Dec_Dfn is a 7-byte character field that defines the type of numeric value the Copy Numeric Value API is to convert to. The initialized value x' 03000F00000000' defines a 15-digit packed decimal variable with no decimal positions. Details on these initialization values can be found here for those of you with inquiring minds.

The last two variables, &CurLilDt and &CurGregDt, are needed when calling the CEELOCT API but are not used in the current program.

When run, CHKLSTSND first retrieves the floating point value stored by SNDUPD in the data area QGPL/LSTSNDTIME. CHKLSTSND then uses the Copy Numeric Value API to convert this floating point value to a decimal value and stores the result in &Snd_Dec. The program calls the CEELOCT API to retrieve the current date and time in seconds (the variable &Cur_Float) and calls Copy Numeric Value to convert this floating point value to the decimal variable &Cur_Dec.

Having now obtained the time in seconds for both the last send function and the current time, CHKLSTSND compares the difference (&Cur_Dec - &Snd_Dec) to the maximum number of seconds that should elapse between send operations (the variable &Alert_Time). If more than &Alert_Time seconds have elapsed, CHKLSTSND sends an alert (shown for simplicity as a SNDPGMMSG) and then sets &Delay_Time to 300 seconds (or five minutes).

If the amount of elapsed time is less than &Alert_Time, the program calculates how many seconds of &Alert_Time remain after the last successful send operation and sets &Delay_Time to this value (plus one second).

The program then uses the DLYJOB command to delay &Delay_Time seconds and loops back to retrieving the floating point value stored by SNDUPD. If CHKLSTSND is in an alert status, the program will alert the operator every five minutes that something is wrong and continue with such alerts until SNDUPD successfully updates the data area QGPL/LSTSNDTIME. Otherwise, the program will sleep until an alertable situation exists, based on no further activity by
http://www.mcpressonline.com Powered by Joomla! Generated: 29 August, 2008, 00:16

MC Press Online

the SNDUPD program.

In the next article, we'll look at how to make this process more friendly to an operator. Specifically, we will look at how to store a formatted date in the LSTSNDTIME data area, rather than a floating point value, so that a user could use the DSPDTAARA command and easily see when the last successful send operation was. We'll also add a check allowing the CHKLSTSND program to end in a controlled manner (as another reader, Sam M., has asked how to determine in CL if an ENDJOB has been issued for the current job).

Subsequent articles will look at non-ILE CEE based approaches that also allow us to easily working with time durations.

Before we close, please note that the sample programs SNDUPD and CHKLSTSND are working with local time values. This has an implication for those areas of the world that observe Daylight Saving Time (DST). When "springing forward" by 60 minutes (or whatever DST time shift you might be using), the alert processing can occur prior to &Alert_Time seconds having actually elapsed. Likewise, when "falling back," alert processing may be deferred by up to the amount of the DST time shift. If this would be a problem for your application, you will want to look at the Get Universal Time Coordinated (CEEUTC) API documented here. The CEEUTC API returns the current time as a UTC normalized value in both Lilian day and Lilian second formats. More CL Questions?

Wondering how to accomplish a function in CL? Send your CL-related questions to me at bvining@brucevining.com. I'll try to answer your burning questions in future columns.

http://www.mcpressonline.com

Powered by Joomla!

Generated: 29 August, 2008, 00:16

You might also like