mac-rom/Toolbox/SexyDate.a

225 lines
6.5 KiB
Plaintext
Raw Permalink Normal View History

;EASE$$$ READ ONLY COPY of file <20>sexydate.a<>
; 1.1 CCH 11/10/1988 Fixed Header.
; 1.0 CCH 11/ 9/1988 Adding to EASE.
; OLD REVISIONS BELOW
; 1.0 BBM 2/11/88 Adding file for the first time into EASE<53>
; END EASE MODIFICATION HISTORY
; File SexyDate.TEXT
;
; Routines to convert between number of seconds elapsed since 1904 Jan 1 00:00:00 am
; and date: year / month / day / hour / min / sec / (day of week).
; Written by Jerome T. Coonen 2 July 1983
;
; Seconds: unsigned 32-bit integer passed in D0.
;
; Date: array of 7 16-bit integers pointed to by A0.
; 0: year -- 1904, 1905, ...
; 1: month -- 1, 2, ..., 12
; 2: day -- 1, 2, ..., 31
; 3: hour -- 0, 1, ..., 24
; 4: minute -- 0, 1, ..., 59
; 5: second -- 0, 1, ..., 59
; 6: weekday -- 1, 2, ..., 7 corresponding to Sun, Mon, ..., Sat
;
BLANKS ON
STRING ASIS
SEXYDATE PROC EXPORT
EXPORT SECS2DATE, DATE2SECS
SECS2DATE
MOVEM.L D0-D4/A0,-(SP) ; SAVE WORKING REGISTERS
;
; Have number of seconds N 1904 in D0. Compute
; DN = number of days elapsed = N div 86400 where 86400 = 24 * 60 * 60
; HMS = number of seconds in last day = N mod 86400.
; Since 86400 > 2^31-1 cannot use 68000 DIVU directly. Instead, divide halved number
; of seconds by 43200. To get HMS, must double computed mod (with 43200) and add in the
; low order bit of the input N.
;
MOVEQ #0,D1 ; INIT HMS
LSR.L #1,D0 ; N DIV 2, WITH ODD BIT TO X
ROXR.L #1,D1 ; GET X BIT IN HI SLOT, FOR LATER ROTATE
DIVU #43200,D0
SWAP D0 ; GET MOD 43200 IN D0.W
MOVE.W D0,D1 ; HALF THE MOD IN D1.W
ROL.L #1,D1
CLR.W D0 ; WANT LONG DN
SWAP D0 ; DN
;
; YearsGone = (DN * 4) div 1461 where 1461 is 4*365+1
; Formula depends on leap year being the first of the four.
;
MOVE.L D0,D2 ; COPY DN
ASL.L #2,D2 ; DN * 4
DIVU #1461,D2 ; YEARSGONE = (DN * 4) DIV 1461
ADDI.W #1904,D2 ; YEAR
MOVE.W D2,(A0)+
;
; Need number of days in Jan+Feb just below. So take YEAR mod 3 before clearing year.
;
MOVEQ #59,D3 ; ASSUME NOT LEAP YEAR
ANDI.W #3,D2 ; YEAR MOD 3
BNE.S SDNOTLEAP
ADDQ.W #1,D3
SDNOTLEAP
CLR.W D2 ; LEAVE 4 * DOY = DAY OF YEAR IN HI WORD
SWAP D2
LSR.W #2,D2 ; D0Y
;
; Computing Month/Day from DOY is an exercise in interpolation. As a function of DOY,
; MONTH is a step function. Because of the leap year glitch, convenient to restart
; function at March.
;
; DOY MONTH
;-------------------------------------------------------------------
; 0-30 1 -- January
; 31-58/59 2 -- February (depends on whether leap year)
;
; 0-30 3 -- March
; 31-60 4 -- April
; 61-91 5 -- May
; 92-121 6 -- June
; 122-152 7 -- July
; 153-183 8 -- August
; 184-213 9 -- September
; 214-244 10 -- October
; 244-274 11 -- November
; 275-305 12 -- December
;
; The linear interpolator is ((DOY * 128) + 71) div 3919.
;
MOVEQ #1,D4 ; MONTH OFFSET, 1 OR 3
CMP.W D3,D2 ; 59/60 VERSUS DOY
BLT.S SDJANORFEB ; LESS THAN MEANS JAN OR FEB
ADDQ.W #2,D4 ; ADJUST MONTH OFFSET
SUB.W D3,D2 ; START DOY AT MARCH
SDJANORFEB
LSL.L #7,D2 ; DOY * 128
MOVEQ #71,D3
ADD.L D3,D2 ; (DOY * 128) + 71
DIVU #3919,D2 ; ((DOY * 128) + 71) DIV 3919
ADD.W D4,D2 ; ADJUST MONTH 1..12
SWAP D2 ; HAVE MONTH | DAY-1
LSR.W #7,D2 ; DIVIDE BY 128 TO GET DAY OF MONTH
ADDQ.W #1,D2 ; DAY 1..31
MOVE.L D2,(A0)+
;
; HOURS = HMS div 3600
; MS = HMS mod 3600 = minutes/seconds
; MINUTES = MS div 60
; SECONDS = MS mod 60
;
DIVU #3600,D1 ; HMS DIV 3600
MOVE.W D1,(A0)+ ; HOURS
CLR.W D1
SWAP D1 ; MS
DIVU #60,D1 ; SECONDS | MINUTES
SWAP D1
MOVE.L D1,(A0)+ ; MINUTES | SECONDS
;
; Finally get the day of week = ((DN + 5) mod 7) + 1
; The 5 is added since 1 Jan 1904 was a Friday.
;
ADDQ.W #5,D0
DIVU #7,D0
SWAP D0
ADDQ.W #1,D0
MOVE.W D0,(A0)
;
; Clean up stack and return.
;
MOVEM.L (SP)+,D0-D4/A0
RTS
;
; Have year / month / day / hours / min / sec in a sequence of words pointed to by A0.
; Deduce number of seconds since 1904, and return in D0.
;
; Since a date is no more than a representation of time in a bizarre mixed radix,
; the computation reduces to:
; DAYSGONE * 86400 + HOURS * 3600 + MINUTES * 60 + SECONDS
; The hard part is deducing the DAYSGONE from the YEAR / MONTH / DAY.
;
DATE2SECS
MOVEM.L D1-D4,-(SP) ; WORKING REGISTERS
;
; Do the easy part with HOURS, MINUTES, and SECONDS.
;
MOVEQ #0,D0 ; INIT SECOND COUNT
ADDQ.L #8,A0 ; POINT TO MINUTES/SECONDS
MOVE.L (A0),D1 ; MINUTES | SECONDS
MOVE.W D1,D0 ; SECONDS
SWAP D1 ; MINUTES
MOVE.W -(A0),D2 ; HOURS
MOVEQ #60,D3
MULU D3,D2 ; HOURS * 60
ADD.W D1,D2 ; (HOURS * 60) + MINUTES
MULU D3,D2 ; ((HOURS * 60) + MINUTES) * 60
ADD.L D2,D0
;
; Compute DAYSGONE in D1.
;
MOVE.W -(A0),D1 ; DAYS
SUBQ.W #1,D1
MOVE.W -(A0),D2 ; MONTH
MOVE.W -(A0),D3 ; YEAR, AND A0 IS BACK TO INPUT VALUE
MOVE.W D3,D4 ; COPY YEAR FOR LEAP TEST
;
; To find number of days in elapsed years use ((YEARSGONE * 1461) + 3) div 4.
; Formula depends on leap year being the first of a quartet.
;
SUBI.W #1904,D3 ; YEARSGONE
MULU #1461,D3 ; YEARSGONE * 1461
ADDQ.L #3,D3 ; (YEARSGONE * 1461) + 3
LSR.L #2,D3 ; ((YEARSGONE * 1461) + 3) DIV 4
ADD.W D3,D1 ; ACCUMULATE DAYSGONE
;
; As above, the tough part is finding the number of days in the elapsed months.
; The function to be interpolated is in a sense the inverse of the step function above.
; The interpolating function is ((MONTHSGONE * 3917) + 52) div 128.
;
SUBQ.W #1,D2 ; MONTH-1 RANGES 0..11
CMPI.W #1,D2 ; 2 OR MORE IS MARCH...
BLE.S DSJANORFEB
SUBQ.W #2,D2 ; MONTH-3, RESTART INTERP AT MARCH
MOVEQ #59,D3 ; DAYS IN JAN AND FEB
ANDI.W #3,D4 ; CHECK FOR LEAP YEAR, MOD 3
BNE.S DSNOTLEAP
ADDQ.W #1,D3
DSNOTLEAP
ADD.W D3,D1 ; SOME MORE ELAPSED DAYS
DSJANORFEB
MULU #3917,D2 ; (MONTHSGONE * 3917)
ADDI.W #52,D2 ; (MONTHSGONE * 3917) + 52
LSR.W #7,D2 ; ((MONTHSGONE * 3917) + 52) DIV 128
ADD.W D2,D1 ; MORE ELAPSED DAYS
;
; Finally multiply the number of days elapsed by 24*60*60 = 86400 = 43200*2
;
MULU #43200,D1
ADD.L D1,D1
ADD.L D1,D0
MOVEM.L (SP)+,D1-D4
RTS
END