Wednesday, October 21, 2015

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

Date built in functions, BIF, %DAYS %MONTHS %YEARS %DIFF and %SUBDT

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:

 

You can learn more about these BIFs on the IBM website:

 

This article was written for IBM i 7.2, and should work for earlier releases too.

1 comment:

  1. Chris Hayden has posted on AS400 Network, all possible uses of date BIFs when they 1st came for /free. I think it was 2000-2002. I still have it with me, so I pulled, and found out that much has improved since then, and the code has gotten a lot slicker due to those enhancements.

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.