October 22, 2018

Show the result of Date arithmetic in the interview

When entering dates for a contract, it is important to get them right during the interview. It might be possible to control this via the Rule command, but often it is very useful to reflect this to the user as they are typing into the interview.

For the purposes of this example, we start off with one date, called StartDate, which the user will capture in the interview, and then allow the user to enter a number of years, months and days to define the duration of the contract. During the entry of these data elements, we want to be able to show the end date of the contract, in the interview, which will change as the user changes the various values. The example will use the OnExitSet command, the Script command, and various date manipulation functions.

Step 1. Capture the date and a number of years.

Here is the XpressDox code to capture the date (StartDate) and the number of years (Years) and show the result of adding the number of years (IncrementDate) to that start date in a Heading on the Place Holder called Show_EndDate:

«PlaceHolder(Show_EndDate)»
«Heading(Show_EndDate,|@Red/Microsoft Sans Serif/8.2@ )»
«CaptureDataElement(StartDate,Date)»
«OnExitSet(Years,Show_EndDate,HeadingText,(), FormatDate(IncrementDate(IncrementDate(StartDate,Years,'Y'),-1,'d'),'d MMM yyyy'),,EvenWhenNotEmpty)»

If you copy and paste this code into a template and run that template, see what happens after you enter a number into the Years and press Tab.

Note that there are two IncrementDate functions – the second subtracts one day, because the last day of a contract is always the duration less one day.

Step 2. Capture the number of months and days as well as the years.

This gets a bit more complicated, but the principle is the same. Now we want the number of Years, Months and Days to be added to the StartDate whenever we change the values of any of those three durations. This means we need an OnExitSet for each of the 3 duration elements. Here is the OnExitSet for the Years data element:

«OnExitSet(Years,Show_EndDate,HeadingText,(), FormatDate(IncrementDate(IncrementDate(IncrementDate(IncrementDate(StartDate,Years,'Y'),Months,'M'),Days,'D'),-1,'d'),'d MMM yyyy'),,EvenWhenNotEmpty)»

This OnExitSet will add the Years, Months and Days to the StartDate, subtract 1 day and set that value into the heading of the ShowEnd_Date placeholder.

Diversion: Chaining functions

One obvious point to make is that the syntax of this OnExitSet is quite difficult to read (and quite difficult to write!), because of the need to nest the function calls. To address this complexity, the concept of “function chaining” was introduced with version 10.2 of XpressDox. Using this concept, the above OnExitSet can be re-written as:

«OnExitSet(Years,Show_EndDate,HeadingText,(),
IncrementDate(StartDate,Years,'Y')->IncrementDate(^,Months,'M')->IncrementDate(^,Days,'D')->IncrementDate(^,-1,'d')->FormatDate(^,'d MMM yyyy'),
,EvenWhenNotEmpty)
»

The “->” symbol can be read as “pass the result into”, or “goes into”.

This means that the entire set of commands needed to show the result of adding all three duration elements to StartDate (and then subtracting one day) and showing the value in the interview is:

«PlaceHolder(Show_EndDate)»
«Heading(Show_EndDate,|@Red/Microsoft Sans Serif/8.2@  )»
«CaptureDataElement(StartDate,Date)»

«OnExitSet(Years,Show_EndDate,HeadingText,(),
IncrementDate(StartDate,Years, 'Y')->IncrementDate(^,Months, 'M')->IncrementDate(^,Days, 'D')->IncrementDate(^,-1, 'd')->FormatDate(^,'d MMM yyyy'),
,EvenWhenNotEmpty)
»

«OnExitSet(Months,Show_EndDate,HeadingText,(),
IncrementDate(StartDate,Years, 'Y')->IncrementDate(^,Months, 'M')->IncrementDate(^,Days, 'D')->IncrementDate(^,-1, 'd')->FormatDate(^,'d MMM yyyy'),
,EvenWhenNotEmpty)
»

«OnExitSet(Days,Show_EndDate,HeadingText,(),
IncrementDate(StartDate,Years, 'Y')->IncrementDate(^,Months, 'M')->IncrementDate(^,Days, 'D')->IncrementDate(^,-1, 'd')->FormatDate(^,'d MMM yyyy'),
,EvenWhenNotEmpty)
»

Step 3. Introduce a Script with Parameters

It is fairly obvious that the three OnExitSets are going to do the job, but it does seem a bit clumsy. The creation of the three would probably be done with copy-and-paste from the first, and change the Years to Months and Days in the second two, respectively.

It would also be nice, in future, to re-use this code for other dates, maybe even in the same template, without the copy-and-paste issues.

Looking at the three OnExitSets, the code is exactly the same, except for the trigger data element in each case, and so now the common code is put into a Script, with the trigger data element name being a parameter, like this:

«Script(ShowDateOnExit,DateElement)»
«OnExitSet(&DateElement&,Show_EndDate,HeadingText,(),
IncrementDate(StartDate,Years,'Y')->IncrementDate(^,Months,'M')->IncrementDate(^,Days,'D')->IncrementDate(^,-1,'d')->FormatDate(^,'d MMM yyyy'),
,EvenWhenNotEmpty)
»
«ScriptEnd()»

And instead of the three, long-winded, OnExitSets, we now have:

«ShowDateOnExit(Years)»
«ShowDateOnExit(Months)»
«ShowDateOnExit(Days)»

Notice how it is not necessary to use «UseScript(ShowDateOnExit, Years)» (although this will have the same effect). The syntax for invoking the Script is similar to that of any other XpressDox command.

The full set of XpressDox code to define the PlaceHolder, Heading and the OnExits looks like this:

«Script(ShowDateOnExit,DateElement)»
«OnExitSet(&DateElement&,Show_EndDate,HeadingText,(),
IncrementDate(StartDate,Years,'Y')->IncrementDate(^,Months,'M')->IncrementDate(^,Days,'D')->IncrementDate(^,-1,'d')->FormatDate(^,'d MMM yyyy'),
,EvenWhenNotEmpty)
»
«ScriptEnd()»

«PlaceHolder(Show_EndDate)»
«Heading(Show_EndDate,|@Red/Microsoft Sans Serif/8.2@ )»
«CaptureDataElement(StartDate,Date)»

«ShowDateOnExit(Years)»
«ShowDateOnExit(Months)»
«ShowDateOnExit(Days)»