MCALL  .MODULE
MODULE LOCLTM,RELEASE=Y01,VERSION=11,COMMENT=<LOCLTM/MBGLIB>,IDENT=NO,LIB=YES

;                           Copyright (c) 2000
;                              Megan Gentry
;                       Framingham, Massachusetts
;                          All Rights Reserved
;                  Commercial Distribution Prohibited
;
; This software may be  freely copied  and used in its entirety for any
; purpose  so long as the above copyright notice and these comments are
; preserved  in  the  source  form  of  this  software, and  the binary
; copyright is preserved in any image built from it.
;
; The author has used best efforts in the research, design, development
; and  testing of  this software.  The author  makes no warranty of any
; kind,  expressed or  implied,  with  regard to  this software and its
; suitability for a given application.  The author shall not  be liable
; in any  event for  incidental or  consequential damages in connection
; with, or arising out of, the use or performance of this software. Use
; of this software constitutes acceptance of these terms.
;
; The author  is committed to making a best effort at fixing any errors
; found  in the  software and  would welcome  any reports  of problems,
; comments  or suggestions  regarding the software.   Please send email
; to <[email protected]>.
      .SBTTL  Edit History

;+
;
; Edit History:
;
; X00 (00) 17-Nov-1999 Megan Gentry
;       Initial coding.
;
; X00 (01) 19-Nov-1999 Megan Gentry
;       o Coding change to use a register in modulo calculation
;         to make it faster.
;       o Convert days per month table to a word table to make
;         calculation of days since Jan 1 faster by reducing
;         number of instructions
;       o Added conditional for EIS
;
; X00 (02) 22-Nov-1999 Megan Gentry
;       Converted name to ILCTIM, to make it closer to the
;       U*x style localtime() routine.
;
; X00 (03) 24-Nov-1999 Megan Gentry
;       Adding code to determine when daylight savings time
;       is in effect so as to return the flag.  Current code
;       will be based on the generic US rule.
;
; X00 (04) 29-Nov-1999 Megan Gentry
;       To be consistent with localtime() call on U*x, this
;       routine should return years since 1900.
;
; X00 (05) 29-Nov-1999 Megan Gentry
;       Check for patently invalid date needs to be split to
;       check month and day separately.
;
; X00 (06) 20-Jan-2000 Megan Gentry
;       Updated Copyright
;
; X00 (07) 28-Jan-2000 Megan Gentry
;       Removed .ASECT use for defining structure offsets, converted
;       to using .DSECT/.DS/.EQU
;
; X00 (08) 10-Feb-2000 Megan Gentry
;       o Changed routine name to LOCLTM to bring it even closer to the
;         U*x name for the routine.
;       o Added more EIS conditional code
;
; Y01 (09) 11-Feb-2000 Megan Gentry
;       o Ready for initial release
;
; Y01 (10) 11-Feb-2000 Megan Gentry
;       o Development of mktime library routine resulted in discovery
;         that there was insufficient information in the TM Array for
;         mktime to be a complete complement of locltm -- the ticks
;         information was lost.  This change added a new TM Array
;         entry for the tick information.
;
; Y01 (11) 14-Feb-2000 Megan Gentry
;       o Month information is supposed to be returned in range 0-11,
;         not 1-12, per U*x library routine localtime()
;       o Corrected TM Array names to be consistent with U*x
;         library routine localtime()
;
;-
      .SBTTL  Definitions

; RT-11 System Macros to be used

       .MCALL  .DATE   .GTIM
       .MCALL  .ASSUM

; Declare the system definition library

       .LIBRARY "SRC:SYSTEM.MLB"

; RT-11 System structure definitions to be used

       .MCALL  .DATDF  .DTMDF  .TIMDF
       .DATDF
       .DTMDF
       .TIMDF

       .MCALL  .DSECT  .DS     .EQU
      .SBTTL  Local definitions

; Define local structure of TM Array

       .DSECT
       .DS     TM.SEC                  ; : Seconds after the minute (0 - 59)
       .DS     TM.MIN                  ; : Minutes after the hour (0 - 59)
       .DS     TM.HOUR                 ; : Hours since midnight (0 - 23)
       .DS     TM.MDAY                 ; : Day of month (1 - 31)
       .DS     TM.MON                  ; : Month of year (0 - 11)
       .DS     TM.YEAR                 ; : Years since 1900 (72 - 199)
       .DS     TM.WDAY                 ; : Days since Sunday (0 - 6)
       .DS     TM.YDAY                 ; : Days since January 1st (0 - 365)
       .DS     TM.ISDST                ; : Daylight Savings Time flag
; Note: Other than TM.TICKS, the following are not supported yet
       .DS     TM.GMT  2               ; : Seconds east of Greenwich
       .DS     TM.TZ                   ; : Time zone code
       .DS     TM.TICKS                ; : Ticks into a second (0 - 59)

; Define Days since Sunday values

       .EQU    TM$SUN  0
       .EQU    TM$MON  1
       .EQU    TM$TUE  2
       .EQU    TM$WED  3
       .EQU    TM$THU  4
       .EQU    TM$FRI  5
       .EQU    TM$SAT  6

;;;     .EQU    TM$EWD  TM$MON          ;For 1900-based epoch
;;;     .EQU    TM$EWD  TM$THU          ;For 1970-based epoch
       .EQU    TM$EWD  TM$SAT          ;For 1972-based epoch
      .SBTTL  Miscellaneous Definitions

; Define the globals

       .GLOBL  $SYSLB
       .GLOBL  $ARGER
       .GLOBL  $NXADR

; Define any conditionals

       .IIF NDF FT.EIS FT.EIS = 0      ;By default, don't use EIS
      .SBTTL  Revision and Copyright string for images

       .PSECT  .COPY.  RO,D

       .NLCSI  TYPE=I
       .ASCII  /Copyright (c) 2000 Megan Gentry/<15><12>
      .SBTTL  LOCLTM  - Convert RT-11 date/time to an array of values

;+
;
; LOCLTM
;       This fortran-callable subroutine is modelled after the U*x
;       call localtime(), and is designed to take a date and time
;       specified in the RT-11 date word and timeblock format (or
;       take the current date and time if unspecified) and fill a
;       data structure with the converted date and time information.
;
; Call:
;
;       CALL LOCLTM ( TM [, DATMBK] )
;
;    where:
;       TM      is an INTEGER*2 array containing 13. entries which will
;               be filled in with individual date/time information as
;               documented below.
;
;       DATMBK  is an optional INTEGER*2 array containing the RT-11 date
;               and time in the following format:
;
;                       +----------+
;                       |   date   |[0] DTM.DT  (returned from .DATE)
;                       +----------+
;                       | time, hi |[2] DTM.TM+TIM.HI (as returned from .GTIM)
;                       +          +
;                       | time, lo |[4] DTM.TM+TIM.HI
;                       +----------+
;
;               If this argument is not provided, the current date and
;               time will be used to fill in the TM Array.
;
; Return:
;       If there was no error, the TM array has been filled in with
;       the following information:
;
;               TM[0]   Seconds after the minute [0-59]
;               TM[1]   Minutes after the hour [0-59]
;               TM[2]   Hours since midnight [0-23]
;               TM[3]   Day of the month [1-31]
;               TM[4]   Month of the year [1-12]
;               TM[5]   Years since 1900 [0-199]
;               TM[6]   Days since Sunday [0-6]
;               TM[7]   Days since January 1 [0-365]
;               TM[8]   Daylight Savings Time flag
;
;       The next three entries are not currently returned.  If/When
;       additional time zones are supported, this information may
;       be returned.
;
;               TM[9]   Seconds east of Greenwich (lo-order word) <future>
;               TM[10]  Seconds east of Greenwich (hi-order word) <future>
;                         (negative indicates west of Greenwich)
;               TM[11]  Time Zone code                            <future>
;
;       The following is RT-specific since RT stores the date and
;       time information down to clock ticks.
;
;               TM[12]  Ticks into the second [0-59]
;
; Errors:
;       o If there is no TM Array specified in the call
;       o If the date or time information is invalid
;
; Notes:
;       o This module was designed from the standpoint of taking as
;         input (or using) a date/time value specified in whatever
;         form is appropriate for the system and using it to fill the
;         TM Array.  This is why we don't use the U*x style 32-bit
;         integer containing seconds since Jan 1, 1900.
;
;       o The base year of the RT-11 Epoch is 1972, but we still return
;         a count of years since 1900 (since that is what the U*x
;         localtime routine does).
;
;       o If a date/time block is not specified in the call, this routine
;         allocates space from the stack in order to perform the programmed
;         requests to obtain the current date and time.
;
;       o The daylight savings time flag is set or reset based on the
;         generic US rule.
;
;-

       .GLOBL  LOCLTM

       .PSECT  SYS$I,I

       .ENABL  LSB

ERROR:  MOV     #$ARGER,R0
       SEC
       RETURN

LOCLTM::
       MOV     (R5)+,R4                ;R4 = Argument count

       CALL    $NXADR                  ;Get first argument (-> TM Array)
       BCS     ERROR                   ;None specified!
       MOV     R0,R1                   ;R1 -> TM Array

       SUB     #<5*2>,SP               ;Make room for argument blocks
                                       ; (2 words for emt area,
                                       ;  3 words for date/time block)

       CALL    $NXADR                  ;Try for pointer to date/time block
       BCC     10$                     ;We got it...

       MOV     SP,R4                   ;R4 -> date/time block
       ADD     #<3*2>,R4               ; (at the hi-order time word)
       MOV     SP,R3                   ;R3 -> EMT Area block
       .GTIM   R3,R4                   ;Get the current time
       .DATE                           ;Get the current date
       MOV     R0,-(R4)                ; and save it
       BR      20$

10$:    MOV     R0,R4                   ;R2 -> Date/time block
20$:

       MOV     <DTM.TM+TIM.HI>(R4),R2  ;R2 = Hi-order time
       MOV     <DTM.TM+TIM.LO>(R4),R3  ;R3 = Lo-order time

; Here we validate the time.  The time is patently invalid if the
; hi-order portion is greater than 79.  If it exactly equals 79,
; then the low order can be no larger than 6655.

       CMP     R2,#79.                 ;Is time invalid?
       BHI     ERROR                   ;Clearly yes...
       BLO     30$                     ;Clearly no...
       CMP     R3,#6655.               ;Maybe... Check lo-order limit...
       BHI     ERROR                   ;Clearly yes...
30$:

; Here we parse the date word.
;
;       RT extended date word (16 bits) = EEMMMMDDDDDYYYYY
;               E = epoch bits
;               M = month bits
;               D = day bits
;               Y = year bits
;
; The date is patently invalid if the day and/or month field is zero.
; Further checking *could* be done to ensure that the month field is
; also not greater than 12.  And if we wanted to get really pedantic,
; we could have the code verify that the day field is valid for a
; given month, taking into account leap years.

       .Assume DTM.DT EQ 0
       MOV     @R4,R0                  ;R0 = Date word
       BIC     #^C<DA.DAY>,R0          ;Isolate the day field

       .IF EQ FT.EIS
       ASL     R0                      ; and right-justify in word
       ASL     R0                      ; ...
       ASL     R0                      ; ...
       SWAB    R0                      ; ...
       .IFF ;EQ FT.EIS
       ASH     #-<DA$DAY>,R0           ; and right-justify in word
       .ENDC ;EQ FT.EIS

       MOV     R0,TM.MDAY(R1)          ;Save 'Day of month' in TM Array
       BEQ     ERROR                   ;If zero, date is patently invalid...

       .Assume DTM.DT EQ 0
       MOV     @R4,R0                  ;R0 = Date word
       BIC     #^C<DA.MON>,R0          ;Isolate the month field

       .IF EQ FT.EIS
       ASR     R0                      ; and right-justify in word
       ASR     R0                      ; ...
       SWAB    R0                      ; ...
       .IFF ;EQ FT.EIS
       ASH     #-<DA$MON>,R0           ; and right-justify in word
       .ENDC ;EQ FT.EIS

       BEQ     ERROR                   ;If zero, date is patently invalid...
       CMP     R0,#12.                 ;Nonzero, is it a valid month?
       BHI     ERROR                   ;Nope...

       MOV     R0,TM.MON(R1)           ;Save 'Month of year' in TM Array

;;;     bit     #3,tm.year(r1)          ;Leap year?
;;;     bne     34$                     ;Nope...
;;;     cmp     r0,#2                   ;Yes, is this february?
;;;     bne     34$                     ;Nope...
;;;     cmp     tm.mday(r1),#29.        ;Yes, is the day valid?
;;;     bhi     error                   ;Nope...
;;;     br      36$
;;;
;;;34$: cmp     tm.mday(r1),il$dpm-2(r0) ;Valid day for this month?
;;;     bhi     error                   ;Nope...
;;;36$:
;;;-

       .Assume DTM.DT EQ 0
       MOV     @R4,R0                  ;R0 = Date word
       BIC     #^C<DA.AGE>,R0          ;Isolate the epoch bits
       SWAB    R0                      ; and shift to bits <06:05>
       ASR     R0                      ; ...
       MOV     R0,-(SP)                ;Save intermediate on stack

       .Assume DTM.DT EQ 0
       MOV     @R4,R0                  ;R0 = Date word
       BIC     #^C<DA.YR>,R0           ;Isolate the year bits
       BIS     (SP)+,R0                ;Merge epoch bits
       MOV     R0,TM.YEAR(R1)          ;Save 'Years since epoch' in TM Array

; Hour = time % 216000l;
; time = time / 216000l;

; We have to do double precision here since the largest value can
; be 5183999. (60 ticks * 60 seconds * 60 minutes * 24 hours - 1 tick)
;       5183999 = 79 (*65536) + 6655.
;
; The value 216000 is (60 ticks * 60 seconds * 60 minutes)
;       216000 = 3 (*65536) + 19392.

       .IF EQ FT.EIS
       CLR     R0                      ;Crude divide by 216000, which
40$:    INC     R0                      ; yields hours since midnight
       SUB     #19392.,R3              ; ...
       SBC     R2                      ; ...
       BCC     50$                     ; ...
       ADD     #19392.,R3              ; ...
       ADC     R2                      ; ...
       BR      60$                     ; ...

50$:    SUB     #3,R2                   ; ...
       BHIS    40$                     ; ...

       ADD     #19392.,R3              ;Correct the remainder
       ADC     R2                      ; ...
       ADD     #3,R2                   ; ...
60$:    DEC     R0                      ;Correct the quotient
       MOV     R0,TM.HOUR(R1)          ;Save 'Hours Since Midnight'
                                       ; in TM Array
       .IFF ;EQ FT.EIS
       DIV     #21600.,R2              ;Divide by 21600.
       MOV     R3,-(SP)                ;Save first stage remainder
       MOV     R2,R3                   ;And setup to divide
       CLR     R2                      ; by an additional 10.
       DIV     #10.,R2                 ; value/21600/10 == value/216000
       MOV     R2,TM.HOUR(R1)          ;Save 'Hours Since Midnight'
                                       ; in TM Array
       MOV     R3,R2                   ;Setup to determine real remainder
       MUL     #21600.,R2              ; which is remainder from second
       ADD     (SP)+,R3                ;  division, plus the remainder
       ADC     R2                      ;   from the first, double precision
       .ENDC ;EQ FT.EIS

; Minute = time % 3600
; time = time / 3600

; We still have to do double precision here since the largest value can
; still be 215999. (60 ticks * 60 seconds * 60 minutes - 1 tick)

       .IF EQ FT.EIS
       CLR     R0                      ;Crude divide by 3600, which
70$:    INC     R0                      ; yields minutes past the hour
       SUB     #3600.,R3               ; ...
       BHIS    70$                     ; ...
       SBC     R2                      ; ...
       BCC     70$                     ; ...
       ADD     #3600.,R3               ;Correct the remainder
       ADC     R2                      ; ...
       DEC     R0                      ;Correct the quotient
       MOV     R0,TM.MIN(R1)           ;Save 'Minutes past hour' in TM Array
       .IFF ;EQ FT.EIS
       DIV     #3600.,R2               ;Divide by 3600. for minutes past hour
       MOV     R2,TM.MIN(R1)           ;Save 'Minutes past hour' in TM Array
       CLR     R2                      ;Clear high-order component
       .ENDC ;EQ FT.EIS

; second = time % 60
; time = time / 60;

; At this point, we can stop doing double precision since the largest
; value is 3599. (60 ticks * 60 seconds - 1 tick)

       .IF EQ FT.EIS
       CLR     R0                      ;Crude divide by 60, which
80$:    INC     R0                      ; yields second of minute
       SUB     #60.,R3                 ;  and tick of second
       BHIS    80$                     ; ...
       ADD     #60.,R3                 ;Correct the remainder
       DEC     R0                      ;Correct the quotient
       MOV     R0,TM.SEC(R1)           ;Save 'Seconds past minute'
                                       ; in TM Array
       .IFF ;EQ FT.EIS
       DIV     #60.,R2                 ;Divide by 60.
       MOV     R2,TM.SEC(R1)           ;Save 'Seconds past minute'
                                       ; in TM Array
       .ENDC ;EQ FT.EIS

       MOV     R3,TM.TICKS(R1)         ;Save 'Ticks into Second'
                                       ; in TM Array

       CLR     R0                      ;Reset counter of days since Jan 1
       MOV     #IL$DPM,R4              ;R3 -> Days per month table
       MOV     TM.MON(R1),R3           ;R3 = Number of month
       BR      100$

90$:    ADD     (R4)+,R0                ;Accumulate count of days
100$:
       .IF EQ FT.EIS
       DEC     R3                      ;More months to account for?
       BGT     90$                     ;Yes...
       .IFF ;EQ FT.EIS
       SOB     R3,90$
       .ENDC ;EQ FT.EIS

110$:   ADD     TM.MDAY(R1),R0          ;Accumulate days for this month
       DEC     R0                      ;Adjust so Jan 1 = zero

       MOV     #<31.+28.+31.-1>,IL$APR ;Set days since Jan 1 for Apr 1
       MOV     #<31.+28.+31.+30.+31.+30.+31.+31.+30.+31.-1>,IL$OCT
                                       ;Set days since Jan 1 for Nov 1
                                       ; (we'll start with Nov and work
                                       ;  backward to last sunday in Oct)

; Although it is understood that the algorithm for determining whether
; a given year is a leap year is more complex then simply checking the
; low-order two bits of the year, it has already been determined that
; this simple algorithm is sufficient to work properly for all years in
; the range of valid years for RT-11 (1972 - 2099).

       MOV     TM.YEAR(R1),-(SP)       ;Stack years since start of epoch
       ADD     #DA.YR0,@SP             ; and convert to actual year
       BIC     #^B<11>,(SP)+           ;Is it a leap year?
       BNE     120$                    ;Nope...
       INC     R0                      ;Yes, account for 29-day february
       INC     IL$APR                  ; ...
       INC     IL$OCT                  ; ...
120$:   MOV     R0,TM.YDAY(R1)          ;Save 'Days since January 1st'
                                       ; in TM Array

; Here we determine the day of the week (sunday = 0).  This code depends
; on the fact that the first year of the RT epoch (1972) was a leap year,
; and that every four years across the range of valid dates is also a
; leap year.  If a different epoch is selected (I don't see why it would
; be), a more precise algorithm should probably be used.

       MOV     #TM$EWD,R0              ;R0 = dow for first day of epoch
       MOV     TM.YEAR(R1),-(SP)       ;Stack the years since epoch
       BEQ     130$                    ;Zero...

       INC     R0                      ;Account for first year of epoch
                                       ; being a leap year

       ADD     @SP,R0                  ;Starting day shifts by one per year
       DEC     @SP                     ;We only count a leap year in this
                                       ; calculation when we're beyond it
       ASR     @SP                     ;Simple divide by four to determine
       ASR     @SP                     ; number of leap years since epoch
130$:   ADD     (SP)+,R0                ;Adjust dow by number of leap years
       MOV     R0,IL$YWD               ;Save weekday count of start of year
                                       ; (Note: not yet reduced by modulo)
       ADD     TM.YDAY(R1),R0          ;Add Days since January 1st, this year

; Now we have to reduce the count via modulo 7 to a value 0 - 6.

       .IF EQ FT.EIS
       MOV     #7.,R2                  ;R2 = Modulo
140$:   SUB     R2,R0                   ;Reduce count by modulo
       BHIS    140$                    ;Hasn't gone negative, keep going...
       ADD     R2,R0                   ;Account for extra reduction...
       MOV     R0,TM.WDAY(R1)          ;Save 'Days since Sunday' in TM Array
       .IFF ;EQ FT.EIS
       CLR     R2                      ;Clear high order component
       MOV     R0,R3                   ;R3 = Value to reduce by modulo 7
       DIV     #7.,R2                  ;Reduce value by modulo 7
       MOV     R3,TM.WDAY(R1)          ;Save 'Days since Sunday' in TM Array
       .ENDC ;EQ FT.EIS

; In this code, we determine the number of days into the year for
; the first sunday in April, when daylight savings time begins...

       MOV     IL$YWD,R0               ;R0 = Weekday for Jan 1 of this year
       ADD     IL$APR,R0               ;R0 = Weekday for Apr 1 of this year

       .IF EQ FT.EIS
       MOV     #7.,R2                  ;R2 = Modulo
150$:   SUB     R2,R0                   ;Reduce by modulo
       BHIS    150$                    ;Hasn't gone negative, keep going...
       ADD     R2,R0                   ;Account for extra subtract
       .IFF ;EQ FT.EIS
       CLR     R2                      ;Clear high order component
       MOV     R0,R3                   ;R3 = Value to reduce by modulo 7
       DIV     #7.,R2                  ;Reduce value by modulo 7
       MOV     R3,R0                   ;R0 = Value modulo 7 (remainder)
       .ENDC ;EQ FT.EIS

       BEQ     160$                    ;First sunday was Apr 1
       NEG     R0                      ;R0 = Count of days to first Sunday
       ADD     #7.,R0                  ; in April
       ADD     R0,IL$APR               ;Adjust the count of days to Apr 1
160$:

; In this code, we determine the number of days into the year for
; the last sunday in October, when standard time begins...

       MOV     IL$YWD,R0               ;R0 = Weekday for Jan 1 of this year
       ADD     IL$OCT,R0               ;R0 = Weekday for Nov 1 of this year
                                       ; (We're starting with Nov 1 and
                                       ;  working backward to last Sunday
                                       ;  in Oct)

       .IF EQ FT.EIS
       MOV     #7.,R2                  ;R2 = Modulo
170$:   SUB     R2,R0                   ;Reduce by modulo
       BHIS    170$                    ;Hasn't gone negative, keep going...
       ADD     R2,R0                   ;Account for extra subtract
       .IFF ;EQ FT.EIS
       CLR     R2                      ;R2 = High order component (zero)
       MOV     R0,R3                   ;R3 = Value to reduce by modulo 7
       DIV     #7.,R2                  ;Reduce value by modulo 7
       MOV     R3,R0                   ;R0 = Value modulo 7 (remainder)
       .ENDC ;EQ FT.EIS

       BNE     180$                    ;R0 = Count of days since Sunday
                                       ; (which was last sunday of October)
       .IF EQ FT.EIS
       MOV     R2,R0                   ;It was exactly one week ago...
       .IFF ;EQ FT.EIS
       MOV     #7.,R0                  ;It was exactly one week ago...
       .ENDC ;EQ FT.EIS

180$:   SUB     R0,IL$APR               ;Adjust the count of days to first
                                       ; Sunday in October

; Here is the beginning of the code which attempts to figure out if
; daylight savings time is in affect.  For the meantime, this routine
; uses only the algorithm defined for the mainland US, and only the
; generic one at that...

       CLR     TM.ISDST(R1)            ;Default to standard time
       CMP     TM.YDAY(R1),IL$APR      ;Before first sunday in April?
       BLO     210$                    ;Yes, still standard time
       BHI     190$                    ;It's after the first sunday in April
       CMP     TM.HOUR(R1),#2          ;First sunday in April, after 2am?
       BLO     210$                    ;Not yet, still in standard time...
       BR      200$                    ;Yes, we're in daylight savings time

190$:   CMP     TM.YDAY(R1),IL$OCT      ;After last sunday in October?
       BHI     210$                    ;Yes, it is standard time
       BLO     200$                    ;It's before last sunday of October
       CMP     TM.HOUR(R1),#2          ;Last sunday in October, after 2am?
       BHI     210$                    ;Yes, we're in standard time again...

200$:   MOV     #1,TM.ISDST(R1)         ;Flag for daylight savings time
210$:

       ADD     #<1972.-1900.>,TM.YEAR(R1) ;Now make it years since 1900
                                       ; to match localtime()
       DEC     TM.MON(R1)              ;Also, month is returned in range 0-11

       ADD     #<5*2>,SP               ;Restore stack
       CLC                             ;Return success
       RETURN

       .DSABL  LSB
      .SBTTL  Pure Data

       .PSECT  SYS$D,D

;       "Thirty days hath September,
;         April, June and November;
;        All the rest have thirty-one
;         Excepting February alone;
;          Which hath but twenty-eight, in fine,
;           Till leap year gives it twenty-nine."

IL$DPM: .WORD   31. , 28. , 31. , 30. , 31. , 30.
       .WORD   31. , 31. , 30. , 31. , 30. ; 31. (last entry not ever used)
      .SBTTL  Impure Data

       .PSECT  SYS$D,D

; The following is for determining if daylight savings time is in effect

IL$YWD: .BLKW                           ;Day of week for Jan 1
IL$APR: .BLKW                           ;Offset to first sunday in April
IL$OCT: .BLKW                           ;Offset to last sunday in October

       .END