I wanted a handy little RPG code snippet to return the day name for a date. My requirement was to feed in a date like “Nov 30 2017” and it to tell me that its ‘Thursday’. Google to the rescue, I found a nice little article by RAFAEL VICTORIA-PEREIRA (Thankyou Sir!) which has a code sample doing 99% of what I want. It’s a couple of years old so, a quick code refactor, modernize and here it is.
Original old style RPG article is here
Here are the two main code snippets in a Service program ready for your copy/paste delight:
Service Program @SRVDATE to find DAY OF THE WEEK
// +---------------------------------------------------------+ // | Name - @SRVDATE | // | Function - Look up a date and return the day name | // +---------------------------------------------------------+ // // CRTRPGMOD MODULE(@srvdate ) // DBGVIEW(*NONE) // BNDDIR('yourbinder') // ---------- // CRTSRVPGM SRVPGM(@srvdate ) // MODULE(@srvdate ) // EXPORT(*ALL) // SRCFILE(@BINDER) // SRCMBR(@srvdate ) // ACTGRP(*CALLER) // REPLACE(*YES) // // Modification History // 2017-11-30 NJL01 Created as part of version(185) revamp project. // ---------------------------------------------------------------- ctl-opt debug option(*nodebugio:*srcstmt) datfmt(*iso-) timfmt(*iso.) fixnbr(*zoned:*inputpacked) indent('| ') truncnbr(*yes) expropts(*resdecpos) copyright('| @srvdate 2017.11.30') nomain; // Day of the week (returns the day of the week of a given date as nbr) // From Monday(1) thru Sunday(7) dcl-proc #rtvDayNumber export; dcl-pi #rtvDayNumber zoned(1); p_Date date const; end-pi; dcl-s rtnDayNumber zoned(1) inz(9); dcl-s RefDate date inz(d'0001-01-01'); // Validate input date (this should be good but lets double check to be sure) TEST(E) p_Date; IF %ERROR; RETURN rtnDayNumber; ENDIF; // If the input parm is ok, calculate the day of the week rtnDayNumber = %REM(%DIFF(p_Date:RefDate:*DAYS):7)+1; return rtnDayNumber; end-proc;
// Day of the week (returns the day of the week of a given date in text) dcl-proc #rtvDayName export; dcl-pi #rtvDayName char(10); p_Date date const; end-pi; dcl-s rtnDayName char(10) inz(*blanks); dcl-s p_daynbr zoned(1); // calculate the day number for our input date p_daynbr = #rtvDayNumber(p_date); // if our date is squiffy then return an error IF p_DayNbr < 1 Or p_DayNbr > 7; rtnDayName = '*UNKNOWN'; else; // If the input date is ok, Return the corresponding text select; when p_DayNbr = 1; rtnDayName = 'Monday'; when p_DayNbr = 2; rtnDayName = 'Tuesday'; when p_DayNbr = 3; rtnDayName = 'Wednesday'; when p_DayNbr = 4; rtnDayName = 'Thursday'; when p_DayNbr = 5; rtnDayName = 'Friday'; when p_DayNbr = 6; rtnDayName = 'Saturday'; when p_DayNbr = 7; rtnDayName = 'Sunday'; endsl; endif; return rtnDayName; end-proc;
Binder Language
STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('your signature here') EXPORT SYMBOL(#rtvDayNumber) EXPORT SYMBOL(#rtvDayName) ENDPGMEXP
Code Example
In our programs we would add that service program and then just do this for any given date:
// +-----------------------------------------------------------------+ // | #DATE - Date Handlign Procedures from SRVPGM (@SRVDATE) | // +-----------------------------------------------------------------+ dcl-pr #rtvDayNumber zoned(1); *n date const; // p_date end-pr; dcl-pr #rtvDayName char(10); *n date const; // p_date end-pr;
then in our mainline code we simply ask it for the day name
name_of_day = @rtvDayName ( someDate );
*boom
Worked like a charm.
So, I’ve got the little service program working, documented it, written this blog in less time than I would have taken to figure it out and written it myself.
This internet thing is bloody useful sometimes. I think it’s going to catch on….
Should really add the Date Format keyword to the Pr/Pi Nick or you may get “interesting” results if the programmer who uses this routine just happens to code a different default on the Ctl-Opt than was used when the service proc was created. Hard-coding th format along with Const deals with that.
Also, although the logic I use is not exactly the same (a slightly bastardized version of mine appears in the RPG “Sorcerers” redbook) – if you do away with the +1 in the main calc and then add 7 if the result was < 1 then you don't need to handle a special case "unknown". In other words: WorkNum = %diff( WorkDate : Anysunday : *days); WorkDay = %rem(WorkNum :7); // Testing for < 1 allows for the situation where the input date // is earlier than the base date (AnySunday) If WorkDay < 1; Return WorkDay += 7; Else; Return WorkDay; Endif; In mine I use two lines to do the base calc because it was a teaching example developed when we first introduced subprocs back in V3r2.