From:	SMTP%"RELAY-INFO-VAX@CRVAX.SRI.COM" 25-AUG-1993 07:32:26.32
To:	EVERHART
CC:	
Subj:	Re: LIB$DAY in DCL?

From: jeh@cmkrnl.com
X-Newsgroups: comp.os.vms
Subject: Re: LIB$DAY in DCL?
Message-Id: <1993Aug23.224011.2570@cmkrnl.com>
Date: 23 Aug 93 22:40:11 PDT
Organization: Kernel Mode Systems, San Diego, CA
Lines: 67
To: Info-VAX@kl.sri.com
X-Gateway-Source-Info: USENET

In article <5224021621081993/A26877/POSSE/1178ABF40200*@mrgate.uwyo.edu>
, Jim Kirkpatrick <JIMKIRK@corral.uwyo.edu> writes:
> I would like to find a way to perform what LIB$DAY does, but in DCL.
> That is, compute the number of days since the system start date (17-NOV-1858)
> or a given date.  I can't figure out how to make F$CVTIME do it for me.
> I believe this involves computing a delta time from two absolute times,
> which F$CVTIME won't do.
> 
> Any ideas?

Two, actually.  

1.  Is there a compelling reason not to simply code this into a tiny image
(calling LIB$DAY) and return the result via LIB$SET_SYMBOL ?

2.  Here is a little hack I originally found in a magazine aimed principally
at, would you believe, IBM System/3 shops -- "Small Systems Journal".  1977 or
so. 

Wait a minute, I want to make sure you understand the implications of the above.
I'll say it another way: 

I DID NOT WRITE THE FOLLOWING FORMULA.  Don't credit (or blame) me in your
comments, d'ya hear me?  

All right, now that that's settled:

   n = 367*y- 7*(y+((m+9)/12))/4 - 3*(((y+((m-9)/7))/100)+1)/4 + (275*m/9) + d
								
This will compute a sequential day number 'n' from month m (1 through 12),
day d (1 through 31), and year y (four digits, not two).  It correctly handles
the 4, 100, 400 leap year rule.  It obviously does not validate its inputs, 
but results are "correct" for out of range input (e.g. the results for 
december 32, year y, and january 1, year y+1, are the same; you can use this
to verify that it handles leap years correctly:  The result for feb 29 1900
and mar 1 1900 are the same (not a leap year, so feb 29 was not a unique day),
but the result for feb 29 2000 and mar 1 2000 are different, as they should be.

You'll notice that if you get rid of the spaces, this will fit in a 66-char
line.  So what?  Well, the point of the contest which this item won, was to 
come up with the most interesting thing that could be done in a single line
of Fortran, according to punched-card format, columns 7 through 72, inclusive. 
(And you thought that C programmers could write obscure code!)

I've used this in Fortran, Basic, C, and (now) DCL.  It relies on integer
arithmetic with truncation toward zero; it won't work right in floating point,
nor an environment where, for example, -2/3 yields -1 (truncation downward --
I believe that's the "floor" function, largest integer not greater than the
input).  (It also needs normal precedence rules:  If you try this in APL you'll
need to add some parentheses!)

The only bugs are:  It does not know that there was no year 0, and Day 1 is
December 2 in the year -1; you can of course add or subtract a constant to make
day 0 = 17 nov 1858, if that's what you want.  Also, it does not know about the
14 or so days that were skipped sometime back in the 1700's.  

To compute the day of the week, simply pre-compute the day of the week and the
day number for, say, 17 nov 1858, and do a little arithmetic.    

No, I don't have a formula for going back from a day number to dd-mmm-yyyy.
(Anyone want to try it?)

	--- Jamie Hanrahan, Kernel Mode Systems, San Diego CA
drivers, internals, networks, applications, and training for VMS and Windows NT
uucp 'g' protocol guru and release coordinator, VMSnet (DECUS uucp) W.G., and 
Chair, Programming and Internals Working Group, U.S. DECUS VMS Systems SIG 
Internet:  jeh@cmkrnl.com (JH645)  Uucp: uunet!cmkrnl!jeh  CIS: 74140,2055

