HP3000-L Archives

June 2000, Week 5

HP3000-L@RAVEN.UTC.EDU

Options: Use Monospaced Font
Show Text Part by Default
Show All Mail Headers

Message: [<< First] [< Prev] [Next >] [Last >>]
Topic: [<< First] [< Prev] [Next >] [Last >>]
Author: [<< First] [< Prev] [Next >] [Last >>]

Print Reply
Subject:
From:
Jeff Woods <[log in to unmask]>
Reply To:
Jeff Woods <[log in to unmask]>
Date:
Fri, 30 Jun 2000 12:11:18 -0600
Content-Type:
text/plain
Parts/Attachments:
text/plain (187 lines)
At  02:15 PM 6/29/00, Boris Kortiak wrote:
>I figured the best thing to use would be a date time stamp. So using a JCL
>I can create a file name that looks like "200006281604", but this is too
>long for use on the target machine.  If I convert this to a base 36 number
>([0-9,A-Z]) it will always fit into 8 digits for all the date ranges I can
>foresee (Y28k or thereabouts).

My perception is that such a conversion will convert the number from human
readable to a blob of data.  If you are going to do that then perhaps
getting rid of the various number bases of the various subfields of the
string (e.g., 12, 31, 24, 60) and making it a "minutes since some date" or
approximation to such would be simpler.  (Doing a real "minutes since some
date" is complicated by variations in number of days in each month not to
mention leap years.  But a simple approximation that assumes 60 seconds in
every minute [Total time-stamp accuracy requires knowing when to put in
leap seconds  :)  ] and 31 days in every month would be just as effective
for your use and much simpler to calculate.)

Along the same lines, will this portion of your application ever need to
handle dates prior to 2000?  If not, then make the year field mean "years
since 2000" and you save 3 orders of magnitude in your number presently.

So...  Try doing this conversion of your example
time-stamp...  200006281604 means:

2000 - year
   06 - month
   28 - day
   16 - hour
   04 - minute

Your new time-stamp would be:

newTimeStamp = ((((2000 - 2000) * 12 + (6 - 1)) * 31 + (28 - 1)) * 24 + 16)
* 60 + 4 = 309124

Note that month and day are "one relative" (1-12 and 1-31) and the others
are "zero relative" (0-23 and 0-59).  This is why one is subtracted from
month and day to make them "zero relative" (0-11 and 0-30) for the
calculation.  [It's my opinion that non-technical folks generally are more
comfortable with a "one relative" view but our arithmetic is decided "zero
relative"; for example, the ten decimal digits are the symbols from 0 to 9.]

Changing from your example's constants to more meaningful variable names:

YEAR_OFFSET = 2000
MONTHS_IN_YEAR = 12
DAYS_IN_MONTH = 31
HOURS_IN_DAY = 24
MINUTES_IN_HOUR = 60

newTimeStamp = ((((year - YEAROFFSET) * MONTHS_IN_YEAR + (month-1)) *
DAYS_IN_MONTH + (day-1)) * HOURS_IN_DAY + hour) * MINUTES_IN_HOUR + minute
= 309124

The wary among us might further include additional parentheses to force the
order of precedence of the operators (although the syntax above will work
with both simplistic algorithms that just process left to right (like many
calculators including the one bundled in Win98) and with "correct"
algorithms that know that multiplication takes precedence over addition
(like most compilers and [I think] the MPE CI):

newTimeStamp = ((((((((year - YEAROFFSET) * MONTHS_IN_YEAR) + (month-1)) *
DAYS_IN_MONTH) + (day-1)) * HOURS_IN_DAY) + hour) * MINUTES_IN_HOUR) +
minute = 309124

The paranoid might also enclose all the variable references in parentheses
just in case unexpected data happens to get inserted into the string:

newTimeStamp = (((((((((year) - YEAROFFSET) * MONTHS_IN_YEAR) +
((month)-1)) * DAYS_IN_MONTH) + ((day)-1)) * HOURS_IN_DAY) + (hour)) *
MINUTES_IN_HOUR) + (minute) = 309124

The *truly* paranoid might also enclose even the constant references and
the whole calculation in parentheses "just in case" (but personally I think
this one is overkill  ;):

newTimeStamp = ((((((((((year) - (YEAROFFSET)) * (MONTHS_IN_YEAR)) +
((month)-1)) * (DAYS_IN_MONTH)) + ((day)-1)) * (HOURS_IN_DAY)) + (hour)) *
(MINUTES_IN_HOUR)) + (minute)) = 309124

So, working backward to determine the last date that can be represented in
eight decimal digits in this scheme: 99999999 maps to (with zero-relative
month and day): 186 years, 8 months , 4 days, 10 hours, 39 minutes which
would be represented as in your example as 218609051039.

To do the forward calculation in multiple simpler lines (which might be
easier to code and maintain in JCL):

set time $year - 2000
set time $time * 12 + ($month - 1)
set time $time * 31 + ($day - 1)
set time $time * 24 + $hour
set time $time * 60 + $minute


On the other hand....  :)

Converting a number from base 10 to base 36 in a script might be
interesting.  :))

I've been doing a lot of work lately on non-MPE systems in TCL so please
forgive me if I do this in TCL syntax instead of MPE JCL.  Hopefully, it
will either be straightforward to translate or sufficiently complex that
you decide on other techniques (such as the one above).  :)

-----------------start-of-TCL-code----------------------------------------------
proc base {decimal {base 16}} {

         # Check the base to be sure it's valid for this routine.
         if {((($base) < 2) || ($base > 36))} {
                 error "Unsupported base specified: $base"
         }

         # Strip the sign and save it's state until the end.
         if {($decimal) < 0} {
                 set negative true
                 set decimal [expr abs($decimal)]
         } else {
                 set negative false
         }

         set result {}
         while {($decimal) != 0} {

                 # Determine "next" digit (moving left to right) for the
result.
                 set digit [expr ($decimal) % ($base)]

                 # Note:  The new digit has to be less than the base but
                 #        that's ensured by the modulus function above.

                 # If the new digit happens to be 0-9 just use it.
                 # [Note: This "if" isn't needed, but should speed up the code.
                 #        In any case the string conversion inside it needs to
                 #        be done on any value above 9 (but 9 and under it
                 #        doesn't change anything).]
                 # I suspect this is fastest although the test may
                 # be as slow as just always doing the translation. )
                 if {$digit > 9} {
                         # The new digit needs to be converted to A-Z.
                         set digit [string index \
                                 {0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ} $digit]
                 }
                 set result "$digit$result"

                 # Integer division throws away the remainder (what we want).
                 set decimal [expr ($decimal) / ($base)]
         }

         if {$negative} {
                 # Put the sign back.
                 set result "-$result"
         }

         return $result
}

# Some calls to test the procedure:
foreach parms {-2 -1 0 1 2 3 5 7 9 10 11 15 16 17 {35 36} {36 36} {37 36}
100 1024} {
         puts "base $parms => [eval base $parms]"
}
-----------------end-of-TCL-code------------------------------------------------

Unfortunately, I'm not willing to spend the time to replace the modulus and
integer division expressions to make it work for numbers larger that 32 bit
signed integers, which limits the values that this code supports on TCL
(and in MPE's CI [I think]) to values from -2147483648 to 2147483647
inclusive.  In any case, that's an algorithm to convert from base 10 to any
base up to 36.

I hope this has been of some help.  :)

--
Jeff Woods
[log in to unmask] (preferred)
[log in to unmask] (work)
[log in to unmask] (deprecated)
[log in to unmask] (deprecated)


__________________________________________________
Do You Yahoo!?
Talk to your friends online with Yahoo! Messenger.
http://im.yahoo.com

ATOM RSS1 RSS2