How to easily perform date conversions in RPGLE (Including Substringing!)

690 pts.
Tags:
RPG
RPG IV
RPGLE
Over the years I have had to modify my fair share of outdated code, especially when it comes to Date Conversions. Not every system uses an 8 position numeric date field. The place I'm currently at still has a number of files with a 6 position numeric date field. I was wondering if anyone else had some cool tips, tricks or techniques for doing date conversions, manipulations or value extractions. Recently, I had to write a financial program to displayed accrued debit memo charges and the only thing I could use as a control break was the date. So instead of doing multiple statements in order to substring the Year and Month from a numeric field holding a date value, I did the following. This can be done in Free-Form or Fixed-Format. D YEARMONTH S 6S 0 INZ D YearMonthDay S 8S 0 INZ(20121127) /FREE YEARMONTH = %UNS(%SUBST(%CHAR(YEARMONTHDAY):1:6)); *INLR = *ON; /END-FREE If anyone does have any cool code usage for this topic, please let me know, i'd love to see if I can get the result i need with the least amount of code.

Software/Hardware used:
V7R1

Answer Wiki

Thanks. We'll let you know when a new response is added.
*=================================================*
*              DECLARATION SPECS   *
*=================================================*
D BREAKFASTTIME   S              6S 0 INZ(083000)
D CANCELDATE      S              8S 0 INZ
D CANCELDATEISO   S               D   INZ
D CHARACTERDATE   S              6A   INZ
D DATEIN6S0       S              6S 0 INZ
D DATEIN7P0       S              7P 0 INZ
D DATEIN8S0       S              8S 0 INZ
D DATEINCHAR6     S              6A   INZ
D DATEINCHAR10    S             10A   INZ
D DATEINDMY       S               D   DATFMT(*DMY)
D DATEINEUR       S               D   DATFMT(*EUR)
D DATEINISO       S               D   DATFMT(*ISO)
D DATEINJIS       S               D   DATFMT(*JIS)
D DATEINJUL       S               D   DATFMT(*JUL)
D DATEINMDY       S               D   DATFMT(*MDY)
D DATEINUSA       S               D   DATFMT(*USA)
D DATEINYMD       S               D   DATFMT(*YMD)
D DAY             S              2S 0 INZ
D DAYINCHAR       S              2A   INZ
D DIFFINDAYS      S              4S 0 INZ
D DIFFINHOURS     S              4S 0 INZ
D DIFFINMONTHS    S              4S 0 INZ
D DIFFINYEARS     S              4S 0 INZ
D DINNERTIME      S              6S 0 INZ(190000)
D ENDTIME         S              6S 0 INZ
D ERRORMESSAGE    S             20A   INZ
D ERRORS          S               N   INZ(*OFF)
D FROMDATEINISO   S               D   INZ
D FROMTIMESTAMP   S               Z   INZ
D INVALIDDATE     S              8S 0 INZ(20091313)
D INVALIDMESSAGE  S             20A   INZ(‘WRONG DATE ERIC!!!!!’)
D LEN             S              2S 0 INZ
D MONTH           S              2S 0 INZ
D MONTHINCHAR     S              2A   INZ
D POS             S              2S 0 INZ
D STARTDATE       S              8S 0 INZ
D STARTDATEINISO  S               D   INZ
D STARTTIME       S              6S 0 INZ
D TIMEINEUR       S               T   TIMFMT(*EUR)
D TIMEINHMS       S               T   TIMFMT(*HMS)
D TIMEINISO       S               T   TIMFMT(*ISO)
D TIMEINJIS       S               T   TIMFMT(*JIS)
D TIMEINUSA       S               T   TIMFMT(*USA)
D TIMESTAMP       S               Z   INZ
D TODATEINISO     S               D   INZ
D TOTIMESTAMP     S               Z   INZ
D YEAR            S              4S 0 INZ
D YEARINCHAR2     S              2A   INZ
D YEARINCHAR4     S              4A   INZ
D YEARMONTH       S              6S 0 INZ
D YEARMONTHDAY    S              8S 0 INZ(20130221)
*=================================================*
*              CURRENT DATE & TIME  *
*=================================================*
EVAL      DATEINISO = %DATE()      2009-03-10
EVAL      DATEINMDY = %DATE()      03/10/09
EVAL      DATEINDMY = %DATE()      10/03/09
EVAL      DATEINYMD = %DATE()      09/03/10
EVAL      DATEINJUL = %DATE()      09/069
EVAL      DATEINUSA = %DATE()      03/10/2009
EVAL      DATEINEUR = %DATE()      10.03.2009
EVAL      DATEINJIS = %DATE()      2009-03-10

EVAL      TIMEINHMS = %TIME()      14:57:06
EVAL      TIMEINISO = %TIME()      14.57.06
EVAL      TIMEINUSA = %TIME()      02:57 PM
EVAL      TIMEINEUR = %TIME()      14.57.06
EVAL      TIMEINJIS = %TIME()      14:57:07

 /FREE
   DATEINISO  = %DATE();           2013-02-21
   DATEINMDY  = %DATE();           02/21/13
   DATEINDMY  = %DATE();           21/02/13
   DATEINYMD  = %DATE();           13/02/21
   DATEINJUL  = %DATE();           13/052
   DATEINUSA  = %DATE();           02/21/2013
   DATEINEUR  = %DATE();           21.02.2013
   DATEINJIS  = %DATE();           2013-02-21

   TIMEINHMS  = %TIME();           09:56:16
   TIMEINISO  = %TIME();           09.56.16
   TIMEINUSA  = %TIME();           09:56 AM
   TIMEINEUR  = %TIME();           09.56.16
   TIMEINJIS  = %TIME();           09:56:17
 /END-FREE
*=================================================*
*                 CONVERSIONS      *
*=================================================*
VALIDATE A DATE ENTERED IN BY THE USER TO SEE IF IT’S AN ACTUAL DATE
EVAL      DATEIN8S0 = INVALIDDATE
  MONITOR
EVAL      DATEINISO = %DATE(INVALIDDATE:*YMD)
  ON-ERROR
  EVAL      ERRORMESSAGE = INVALIDMESSAGE
ENDMON

RETRIEVE TODAY’S DATE IN A 7-POSITION PACKED FIELD AS CYYMMDD
EVAL      DATEIN7P0 = %DEC(%CHAR(%DATE:*CYMD0):7:0)

RETRIEVE TODAY’S DATE IN A 10-POSITION ALPHANUMERIC FIELD IN A USA FORMAT
EVAL      DATEINCHAR10 = %CHAR(DATEINUSA)         

RETRIEVE TODAY’S DATE IN AN 8-POSITION NUMERIC FIELD IN A USA FORMAT
EVAL      DATEIN8S0 = %DEC(%CHAR(%DATE:*USA0):8:0)

RETRIEVE TODAY’S DATE IN A 6-POSITION ALPHANUMERIC FIELD IN A JULIAN FORMAT
EVAL      DATEINCHAR6 = %CHAR(DATEINJUL)

CONVERT DATE IN ISO TO A 6-POSITION NUMERIC FIELD
EVAL      DATEIN6S0 = %DEC(%CHAR(DATEINISO:*YMD0):6:0)   

CONVERT DATE IN MDY TO AN 8-POSITION NUMERIC FIELD
EVAL      DATEIN8S0 = %DEC(%CHAR(DATEINISO:*ISO0):8:0)   

CONVERT DATE IN MDY TO AN 8-POSITION NUMERIC FIELD
EVAL      DATEIN6S0 = %DEC(%CHAR(DATEINMDY:*MDY0):6:0)   

RETRIEVE TODAY’S DATE IN A 10-POSITION CHARACTER FIELD IN ORDER TO SUBSTRING
EVAL      DATEINCHAR10 = %CHAR(%DATE())          
EVAL      MONTHINCHAR  = %SUBST(DATEINCHAR10:6:2)
EVAL      DAYINCHAR    = %SUBST(DATEINCHAR10:9:2)
EVAL      YEARINCHAR4  = %SUBST(DATEINCHAR10:1:4)

RETRIEVE THE VALUE OF THE MONTH, DAY, AND YEAR FROM AN ISO DATE
EVAL      MONTH = %SUBDT(DATEINISO:*M)
EVAL      DAY   = %SUBDT(DATEINISO:*D)
EVAL      YEAR  = %SUBDT(DATEINISO:*Y)

* SUBTRACT 77 MONTHS FROM AN *ISO DATE FIELD
EVAL      FROMDATEINISO = DATEINISO                     
EVAL      TODATEINISO   = FROMDATEINISO – %MONTHS(77)   

GET THE NUMBER OF DAYS, MONTHS, AND YEARS WITHIN A SPECIFIC DATE RANGE
EVAL      DIFFINDAYS = %DIFF(FROMDATEINISO:TODATEINISO:*DAYS)
EVAL      DIFFINMONTHS  = %DIFF(FROMDATEINISO:TODATEINISO:*MONTHS) 
EVAL      DIFFINYEARS   = %DIFF(FROMDATEINISO:TODATEINISO:*YEARS)      

* CONVERT AN 8-POSITION *YMD DATE INTO A 6-POS *MDY DATE FIELD
MOVE      DATEIN8S0     DATEINISO                       
EVAL      DATEIN6S0 = %DEC(%CHAR(DATEINISO:*MDY0):6:0)   

* CONVERT A 6-POSITION *MDY DATE INTO AN 8-POSITION *YMD DATE FIELD
MOVE      DATEIN6S0     DATEINMDY                       
EVAL      DATEINISO = DATEINMDY                         
EVAL      DATEIN8S0 = %DEC(%CHAR(DATEINISO:*ISO0):8:0)   

* CONVERT THE FORMAT OF AN 8-POSITION DATE FROM YMD TO A 6-POSITION MDY
MOVE      DATEIN8S0     DATEINISO                       
EVAL      DATEINMDY = DATEINISO                         
EVAL      DATEIN6S0 = %DEC(%CHAR(DATEINMDY:*MDY0):6:0)   

/FREE

  STARTDATEISO  = %DATE(DATEIN6S0:*YMD);
  STARTDATE6    = %DEC(%CHAR(STARTDATEISO:*MDY0):6:0);

  CANCELDATEISO = DATEINISO – %MONTHS(16);

  DATETODAY6    = %DEC(%CHAR(DATEINISO:*MDY0):6:0);
  DATETODAY8    = %DEC(%CHAR(DATEINISO:*MDY0):8:0);
  DATEINCHAR10  = %CHAR(%DATE());

  MONTHINCHAR   = %SUBST(DATEINCHAR10:6:2);
  DAYINCHAR     = %SUBST(DATEINCHAR10:9:2);

  FROMDATEISO   = DATEINMDY;
  FROMMONTHISO  = %SUBDT(DATEINISO:*M);
  FROMDAYISO    = %SUBDT(DATEINISO:*D);
  FROMYEARISO   = %SUBDT(DATEINISO:*Y);

  FROMDATEISO   = DATEINISO – %YEARS(1);
  TODATEISO     = DATEINISO;

  CANCELDATEISO = %DATE + %DAYS(30);
  CANCELYEAR    = %SUBDT(CANCELDATEISO:*Y);
  CANCELMONTH   = %SUBDT(CANCELDATEISO:*M);
  CANCELDAY     = %SUBDT(CANCELDATEISO:*D);

  STARTDATEISO  = %DATE();
  STARTYEAR     = %SUBDT(STARTDATEISO:*Y);
  STARTMONTH    = %SUBDT(STARTDATEISO:*M);
  STARTDAY      = %SUBDT(STARTDATEISO:*D);

  DIFFINDAYS    = %DIFF(TODATEISO:FROMDATEISO:*DAYS);
  DIFFINDAYS    = %DIFF(CANCELDATEISO:STARTDATEISO:*DAYS);

  YEARMONTH     = %UNS(%SUBST(%CHAR(YEARMONTHDAY):1:6))

/END-FREE

Discuss This Question: 9  Replies

 
There was an error processing your information. Please try again later.
Thanks. We'll let you know when a new response is added.
Send me notifications when members answer or reply to this question.

REGISTER or login:

Forgot Password?
By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy
  • BigKat
     i'd love to see if I can get the result i need with the least amount of code.   What is the result you need?  At one point you are discussing 6-digit dates and later your code example has an 8-digit date and it seems to do what it should, so I am confused as to what you are looking for.
    8,350 pointsBadges:
    report
  • Eric Witham
    BigKat, was really looking for various tips and tricks with date conversions than anything. I was actually only giving examples in the past where I had to do one thing or another. When I said "I'd love to see if I can get the result I need with the least amount of code" I simply meant i normally try to get what i need in the least amount of code lines. I don't really have a specific question other than if anyone wanted to share some of their tips and tricks.
    690 pointsBadges:
    report
  • TomLiotta
    I'd look at creating a SQL VIEW that presented all of the same columns except that it would convert any "date" values into actual DATE data types. Then these conversions wouldn't be an issue at all. Often, the more code you can push below the program level into the database level, the better things will run. As time passes and the original file is replaced program-by-program with the VIEW, eventually the file can be converted to a real SQL table; and many future problems don't happen. Future code then won't need overhead of conversions. -- Tom
    125,585 pointsBadges:
    report
  • Eric Witham
    I wouldn't use SQL for something like this. I actually never use SQL in my programs. It can get way to complicated, hard to follow for future programmers who aren't as versed in it and I have never had the need to. But that's only my opinion from past experiences.
    690 pointsBadges:
    report
  • TomLiotta
    I'm not sure I'd hire programmers who weren't more comfortable with SQL than with RPG except for specific maintenance tasks, so I wouldn't run into a problem with future developers. Actually, I can't recall the last time I worked with one who wasn't comfortable with both; it was at least 15 years ago.   I can understand the reluctance, though. It's a different mindset to think in terms of sets rather than one-at-a-time. The one-at-a-time design of most legacy programs is what leads to SQL practices that tend to complicate.   Tom
    125,585 pointsBadges:
    report
  • Eric Witham
    I've never had a problem getting a programming position with the little SQL knowledge that i have or the lack of experience in embedded SQL. Most companies want their developers to write programs that can easily be maintained by future programmers. At a few places, I've been told not to use embedded SQL just because it's not typically common knowledge with programmers anymore. I don't think it's right that you speak with a stigma on those who don't use SQL and label them as unable to think in terms of you. But thanks for taking this post to a different level. This was really about giving people an easier way to convert dates and use the tools that IBM gives us instead of sticking with the same code that programmers from the S/36 or RPGII days. I thought it would be cool to show people new ways of doing old things.
    690 pointsBadges:
    report
  • TomLiotta
    A big reason it's not as common as the knowledge could be is that those who learn solid SQL techniques tend to go on to better jobs. Those who don't, tend to stay behind. That leads to a shrinking concentration centered around older technologies such as RPGII and S/36 code. Effort tends to focus on keeping the old file structures going. There's no time to put redesigned databases in place because time is taken up with code like subtracting 28 days from 6-digit numeric dates.   Now, you have definitely recognized that category of problem for developers and you decided to build library of code. You'll be able to reference it for many programs to come. And, over time, more and more of your programs will be using recognizeable code fragments.   One thing I've been sarching for is a code library that was made available some 12 or 15 years ago (more?) called something like "The Ulimate Date Routines".  It's been so long that I can't remember who put it together. (Bob Cozzi keeps coming to mind, but it only sems partly right for some reason.) I was hoping to track it down to help you out, but I still haven't hit on it. It's been update once or twice as new native functions have been released.   For that, it's something you shouldn't have to do. But you came to a conclusion that spending the time was valuable. It's something that's been done more than once, yet somehow it's worth doing again. Why?   Because you didn't already have the routines and you believed it would save more time in the future than the time you spent putting together. It's a near certainty that you're right, too.   It does lead to another question, though. If your database didn't have 6-digit numeric fields or 8-byte character fields or whatever, and instead was converted to use actual DATE fields, and programming was also adapted to expect all DATE (and TIME and TIMESTAMP) fields, how many of the code snippets would be needed?   I've been searching for a code library that was published 10 or more years ago called something like "The Ultimate Date Routines". It was a full set of RPG code snippets covering what you posted. It was updated at least once to include new date functions after they were released by IBM. I haven't been able locate any references, but I'll keep looking. (I keep thinking Bob Cozzi might have done it, but it doesn't seem totally right.)   Anyway, I recognize the problems you're trying to solve with your collection of snippets. SQL in the right places could handle a lot of it, but it's your choice not to use it. Considering the performance and other advantages of SQL over native, though, I'll still recommend that it be investigated farther for its appropriate uses.   Tom
    125,585 pointsBadges:
    report
  • aceofdelts
    Before IBM came out with the DATE type fields and the Duration op codes, we would convert our dates to Day of Century and simply subtract to get duration. A divide-by-7 with MVR would tell you the day of the week. The '50-year convention' for determining century is another one that we did a little differently ... had a stand-alone program to call & pass the 6 digit & get the 8 digit return parm. The advantage was the ability to redo the scheme by changing just 1 program. Yes, these techniques are mostly useless now, but I'll run into situations now & then where it's handy. Mostly useful in decifering other peoples code.
    1,960 pointsBadges:
    report
  • TomLiotta
    I ran across an old TechTarget article, RPG free-format date-conversion cheat sheet, that might have one or more conversions you don't have. I didn't check them all nor compare against yours.   I did find probable typo bugs between statements 31.00 and 45.00 where many 7-digit conversions should be specified as 8-digits. Also, even though the article contains a source module that can be compiled and run, the statements conflict with other statements. As values are changed, later statements are affected.   One technique I don't see in your examples nor in the linked article is the use of DS subfields. By referencing basic data definitions, operations involving substringing can sometimes be eliminated.   Tom
    125,585 pointsBadges:
    report

Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to:

To follow this tag...

There was an error processing your information. Please try again later.

REGISTER or login:

Forgot Password?
By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy

Thanks! We'll email you when relevant content is added and updated.

Following