Joined: 01 Sep 2006 Posts: 2547 Location: Silicon Valley
I want to create a unique eight character dataset qualifier, based on the time. So I start with: DATE('J') and TIME('L'), where the long time looks like this: '16:54:22.123456'
I compute various indexes into "ABCDEFGHIJKLMNOPQRSTUVWXYZ@#$0123456789", concatenating to the token for each iteration. My problem is that there are not enough characters in the length of the token to account for all of the digits of the time. The last few digits have to be ignored. If I run it twice, it might produce the same value because the higher order digits are the same.
Does anyone have a better idea?
Is it better to ignore high order digits so that I can preserve the low order digits? I really do not want to wait until some time has passed so that there is a difference in two tokens.
Code:
/* rexx */
numeric digits 22
/* 15127/16:54:22.123456 */
say 'current' setuniq(DATE('J')'/'TIME('L'))
say 'current' setuniq(DATE('J')'/'TIME('L'))
say 'max ' setuniq('28366/23:59:59.999999')
say 'min ' setuniq('15001/00:00:00.000000')
exit
/* compute number of seconds */
seconds = ss + (60 * mm) + (60 * 60 * hh) + ( 24 * 60 * 60 * DDD )
/* compute number of milli seconds to date, in this year */
tsecond = (seconds * 1000000) + tt
say '----+----1----+----2----+----3----+----4'
say tsecond
base = length(charstr) - 1
divisor = base ** 8
/* convert large decimal number to base 36 number */
uniq = substr(charstr,yy-14,1) /* year */
Do While (tsecond > 0)
indx = (tsecond % divisor)+1 /* integer portion */
chr1 = substr(charstr,indx,1) /* get char value */
uniq = uniq || chr1 /* concatenate to name */
tsecond = tsecond // divisor /* remainder */
divisor = divisor / base /* smaller divisor */
End
say 'Long ' uniq
/* only use leftmost 8 characters */
uniq = left(uniq,8)
Joined: 06 Jun 2008 Posts: 8696 Location: Dubuque, Iowa, USA
As mentioned, the granularity is important in this case. One scheme would be to establish a base year, which becomes A. The following year becomes B and so forth -- 1 character could cover 39 years. Julian day of the year could be done in 2 characters (using base-39 modulus). That leave 5 characters for time (unless you wind up using 2 levels of data set name instead of 1). Hour, minute, second each can be coded into 1 character leaving you 2 characters for fractions of a second. 39 times 39 gives 1521 possible values, so you could use thousandths of a second and modulo 39 arithmetic to encode them into 2 characters. If you need more accurate time measurement, you could take ten-thousandths of a second, divide by 7, then use modulo 39 to encode into 2 characters -- unless you have duplicates within 7/10000 of a second you wouldn't get duplicate time values.
Joined: 09 Mar 2011 Posts: 7309 Location: Inside the Matrix
I'm guessing, enrico, that you want to make use of the "sparse" nature of dates and times. Other than the year and the scrinchy little parts of a second, each element is limited in range, so readily subject to "compression" of some type. Three times I've started typing that up... I think it'll work :-)
Joined: 09 Mar 2011 Posts: 7309 Location: Inside the Matrix
DFSMS: Using Data Sets, Naming Datasets wrote:
Each name segment (qualifier) is 1 to 8 characters, the first of which must be alphabetic (A to Z) or national (# @ $). The remaining seven characters are either alphabetic, numeric (0 - 9), national, a hyphen (-), or X'C0'.
So, 29 for the first, and 41 for the remaining seven. A bit more wriggle-room.
26 letters, 26 slots
10 years slots for the hundredths of seconds resolution
here is the code
Code:
/* REXX
*/
Trace "O"
numeric digits 32
signal on novalue
if "A" > "0" then do
alpha = "#$@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
end
else do
alpha = "$@#ABCDEFGHIJKLMNOPQRSTUVWXYZ"
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
end
/* automagically take into account ASCII EBCDIC collating sequence
if ( date("B") - date("B", dateMin, "S") ) > 99999 then ,
signal _logic_error
if ( date("B", dateMax, "S") - date("B") ) > 99999 then ,
signal _logic_error
parse upper arg coun
coun = strip(coun)
if coun = "" then do
/* just encode and display a few dates
*/
say "some random previous date"
date = random(date("B", dateMin, "S"), date("B"))
date = date("S", date, "B")
time = random(0,86399)
micr = random(1,999)
time = timeS2N(time) || "." || right(micr, 6, "0")
say " " date time token(date, time)
say "NOW"
date = date("S")
time = time("L")
say " " date time token(date, time)
say "some random future date"
date = random(date("B"), date("b", dateMax, "S"))
date = date("S", date, "B")
time = random(0,86399)
micr = random(1,999)
time = timeS2N(time) || "." || right(micr, 6, "0")
say " " date time token(date, time)
exit
end
if \ datatype(coun, "W") then do
/* decode and show the date and the time for a token
*/
if length(coun) \= 8 then do
say "token must be exactly 8 chars"
exit
end
tokn = translate(coun)
if \ datatype(tokn, "A") then do
say "token must contain only the chacters A-Y 0-9"
exit
end
if \ datatype(left(tokn, 1), "U") then do
say "token must start with an UPPERCASE A-Y"
exit
end
say "token decoded"
say " " date time tokn
say "token re-encoded"
say " " date time token(date, time)
exit
end
else do
/* the bulk test
*/
fdmax = dateF(dateMax, "S")
date = random(date("b", dateMin, "S"), date("B"))
date = dateF(date,"B") + timeU()
step = 1
step = random(1234 ,5678 )
OldTokn = ""
OldDate = ""
OldTime = ""
done = 0
do fd = date by step*123456789 for coun,
while (fd <= fdmax)
NewDate = dateS(fd, "F")
NewTime = timeL(fd, "F")
NewTokn = token(NewDate, NewTime)
if (length(NewTokn) > 8) then do
say "******* length(NewTokn) > 8"
say "NewTokn " NewDate NewTime NewTokn
signal logic_error
end
if (done // 100 = 0) then ,
say "checked " NewDate NewTime NewTokn
if (OldTokn > NewTokn) then do
say "*******" "sequence error"
say "OldTokn" OldDate OldTime OldTokn
say "NewTokn" NewDate NewTime NewTokn
signal logic_error
end
OldTokn = NewTokn
OldDate = NewDate
OldTime = NewTime
done = done + 1
end
say "checked " done
end
exit
/* error handlers
*/
logic_error:
say "++"copies(" -",35)
say "++ Logic error at line '"sigl"' "
say "++"copies(" -",35)
exit
novalue:
say "++"copies(" -",35)
say "++ Novalue trapped, line '"sigl"' var '"condition("D")"' "
say "++"copies(" -",35)
exit
if length(tail) > 7 then do
say "*******" "length(tail) > 7"
say " " dateS timeL tail
signal logic_error
end
tail = right(tail, 7, left(alphanum, 1))
return head || tail
/* utility
*/
dateF:procedure
Trace "O"
parse upper arg arg1, type
if arg1= "" & type = "" then ,
date = date("B")
else if type = "B" then ,
date = arg1
else ,
date = date("B", arg1, type )
dateF = date*24*60*60*1000000
if type = "" then
dateF = dateF + timeU()
return dateF
dateS:procedure
Trace "O"
parse upper arg arg1, type
if arg1 = "" & type = "" then
return date("S")
if type = "S" then ,
return arg1
if type \= "F" then ,
return date("S", arg1, type)
date = arg1 % (24*60*60*1000000)
return date("S", date, "B")
timeL:procedure
Trace "O"
parse upper arg arg1,type
if arg1 = "" & type = "" then
return time("L")
if type = "L" then ,
return arg1
if type = "N" then ,
return arg1".000000"
if type = "S" then do
ss = right(arg1 // 60, 2, "0")
arg1 = arg1 % 60
mm = right(arg1 // 60, 2, "0")
hh = right(arg1 % 60, 2, "0")
return hh":"mm":"ss".000000"
end
if type = "F" then do
time = arg1 // ( 24*60*60*1000000)
secs = time % 1000000
micr = time // 1000000
ss = right(secs // 60, 2, "0")
secs = secs % 60
mm = right(secs // 60, 2, "0")
hh = right(secs % 60, 2, "0")
timeL = hh":"mm":"ss"."left(micr, 6, "0" )
return timeL
end
return -1
timeU:procedure
Trace "O"
parse upper arg time
if time = "" then ,
time = time("L")
parse var time hh ":" mm ":" ss "." uu
timeU = ( hh*3600 + mm*60 + ss ) * 1000000 + uu
trace "O"
return timeU
timeL2S:procedure
Trace "O"
parse upper arg arg1
parse var arg1 hh ":" mm ":" ss "." .
return hh*3600 + mm*60 + ss
timeN2S:procedure
Trace "O"
parse upper arg arg1
parse var arg1 hh ":" mm ":" ss
return hh*3600 + mm*60 + ss
to_dec:procedure
Trace "O"
parse upper arg arb, tbl, base
if base = "" then ,
base = length(tbl)
if base > length(tbl) then ,
signal logic_error
pow = 1
dec = 0
do d = length( arb ) to 1 by -1
dec = dec + pow * ( pos( substr( arb,d,1 ),tbl ) - 1 )
pow = pow * base
end
return dec
to_arb:procedure
Trace "O"
parse upper arg dec, tbl, base
if base = "" then ,
base = length(tbl)
if base > length(tbl) then ,
signal logic_error
arb = ""
do until (dec = 0)
arb = substr(tbl,dec//base+1,1) || arb
dec = dec % base
end
return arb