|
|
![]() |
|
|
Back To Basics: The Date Data Type by Kevin Vandever [The code for this article is available for download.]
How many times this year have you had to cross out the year on a check or some other document you signed because you forgot we are now in 2003? I know, I've done it too. Well, this article will not help with that problem one bit; but it will provide an overview of a data type that is not only easy and flexible to use but also significantly eases many business calculation and display issues that existed up to the point of their introduction. I'm talking about the date data type. First Date The date data type is neither a string nor a number, and therefore it is incompatible with each of them. The reason I mention that is because, in the old days, we didn't have a date data type and had to use either character or numeric data to store and display dates. It also meant that we had to jump through hoops to perform date math because simple numeric data wasn't, and still isn't, aware of the many rules that dates have to follow. Well, that is no longer the case. There is now a date data type at our disposal that allows us to do all sorts of things to date data without having to jump through those darn hoops. The date data type is based on the Gregorian calendar and is broken up into three parts: year, month, and day. Depending on the format of the date, there are a variety of valid ranges for the year. The month, in any format, can range from 1 to 12, and the day ranges from 1 to 28, 29, 30, or 31, depending on the month and whether it is a leap year. DB2 stores dates as a 4-byte integer. I know, I said earlier that dates are neither strings nor numbers, and now I'm saying they are stored as numbers. Well, that's correct. The date is stored in the database as a 4-byte number, but it is represented in one of many data formats, as shown in the data type section of IBM's ILE RPG reference manual (see Table 13). Notice that the 2-digit date formats contain many potential separators. These separators can be initialized in the D-spec, using the optional separator parameter of the DATFMT keyword. The 4-digit date data types do not allow you to change the separator. The default date data type is *ISO, but you can override that using the DATFMT keyword in a control specification (H-spec) or at the D-spec when defining a date. A program can have many dates defined, all with different formats. As I mentioned before, the year part of a date has different limits depending on the format. Also in the IBM ILE RPG reference manual (see Table 14) is a list of the formats, default values, and high and low values of each date. This is important to note because the range on the year is quite different among formats. For example, just about any year works for the 4-digit year formats; however, if you still use a 2-digit year format, you are limited to a range of 1940 to 2039. Do the Math Date data formats do more than make the date look good. They also allow you to perform mathematical operations on dates while you rest easy knowing that your result will always contain a valid value, which wasn't the case when we used to perform date math using plain old numbers. For example, if you take any date representation of May 5, 2002, and subtract five days from that day using date math, you will get April 30, 2002. If you try that with numeric data, you get the following: 20020505 6 = 20020499, or April 99, 2002, which, of course, isn't a valid date. Like I said before, we had to jump through hoops to perform that type of date math before date data types. So how do you perform such date math? I've included a couple of programs to illustrate a number of ways to perform date math and manipulation. The first program, DATESTUFF1, shows four op codes you can use to manipulate date data. Before I go into them, I want to explain a couple of things. First, notice the H-spec at the top of the program. The DATEDIT keyword allows you to specify the format of numeric fields when using the Y edit code to display those fields. It is optional and really not needed in this program, because I am not formatting the numeric field, but I added it to show you that it exists. I set the DATEDIT keyword to *MDY because that matches the format of the date field I define in the D-spec, but I could have defined it as *YMD or *DMY. Be careful if you do use the DATEDIT keyword for formatting numeric data, because if it doesn't match the format of your date field and you move one to the other, you will get an error. I have defined three fields in my D-specs. The first field is the numeric field that will house the current date. Next, I define an actual date field by using a D in position 40. I then set its format to *USA, using the DATFMT keyword. If you look back at Table 13 of the ILE RPG reference manual, you will see that *USA displays the date in MM/DD/YYYY format. The last field I define is a 2-byte numeric field that will contain the days of the date field. I will talk more about that later. The first thing I do in the calculation specs is to assign today's date to the numeric field, using the *Date reserved word. I then display that field so I can see the results. Assuming the date is Jan 16, 2003, you should see 1162003. The leading 0 is suppressed. Next, I move the numeric field into my date field, WorkDate, using the Move operation. Once again I display the results. You should see 01/16/2003. Now that I have a date data type to work with, I can use date operations. The first one I'm going to employ is the add duration (Adddur) operation. This op code allows you to add some duration to a date to get another valid date. In my example, I take WorkDate and add the duration of one month to it, as signified by 1:*M. The 1 states how many of something I want to add and the *M tells me what part of the date I'm adding: in this case, months. The colon (:) separates the two parameters. When you display the results, you should now see 02/16/2003, which is the result of adding 1 month to the 01/16/2003 date. Next I use subtract duration (Subdur) to subtract one month from the date. Now when the date displays again, you should see 01/16/2003. The next two sections use the same op codes, Adddur and Subdur, but instead of adding and subtracting a month, I add and subtract 30 days. You can see the difference in factor two of the statements. One month was signified by 1:*M; whereas 30 days is signified by 30:*D. The last little bit of date math will determine the last day of the month for a given date. For example, for any date in January, the result should be 01/31/2003. If I use a February date, I should get 02/28/2003 because 2003 is not a leap year. Finally, if I use any date in April, June, September, or November, I should get a date with 30 as the number representing the month. I do this by first adding one month to the current date. In my example the result will be 02/16/2003. Next I extract the days from the date using the Extrct operation. Factor 2 tells the Extrct operation what variable to use, WorkDate, and what portion of that date to extract--in this case, the days. The result field is the numeric field defined in my D-specs that will contain the extracted data. Next, I subtract the extracted days from the date. In this case, the days will equal 16. I subtract that number of days from my date, 02/16/2003, to get the last day of the previous month, which is 01/31/2003. Before you get too comfortable with the date operations, take a look at the program DATESTUFF2. Believe it or not, this program accomplishes the same things as DATESTUFF1, but it makes use of more current methods of manipulating dates. I also threw in some free-formed RPG, which was introduced in V5R1. But you don't need free-formed RPG to use the newer techniques; I just thought I'd show you how I would code this date stuff if I were given the assignment today. (For more information on free-formed RPG, see "Let Your Hair Down With Free-Formed C-Specs.") The primary difference with this code, besides the free-formed nature, is that I used built-in functions to handle the date manipulation instead of operation codes. To add one month to my WorkDate field, I employ the %Months built-in function and give it a parameter of 1. It's very straightforward and easy to read. Much easier, in my opinion, than the op code method. To add 30 days to my date, I used the %Days function and gave it a parameter of 30. Give it shot; you'll get the same results. Finally, to obtain the last day of the month, I used the %Months function to add a month to my date, but I also embedded the %SubDt function to extract the days from the date. This function works just like the Extrct op code, except that I can embed it right in the %Days function, because it returns a numeric value. Can I Call You Again? There you have it: two ways to manipulate dates, operation codes, and built-in functions. And no one got his feelings hurt during the process. I showed you both methods because you may see both in the future. Also, it allows you the opportunity to choose the method you like best. I prefer the latter methods employed in DATESTUFF2, because they are easier to use and more intuitive, which sets them up nicely for more complicated date manipulations, which you will surely come across as you delve further into date logic. But don't worry about that too much right now. Download my code and give it a try. I think you'll like what you see.
|
Editors
Contact the Editors |
| Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved. |