Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Faking a more accurate TIMESTAMP

Status
Not open for further replies.

wahlers

Programmer
May 13, 2004
142
NL

For those interested...

It is not uncommon to use the timestamp as a unique (log) registration field.
Of course, any timestamp field has a limited accuracy!
The chances on duplicates is real and often high!

The standard 'FUNCTION CURRENT-TIME' is by no means sufficient.
This current timestamp is accurate only to one hundredth of a second, which is totally insufficient!

There are several alternatives!
For instance, use a database (like mainframe DB2 TIMESTAMP) and a locking mechanism.
This works but might drain the resources within a multi-user/multi-tasking system.

You may opt for a simple counter function with a locking mechanism that simply adds '1' to the last number given and return this new '+1' next unique number.

The code following is a simple and compact example of faking an incredible accurate timestamp.

Just copy, compile and try it by calling the subprogram as follows:
Code:
[COLOR=red]
05  myTIMESTAMP   PIC  X(30).
CALL  TIMESTMP  USING  myTIMESTAMP
[/color]
Which calls...
Code:
 IDENTIFICATION DIVISION.
 PROGRAM-ID.  TIMESTMP.
*---
* Faking(!) a more accurate timestamp!
*
* The guaranteed accuracy (in seconds) PER USER is:
* Inverse (100 * 100 * 999,999) / 2 = 1/4,999,995,000
*
* pseudoRandom3 actually is a static value for a
* given user-session! It consists partly of the
* unique address value of the TIMESTMP field.
*
* The changes on duplicates within a multi-user, 
* multi-tasking environment is:
* (assuming the 'TIMESTMP' field is NOT defined as
* EXTERNAL!)
* Inverse (4,999,995,000 * 999,999) / 2 = 
* 1/2,499,995,000,002,500
*
* Thus, duplicates are NOT impossible,
* but highly improbable!
*---
 DATA DIVISION.
 WORKING-STORAGE SECTION.
 01  globalWorkFields           GLOBAL.
   05  PTR USAGE POINTER.
   05  BIN REDEFINES PTR           PIC  9(09)  BINARY.
   05  pseudoCount                 PIC  9(02)  BINARY.

 LINKAGE SECTION.
 01  TIMESTMP.
   05                              PIC  X(16).
   05  pseudoRandom1               PIC  9(02).
   05  pseudoRandom2               PIC V9(06).
   05  pseudoRandom3               PIC  9(06).

 PROCEDURE DIVISION USING TIMESTMP.
 begin.
     MOVE  FUNCTION CURRENT-DATE    TO  TIMESTMP(1:16)
      ADD  1  pseudoCount       GIVING  pseudoRandom1 
                                        pseudoCount
      ADD  ZERO FUNCTION RANDOM GIVING  pseudoRandom2
     CALL  'useTIMESTMPaddress'  USING  pseudoRandom3 TIMESTMP
     GOBACK
     .
 IDENTIFICATION DIVISION.
 PROGRAM-ID.  useTIMESTMPaddress.
 DATA DIVISION.
 LINKAGE SECTION.
 01  pseudoRandom3                 PIC  9(08).
 01  TIMESTMP                      PIC  X(01).
 PROCEDURE DIVISION              USING  pseudoRandom3 
                                        TIMESTMP.
 begin.
      SET  PTR          TO  ADDRESS OF  TIMESTMP
     MOVE  BIN                      TO  pseudoRandom3
     GOBACK
     .
 END PROGRAM  useTIMESTMPaddress.
 END PROGRAM  TIMESTMP.
Regards, Wim Ahlers.
 
Additional note...

Due to the box limitations the following statements look odd:

Code:
   05  BIN REDEFINES PTR           PIC  9(09)  BINARY.
   05  pseudoCount                 PIC  9(02)  BINARY.

This should (of course!) be:
Code:
05  BIN REDEFINES PTR  PIC  9(09)  BINARY.
05  pseudoCount        PIC  9(02)  BINARY.
And, likewise:
Code:
     MOVE  FUNCTION CURRENT-DATE    TO  TIMESTMP(1:16)
Should be:
Code:
MOVE  FUNCTION CURRENT-DATE  TO  TIMESTMP(1:16)

I did pre-edit the source to make it fit the box, but I overlooked these statements!


Regards, Wim Ahlers.
 
I was awaiting some criticism on the code provided.
Note: I know it is weekend now, but I don't have much time for the forum in the coming days...that is why I (try to) anticipate on 'to be expected' criticism.

For instance I implicitly use the special register 'LENGTH OF' and the 'ADDRESS' register.

Both are not standardised and are machine dependent (think for instance about 32 versus 64 bit addressing!).

I (knowingly!) made the assumption that the (address) pointer register as well as the 'LENGTH OF' register are implicitly defined as 9(09) BINARY!

A dangerous assumption indeed!
The following code (same functionality) also uses the 'ADDRESS' and 'LENGTH OF' register but without making any assumptions to the physical implementation!

This code is therefore more portable and thus more preferrable...though I am, as always, interested in other points of view!

Here is the code:
(Note: due to the forum box limitations some statements 'overflow' to the next line!
Just copy&paste the text to your own *.txt file! Than it will be easier to read!).
Code:
       IDENTIFICATION DIVISION.
       PROGRAM-ID.  TIMESTMP.
      *---
      * Faking(!) a more accurate timestamp!
      *
      * ATTENTION:
      * NEVER code the 'IS INITIAL' clause.
      * NEVER initialize any working-storage field.
      *
      * The address taken from TIMESTMP is fixed per single task,
      * but unique within a multi-tasking system.
      * ...assuming TIMESTMP is NOT defined as an EXTERNAL field!
      *
      * Note:
      * Only an extract of the address bit pattern is used!
      * This bit pattern is converted to a numeric value.
      * (see reference modification)
      * This numeric value is NOT guaranteed to be unique within
      * a multi-user / multi-tasking system,
      * though in most cases it will be unique!
      *
      * Given the algorithm, the chance on duplicate TIMESTAMPS,
      * within a multi-user /  multi-tasking system, is NOT
      * impossible but to a high degree of certainty improbable!
      *---
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  globalWorkFields            GLOBAL.
         05  PTR.
           10  aPTR                    USAGE POINTER.
         05  BIN.
           10  aBIN                    PIC  9(18) BINARY.
         05  pseudoCount               PIC  9(06) BINARY.
         05  offsetPTR                 PIC s9(02) BINARY.
         05  offsetBIN                 PIC s9(02) BINARY.

       LINKAGE SECTION.
       01  TIMESTMP.
         05                            PIC  X(16).
         05  pseudoRandom1             PIC  9(06).
         05  pseudoRandom2             PIC  9(08).

       PROCEDURE DIVISION USING TIMESTMP.
       begin.

           IF  LENGTH OF  PTR  < LENGTH OF BIN
           , COMPUTE offsetPTR = 1
           , COMPUTE offsetBIN = LENGTH OF BIN - LENGTH OF PTR + 1
           ELSE
           , COMPUTE offsetBIN = 1
           , COMPUTE offsetPTR = LENGTH OF PTR - LENGTH OF BIN + 1
           END-IF

           MOVE  FUNCTION CURRENT-DATE  TO  TIMESTMP(1:16)
            ADD  1  pseudoCount     GIVING  pseudoRandom1 pseudoCount
           CALL  'getAddressOF'      USING  TIMESTMP
           MOVE  PTR(offsetPTR:)        TO  BIN(offsetBIN:)
           MOVE  aBIN                   TO  pseudoRandom2

           GOBACK
           .
       IDENTIFICATION DIVISION.
       PROGRAM-ID.  getAddressOF.
       DATA DIVISION.
       LINKAGE SECTION.
       01  TIMESTMP                    PIC  X(01).
       PROCEDURE DIVISION            USING  TIMESTMP.
       begin.
           SET  aPTR  TO  ADDRESS OF        TIMESTMP
           GOBACK
           .
       END PROGRAM  getAddressOF.
       END PROGRAM  TIMESTMP.


Regards, Wim Ahlers.
 
Well if a user can only be signed on once you could add the user and terminal they are using to that. Well if you stored some number in a field you could add that to the end and add one to it every time. Kind of like a log entry file.

I kind of like storing the username or logon ID as part of the key.

If you do not like my post feel free to point out your opinion or my errors.
 
ceh4702

Thanks for your input!

The timestamp as described is not intended as an ID but as a unique timestamp to time-register concurrent events.
As such it can only consist of digits.

E.g. a public (database) field is updated and later read and updated by other (concurrent) users.
That is why the timestamp must be unique!...or as I described; to a high degree of certainty be unique!

Thus, the timestamp field truly is a timestamp field used for (mainly) information (modification) consistency of data stored in a database.

Your suggested alternative, of storing the userid of the modifier, is (or can be) a valid alternative!
But this creates similar problems, for instance: How large should the userid field be? (8 characters? 10? 30?)
What is the userid used when a batch program is modifying the data?

Regards, Wim.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top