Midrange News for the IBM i Community


Posted by: sarge
Citizen/Soldier
U.S. Army
United States
Date Conversion
has no ratings.
Published: 07 Nov 2012
Revised: 23 Jan 2013 - 1587 days ago
Last viewed on: 29 May 2017 (4147 views) 

Using IBM i? Need to create Excel, CSV, HTML, JSON, PDF, SPOOL reports? Learn more about the fastest and least expensive tool for the job: SQL iQuery.

Date Conversion Published by: sarge on 07 Nov 2012 view comments(18)

hi all.

i used FndStrPdm to identify programs that use MULT 10000.01 to convert the date. i frown upon this, and want to change this process. i converte all of these programs to RPGLE, albeit fixed-format, in 2010.

what argument can i use to convince my boss that it would be a good thing to convert these to either a data structure, procedure, etc.?

i am not certain how to test this, nor am i convinced which NEW method would be best. i have used the data structure method since the late days of the /34 (yes, i'm that old) but i dont have a reference as to which is a faster method.

of course a sub-program or procedure is my preference, but i need ammunition to convince my boss to allow me to change the way that 47 pages of source members function.

thanks for all suggestions, except the one that i seem to get most of all, telling me "where to go." :)

-sarge

Return to midrangenews.com home page.
Sort Ascend | Descend

COMMENTS

(Sign in to Post a Comment)
Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: Date Conversion
Posted: 4 years 6 months 21 days 15 hours 31 minutes ago

Depends on what format the input date is in. Given your literal, I'm assuming your going from MDY to YMD.

If your date in MDY is stored in a 6-digit field, then you could use this:

 

.....H BNDDIR('COZTOOLS')
      /include cozTools/qcpysrc,Dates
     
     D oldDate     S       6S 0
     D YMD         S        D   DATFMT(*YMD)
     D newDate     S       6S 0

      /free
           // Convert to true date value from MDY
        ymd = %date( %edit(oldDate : 'X') : *MDY);

           // Convert from Dec(6,0) MDY to YMD
        newDate = %dec( %date( oldDate : *MDY) : *YMD);
     /end-free

 

If it's stored in another size field, I can help with that too.

Posted by: sarge
Premium member *
United States
Comment on: Date Conversion
Posted: 4 years 6 months 21 days 15 hours 11 minutes ago

nah, they are all in MDY. your method pretty much follows mine.

i know this is the better method, but is it "faster" than an internal loop that performs 10000.01 times?

that would be the selling point, since we do so much night-time batch work. This is also used many times (hundreds, at least) throughout the day by multiple users.

Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: Date Conversion
Posted: 4 years 6 months 21 days 14 hours 49 minutes ago
Edited: Wed, 07 Nov, 2012 at 19:52:06 (1664 days ago)

Nah, probably not faster when it comes to just hundreds of iterations.

Converting from/to date formats is expensive--more so than the old MULT method. There is a fix on v7r1 to avoid doing the conversion into and out of the internal date format if nothing's changed, but that requires v7r1 TR4.

The advantage the above method has over MULT is that of implicitly testing for a valid date value. You don't get that with MULT.

     /free
         qwccvtdt( '*MDY' : myDate : '*YMD' : newDate : apiError);
     /end-free

The QWCCVTDT API might be something to do a test vs the MULT basis. The values need to be type CHAR so you'd also have to include the time to convert from Zoned to Char (although there is a cheat for that).

 

Posted by: neilrh
Premium member *
Jackson, MI
Comment on: Date Conversion
Posted: 4 years 6 months 21 days 1 hours 1 minutes ago

Fish probably has more metrics on this, but I would guess the most efficient code method is to use a data structure. With potentially 3 data move you're done. 

d dsDATE          ds                                   
d  xYMD                          6s 0 overlay(dsDATE:1)
d  xYY1                          2s 0 overlay(dsDATE:1)
d  xYY2                          2s 0 overlay(dsDATE:7)
d  xMDY                          6s 0 overlay(dsDATE:3)

c                   eval      xYMD = FileDate
c                   eval      xYY2 = xYY1
c                   eval      DisplayDate = xMDY

 

Posted by: DaleB
Premium member *
Reading, PA
Comment on: Date Conversion
Posted: 4 years 6 months 21 days 30 minutes ago

Sarge, MULT opcode does not work by doing adds in a loop. You have to go pretty far back to find a CPU that doesn't do multiplication as part of the instruction set (8080, maybe). Timing of a multiply instruction is on par with an addition or subtraction.

Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 23 hours 17 minutes ago

Neil, yes, if not validating the actual date is okay, then yes, the data structure method is "best". I would use the built-ins or QWCCVTDT over other methods any time.

I suppose there should be just a flat "convert this 6-digit numeric value from XYZ to ABC format. I could add that to cozTools, but it would be best to have an RPG compiler implementation due to the "overhead" of a subprocedure call in high-performance areas.

Posted by: Viking
Premium member *
CA
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 22 hours 16 minutes ago

Is something like this (converting to date and back) more or less expensive than a subprocedure call?

 

X-NONE

YYMMDD = %Dec(%date(MMDDYY:*mdy):*ymd);

Posted by: neilrh
Premium member *
Jackson, MI
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 22 hours 11 minutes ago

I tend to go with the Viking method, in-line code, rather than call some procedure.

Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 22 hours 2 minutes ago

Viking, I'm working on a test case now.

I've built a new cozTools subprocedure named CVTDATE that wraps the QWCCVTDT API. I'll test it in a iterative loop vs the %DEC(%DATE()) routine and to the legacy MULT operation code. It should be finished by later this morning.

Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 21 hours 8 minutes ago
Edited: Thu, 08 Nov, 2012 at 11:41:47 (1663 days ago)

RESULTS - Performed each task 10000 times in a FOR loop

%DEC( %DATE () ) Method = 0.024 seconds

Fixed-Format MULT 10000.01 = 0.002 seconds

Subproc call w/embedded %DEC( %DATE ) Method = 0.028

inLine call to CEEDAYS/CEEDATE Method = 0.118

 

NOTE: Results shown are for all 10,000 iterations combined. Not an individual execution.

So it turns out that an in-line MULT is the fastest way to convert a 6-digit zoned numeric field from MDY to YMD format. But the other two methods aren't so bad (15 times slower) that it should prevent from using one of them.

NOTE 2: I ran the test again with the Subproc call using two different methods. Here are those results:

  1. Call CEEDAYS and CEEDATE APIs to perform the conversion: 0.138 seconds (up 0.02 seconds from inline method)
  2. Call QWCCVTDT API to perform the conversion: 0.600 seconds (slowest by far)

Clearly the CEEDAYS/CEEDATE methodology is the fastest if a dynamic date format is needed (such as in a subprocedure with date format parameters).

 

Posted by: Viking
Premium member *
CA
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 20 hours 39 minutes ago

A subprocedure call seems cheap... .004 s for 10,000 subprocedure calls.


Bob, what are the specs on your machine, just for comparison/reference?

Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 20 hours 30 minutes ago

My Specs via DSPSYS:

==>dspsys                                                    
COZSYS/067xxxP1 V7R1M0 CPU(1/4/P05) RAM:7.43GB DiskUse:41.91%

 

Running v7.1

1 of 4 CPU cores are active

P05 processor group

Looks like 8GB of RAM

with 60% free disk space.

 

Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 19 hours 42 minutes ago
Edited: Thu, 08 Nov, 2012 at 13:03:36 (1663 days ago)

To sum up... the MULT legacy method is the fastest inline method for converting a 6-digit numeric date between MDY and YMD format. I did not test larger figures, but I assume it would be similar performance.

For "one off" conversions, any method would be good enough, although I would never use the MULT option or the data structure option. The DS option is okay if hidden inside a subproc, however.

Sadly the one I thought would be good, QWCCVTDT is really not a good choice--probably because it is (A) a dynamic call and (B) an OPM program.

These leads me to conclude that the CEEDAYS/CEEDATE methods are the 'best' for legacy date conversion--you also have to convert from decimal to character format to use these APIs.

For cozTools, there are already methods to do this--most use internal APIs or C runtime. But I've now added the cvtDate() subprocedure. It basically wraps the CEExxxx APIs and adds some ease-of-use options.

 ymd = cvtDate( mdy );  // Convert MDY to YMD (assumes a numeric date value)

 mdy = cvtDate( ymd : '*YMD' );  // Convert YMD to MDY

The CVTDATE subprocedure assumes the date format is *MDY and should be converted to *YMD, likewise if the optional 2nd parameter is specified as *YMD, it assumes you want to return the value as *MDY, but you can specify the return format as the 3rd parameter.

In addition, any 6-digit or 8-digit day may be specified and it'll convert it. It will not return date formats that include text characters. For that, use on of the other cozTools functions, such as editDate().

 

Posted by: Ringer
Premium member *
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 16 hours 19 minutes ago

Date conversion speed won't matter much once you add in the database I/O - that's the bottleneck of most any business program. Sorta like standing on a chair to get closer to the moon - the net effect is infinitesimal. bm

Chris Ringer

Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 11 hours 14 minutes ago

Chris, true enough. But Sarge's question was how to test things to support changing it from X to Y. So the testing was done to help him support however he changes it.

Oh, and that old Hans Bolt argument "its the database" doesn't always come into play--if your function is slow, and the database is slow, then both you and the database are the issue.

And you can never get to the Moon unless you take that first step.

What if they fix database by installing Solid State Drives in your system? 

 

Posted by: Ringer
Premium member *
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 10 minutes ago

Yeah Bob. I'm all about coding something the correct way, then determine which method is fastest. Like a few years ago, I had to figure out if a failed CHAIN or a failed SETLL fails the fastest because the logic would normally fail a few times before getting a hit. CHAIN won, it doesn't position the cursor to EOF.

Chris Ringer

Posted by: DaleB
Premium member *
Reading, PA
Comment on: Date Conversion
Posted: 4 years 6 months 20 days 7 minutes ago

Out of curiosity, did you happen to test MULT vs. the overlaid DS with MOVEs? But you'd need more iterations for it to be visible with millisecond precision.

Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: Date Conversion
Posted: 4 years 6 months 19 days 23 hours 42 minutes ago
Edited: Fri, 09 Nov, 2012 at 08:34:41 (1662 days ago)

Dale, no. I don't find that technique viable. Traditionally it requires direct manipulation based on data configuration. But I suppose with EVAL-CORR you could modernize it assuming you've setup the data structures properly.

 

.....D mdy             DS                  Qualified Inz
     D  mm                            2S 0
     D  dd                            2S 0
     D  yy                            2S 0

.....D ymd             DS                  Qualified Inz
     D  yy                            2S 0
     D  mm                            2S 0
     D  dd                            2S 0
      /free
           eval-corr YMD = MDY;