Here's an assembly language program that computes the day of the week for any Gregorian date from February 24, 1582 to December 31, 9999 inclusive. Please read the comments to see how to pass a date into this program and what to expect as output. Dates earlier than 1582/02/24 can be passed but will produce erroneous output, as the calendar system in general use prior to that date was the (less accurate) Julian system. Note that the British Empire didn't switch to the Gregorian calendar until September 14, 1752.
You can also download the source file via the link below.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;* *
;* CALCULATE THE DAY OF THE WEEK *
;* *
;* by BigDumbDinosaur, March 1997 *
;* *
;* This 6502 assembly language program calculates the day of the week for any *
;* calendar date from February 24, 1582 to December 31, 9999 inclusive. *
;* *
;* --------------------------------------------------------------------------- *
;* *
;* Copyright (C)1997 by BigDumbDinosaur. All rights reserved. *
;* *
;* Permission is granted to copy and redistribute this software, provided this *
;* copyright notice is retained and proper attribution is given. *
;* *
;* THERE IS NO WARRANTY OF ANY KIND WITH THIS SOFTWARE. It's free, so don't *
;* look a gift horse in the mouth. *
;* *
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;
; Calling Syntax:
;
; ldx #<date ;starting address of..,
; ldy #>date ;date data
; jsr cdow ;this subroutine
; sta dow ;day of week returned in .A
;
; .X and .Y are preserved.
;
; The information at DATE must be in the following format:
;
; Offset Data
; --------------------------------------------------------------
; $00 Year MSB. For example, if the year is 1997 then this
; value would be $07.
;
; $01 Year LSB. For example, if the year is 1997 then this
; value would be $CD.
;
; $02 Month, ranging from $01 to $0C.
;
; $03 Date, ranging from $01 to $1F.
; --------------------------------------------------------------
;
; Upon return, .A will contain the day of the week in the range $01-$07,
; with $01 being Sunday.
;
; Execution time will typically be 4150 clock cycles, depending on the
; supplied values. No range checking is performed. A bogus date will
; produce a bogus result.
;
;===============================================================================
;
;DECLARATIONS
;
_origin_ =$02000 ;assembly address
;
zpptr =$FA ;working ZP pointer...
;
; --------------------------------------------------------
; Redefine the above assignments to suit your application.
; --------------------------------------------------------
;
dayswk =7 ;days in a week
march =$03 ;March in binary
s_bits =8 ;number of bits in a byte
s_byte =1 ;size of a byte or char
s_date =4 ;size of the input date
s_dword =4 ;size of a double word
s_word =2 ;size of a word
y2fac =4 ;Y2 computation factor
y3fac =100 ;Y3 computation factor
y4fac =400 ;Y4 computation factor
;
;===============================================================================
;
;COMPUTE DAY OF WEEK
;
*=_origin_ ;set program counter
;
cdow stx zpptr ;save pointer to...
sty zpptr+1 ;date info
ldy #s_date-1 ;bytes in date -1
;
cdow01 lda (zpptr),y ;copy user's date...
sta userdate,y ;into our storage
dey
bpl cdow01
;
lda month ;month
ldx yearlo ;year LSB
ldy yearhi ;year MSB
pha ;save month
;
; ------------------------
; evaluate Y -= M < 3 (Y1)
; ------------------------
;
cmp #march ;month March or later?
bcs cdow03 ;yes, no year adjustment
;
txa ;year LSB
sec
sbc #1 ;move back a year
bcs cdow02
;
dey ;adjust MSB
;
cdow02 tax ;hold LSB
;
cdow03 stx y1 ;save Y1
sty y1+1
;
; -----------------
; compute Y2 (Y1/4)
; -----------------
;
jsr stafaca ;store Y1 in accummulator #1
ldx #<y2fac ;4
ldy #>y2fac
jsr stafacb ;copy to accummulator #2
jsr dpdiv ;Y2=Y1/4
stx y2 ;store
sty y2+1
;
; -------------------
; compute Y3 (Y1/100)
; -------------------
;
jsr stay1fac ;copy Y1 to accummulator #1
ldx #<y3fac
ldy #>y3fac
jsr stafacb ;copy to accummulator #2
jsr dpdiv ;Y3=Y1/100
stx y3 ;store
sty y3+1
;
; -------------------
; compute Y4 (Y1/400)
; -------------------
;
jsr stay1fac
ldx #<y4fac
ldy #>y4fac
jsr stafacb ;copy to accummulator #2
jsr dpdiv ;Y4=Y1/400
stx y4 ;store
sty y4+1
;
; -------------
; combine terms
; -------------
;
clc
lda y1 ;Y1
adc y2 ;Y2
sta acm1
lda y1+1
adc y2+1
sta acm1+1
sec
lda acm1
sbc y3 ;Y3
sta acm1
lda acm1+1
sbc y3+1
sta acm1+1
clc
lda acm1
adc y4 ;Y4
sta acm1
lda acm1+1
adc y4+1
sta acm1+1
pla ;get month
tax ;change 1-12 to...
dex ;0-11
clc
lda acm1 ;combined terms
adc dowmctab,x ;month comp factor
bcc cdow04
;
inc acm1+1
;
cdow04 sta acm1
clc
lda date ;date
adc acm1 ;last term
bcc cdow05
;
inc acm1+1
;
cdow05 sta acm1
ldx #<dayswk ;number of days in a week
ldy #>dayswk
jsr stafacb ;copy to accummulator #2
jsr dpdiv ;ACM1=ACM1 mod 7
adc #1 ;0-6 --> 1-7...
;
; -------------------------------------------------
; remove the ADC #1 instruction for a 0-6 DOW range
; -------------------------------------------------
;
ldx zpptr ;restore
ldy zpptr+1 ;likewise
rts ;return day of week in .A
;
;================================================================================
;
;DOUBLE-PRECISION DIVISION
;
; -----------------------------------------
; acm1 = 16 bit dividend
; acm2 = 16 bit divisor
; -----------------------------------------
; acm1 = 16 bit quotient
; .A = remainder
; .X = quotient LSB
; .Y = quotient MSB
;
; The remainder is also available in acm1+2.
;
; No check is made for division by zero.
; ------------------------------------------
;
dpdiv lda #0
sta acm1+s_word ;clear dividend hi bits
sta acm1+s_word+s_byte
ldx #s_bits*s_word ;bits to process
clc
;
dpdiv01 rol acm1 ;rotate dividend
rol acm1+s_byte
rol acm1+s_word
rol acm1+s_word+s_byte
sec
lda acm1+s_word
sbc acm2 ;subtract divisor
tay
lda acm1+s_word+s_byte
sbc acm2+s_byte
bcc dpdiv02
;
sty acm1+s_word ;save partial quotient
sta acm1+s_word+s_byte
;
dpdiv02 dex
bne dpdiv01 ;next
;
rol acm1 ;rotate in last carry to...
rol acm1+s_byte ;finish quotient
lda acm1+s_word ;get remainder LSB
ldx acm1 ;get quotient LSB
ldy acm1+s_byte ;get quotient MSB
rts
;
;================================================================================
;
;STORE Y1 INTO ACCUMMULATOR #1
;
stay1fac ldx y1
ldy y1+1
;
;================================================================================
;
;STORE INTO ACCUMMULATOR #1
;
stafaca stx acm1
sty acm1+1
rts
;
;================================================================================
;
;STORE INTO ACCUMMULATOR #2
;
stafacb stx acm2
sty acm2+1
rts
;
;===============================================================================
;
;COMPENSATION TABLE
;
dowmctab .byte 0,3,2,5,0,3,5,1,4,6,2,4
;
;===============================================================================
;
;WORKING STORAGE
;
acm1 *=*+s_dword ;accummulator #1
acm2 *=*+s_word ;accummulator #2
y1 *=*+s_word ;adjusted year (Y1)
y2 *=*+s_word ;Y1/4
y3 *=*+s_word ;Y1/100
y4 *=*+s_word ;Y1/400
;
; ---------------------------------------------------------------------
; The above locations can be defined on page zero if room is available.
; Execution time will be reduced about 20 percent.
; ---------------------------------------------------------------------
;
userdate *=*+s_date ;input date storage...
;
yearhi =userdate ;year MSB
yearlo =yearhi+s_byte ;year LSB
month =yearlo+s_byte ;month
date =month+s_byte ;date
;
;===============================================================================