## Wednesday, October 21, 2015

### Everything you wanted to know about dates but never dared to ask, part 2

In part 1 of this series I covered what I consider to be the basics:

• Date formats
• Defining dates
• Moving values in and out of dates

In this part I am going to be covering the RPG built in functions for Date data types I use.

## Calculations using dates

In my opinion one of the best changes that came with RPGLE was the ability to do arithmetic with dates. It gave us the Add Duration, ADDDUR, and Subtract Duration, SUBDUR, operation codes. When free format was introduced in V5R1 it no longer supported these operation codes, but gave us three new built in functions:

• %DAYS
• %MONTHS
• %YEARS

Before we can see them in action I need to define the variables I am going to use:

 ```01 dcl-s Dte1 date ; 02 dcl-s DaysDiff packed(3) ; ```

And the equivalent in fixed format would be:

 ``` DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords 01 D Dte1 S D 02 D DaysDiff S 3 0 ```

Now for the built in functions:

 ```03 Dte1 = %date() + %days(21) ; 04 Dte1 -= %months(3) ; 05 Dte1 += %years(1) ; 06 DaysDiff = %diff(Dte1:%date():*d) ; ```

Line 3: I initialize the Date data type Dte1 with today's date, 2015-10-21, plus 21 days. Dte1 = 2015-11-11.

Line 4: Then I subtract 3 months from Dte1. Dte1 = 2105-08-11.

Line 5: Finally I add one year to Dte1. Dte1 = 2016-08-11.

Line 6: Using the Difference between two dates built in function, %DIFF, I calculate the number of days between Dte1 and today. DaysDiff = 295.

Rather than using %DATE, I could have hard coded the dates:

 ```03 Dte1 = d'2015-10-21' + %days(21) ; 06 DaysDiff = %diff(Dte1:d'2015-10-21':*d) ;```

I am not advocating the replacement of %DATE with hard coded dates, I just wanted to show what was possible.

There is a gotcha with using the %MONTHS. What happens when I do this?:

 ```01 Dte1 = d'2015-01-31' + %months(1) ; 02 Dte1 -= %months(1) ; ```

Line 1: If I add one month to January 31 2015 I cannot get February 31 2015 as that is an invalid date. I get the last day of February instead, so Dte1 = 2015-02-28.

Line 2: Now if I subtract one month from Dte1 I get 2015-01-28.

I can use the %DIFF in more interesting ways. For example for determining employees' age:

 ``` Age = %diff(%date():BIRTHDTE:*y) ; ```

How about finding all employees who have been employed for less than three months.

 ``` if (%diff(HIREDTE:%date():*m) < 3) ; ```

## Extracting parts of the date

Dates have their own special substring built in function, %SUBDT. The first parameter of the built in function is the name of the Date data type variable, and the second which part of the day I want to extract. But first I need to define my variables:

 ```01 dcl-s Dte1 date inz(d'2105-10-21') ; 02 dcl-s Days packed(2) ; 03 dcl-s Months packed(2) ; 04 dcl-s Year packed(4) ; ```

The fixed format equivalent would be:

 ``` DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords++++++++++ 01 D Dte1 D inz(d'2015-10-21') 02 D Days S 2 0 03 D Months S 2 0 04 D Year S 4 0 ```

Now can substring out the parts of the date:

 ```01 Days = %subdt(Dte1:*d) ; 02 Months = %subdt(Dte1:*m) ; 03 Year = %subdt(Dte1:*y) ; ```

Line 1: I am substring-ing the days part of the date as I have given *D as the second parameter. I could have used *DAYS rather than *D. If you are a regular reader of this blog it should come as no surprise that I have used the abbreviation *D. Days = 21.

Line 2: Now for the month, *M. Months = 10.

Line 3: Finally the year, *Y. No matter what date format is used the substring-ed year will always be YYYY. Year = 2015.

Others in this series include: