ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

Using "TEST(DE)" Op code before %DATE

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Using "TEST(DE)" Op code before %DATE

    Hi, all. In the course of accommodating older *CYMD date formats, I'm playing around with %DATE, %CHAR, and TEST(DE). I step through the following code in debug:

    Code:
    // DCL-S DateEntered     DATE;
    // DSP_P1InDate is character 10A, from a DSPF.
    
      TEST(DE) *MDY DSP_P1InDate;
      IF NOT %ERROR;
                                                        ErrPosition = 'A';
        DateEntered = %DATE(DSP_P1InDate : *MDY);
    When I enter "03/31/2012" into DSP_P1InDate, it apparently passes TEST(DE); control passes to the "NOT %ERROR" path. But the EVAL fails with RNX0112 ("Date, Time or Timestamp value is not valid.").

    Having passed the TEST(DE) test, I expected the %DATE BIF to successfully convert the characters to a date. Am I not correctly understanding how either TEST(DE) or %DATE works? Why does/might this fail?

  • #2
    Well "03/31/2012" is _not_ an *MDY date. They can only have a 2 digit year.

    I can only assume that TEST is only looking at the first 8 characters i.e. 03/31/20 - which is a valid MDY date - and that the %Date conversion is using the full length of the field and requires that the last 2 characters be blanks perhaps?

    Comment


    • #3
      Thanks, JonBoy. I think you've explained why the %DATE (appropriately) fails. (And maybe that's how TEST works, too.)

      So, my update: When I intercepted control after TEST(DE) and changed DSP_P1InDate from "03/31/2012" to "03/31/12", the %DATE line executed OK.

      It's previous failure (RNX0112) makes sense now, as *MDY is a 2-digit date format. Apparently the cause of the "problem" is that TEST(DE) does not consider a 4-digit year with *MDY to be an error, even though %DATE does consider that an error. Hmm.

      Has anyone else noticed this?

      I'm not sure it's a bug ... but does seem a little inconsistent.

      Comment


      • Jerry G
        Jerry G commented
        Editing a comment
        Does this mean we can't blindly trust TEST(DE) alone to prevent RNX0112 errors with the %DATE BIF?

      • JonBoy
        JonBoy commented
        Editing a comment
        Well if you lie to the compiler Jerry (telling it you have a *MDY date when it is actually *USA) then all bets are off.

        You could perhaps make the argument that the compiler should have diagnosed that a 10 character field could not be a valid *MDY date and set %Error - but if it has worked this way in the past IBM won't change it as it would break too much code. See my example of handling both formats elsewhere in this thread.

    • #4
      Instead of using TEST to validate the date beforehand, you could wrap the %DATE in a MONITOR so you can catch the resulting error if the date is invalid

      Code:
        MONITOR;
          DateEntered = %DATE(DSP_P1InDate : *MDY);
        ON-ERROR;
          //Date was not valid
        ENDMON;

      Comment


      • #5
        Good advice; thank you. That's what I did to test lots of input without using debug. (I need to use MONITOR more often!) ;-)

        Comment


        • #6
          I agree that using MONITOR is a good idea - in cases where the date is normally correct it is also more efficient.

          But your initial problem could easily be cured simply by using the appropriate date format. You didn't need to edit the input string to make it fit an MDY format.
          Code:
            TEST(DE) *USA DSP_P1InDate;
            IF NOT %ERROR;
                ErrPosition = 'A';
                DateEntered = %DATE(DSP_P1InDate : *USA);
          If for some reason you want to allow the user to optionally enter an actual MDY date then this would do it I think.
          Code:
          Monitor;
            If %Len(%TrimR(DSP_P1InDate)) < %Size(DSP_P1InDate);
                DateEntered = %DATE( %TrimR(DSP_P1InDate) : *MDY);  // If short entry test as MDY
            Else;
                DateEntered = %DATE(DSP_P1InDate : *USA);
            EndIf;
            ErrPosition = 'A';
          On-Error codesForDate Errors;
            // error handling
          End-Mon;
          One more thing - is there any reason why you can't change the display file and make it a real date field? That way the user can never enter a bad date and you would never have had this problem.

          Comment


          • #7
            Thanks for the suggestions. I have to replace a pre-year-2000 RPG III routine called by many programs (not [directly] from a DSPF), which pass in a 10A field and a "home-grown" indication of its type. (Our "*MDY" implies only the ordering of the digits, but not the year format or the presence of separators [any non-digit character].) I might be getting "mm/dd/yy" or "mm/dd-yyyy" or "mmddyy" or "mmd/dyyyy" or mm#ddyy" or .... anything that "strips down" to "mmddyy" or "mmddyyyy". (The old procedure even accepts "1/2/2//5/17" or "A12/2H51*7" as valid for last Christmas!) :-) Unfortunately, I don't have the "luxury" of creating the standards by which this routine will be called. :-( Those old MOVE and MOVEA and MOVEL op codes were pretty (dangerously) powerful! But, yeah, the %LEN BIF comes in handy here.

            Now I understand the significance of something in the reference to which you alluded earlier, under explanation of the "TEST" op code: "If the character or numeric field specified as the field-name operand is longer than required by the format being tested, extra data is ignored. For character data, only the leftmost data is used; for numeric data, only the rightmost data is used." So your assumption in your first post, that TEST(DE) is only testing "03/31/20" of "03/31/2012" is borne out.. (I suppose the numeric value 58120331 as *YMD would pass, too, as 31 MAR (20)12, but haven't tried that yet.)

            So had I better understood what that paragraph meant ... I shouldn't have posted! ;-) Well, hopefully this may help someone else at some point. Thanks, JonBoy, for your thoughts and time. ("Vectorspace" too.)

            Comment


            • #8
              Nasty. Sounds like perhaps using %Xlate to convert everything that is not a digit 0 - 9 to (say) '*' and then doing a %Replace on the '*' to '' (null) would give you a common starting point. The trimmed length of the resulting string should tell you if you have a 2 or 4 digit year. Come to think of it, a simple character copy loop would probably be as fast and would allow the retention of '/' characters for example.

              Good luck!

              P.S. If you haven't already done so you might want to consider using a varying length work field for the date and start by doing workDate = %Trim(inputDate). That way the length is always readily accessible for subsequent tests.

              Comment

              Working...
              X