vypocet dna v tyzdni
Jan Waclawek
konfera@efton.sk
Čtvrtek Únor 21 23:53:20 CET 2008
Tak som si dovolil male variacie na danu temu. Prva funkcia je vlastne ta povodna, druha je variacia na temu 366-dnovy rok (vratane gregorianskej korekcie), a tretia je modifikacia druhej tak, aby sa to dalo jednoducho implementovat v jednocipe. No a prikladam aj vzorovu implementaciu v '51, ale len pre toto storocie. Oboje ma ako "main" test, ktory testuje den za dnom.
Prijemne (po)citanie! :-)
wek
------
uses crt;
var d,m,y:integer;
dow:integer;
leapday:boolean;
const
dd: array[1..12] of integer = ( 31,28,31,30,31,30,31,31,30,31,30,31);
md:array[1..12] of integer = (
0,
31,
31+29,
31+29+31,
31+29+31+30,
31+29+31+30+31,
31+29+31+30+31+30,
31+29+31+30+31+30+31,
31+29+31+30+31+30+31+31,
31+29+31+30+31+30+31+31+30,
31+29+31+30+31+30+31+31+30+31,
31+29+31+30+31+30+31+31+30+31+30
{ 31+29+31+30+31+30+31+31+30+31+30+31,}
);
function get_dow(d,m,y:integer):integer;
var dd:integer;
const
a=3; b=4;
begin
y:=y-2000;
dd:=y+((y+a) div 4);
dd:=dd+md[m];
if (m>2) and (y mod 4 <> 0) then begin
dd := dd - 1 ;
end;
dd:=dd+d;
dd := dd + b;
get_dow := dd mod 7;
end;
function get_dow2(d,m,y:integer):integer;
var dd,c1,c2,c3,c4:longint;
const b=0000; c=2; {"gregorian" 1.3.0000 - wednesday}
begin
dd:=longint(y-b)*366+md[m]+d-31-29-1; {nr of days since 1.3.0000 in hypothetical 366-day years}
c1:=dd div 366; {correction 366 -> 365 days per year}
c2:=c1 div 4; {standard Julian leap year correction}
c3:=c1 div 100; {Gregorian correction for 100 years are not leap}
c4:=c1 div 400; {Gregorian correction for the overshoot in each 400 years}
dd := dd - c1 + c2 - c3 + c4;
get_dow2 := (dd + c) mod 7;
end;
function get_dow3(d,m,y:integer):integer;
var dd,c1,c2,c3,c4:longint;
const b=0000; c=4; {"gregorian" 1.3.0000 - wednesday}
begin
dd:=longint(y-b)*(366 mod 7)+(md[m] mod 7)+d; {nr of days since 1.1.0000 in hypothetical 366-day years}
c1:=y-b; if m<3 then dec(c1);
c2:=c1 div 4; {standard Julian leap year correction}
c3:=c2 div 25; {Gregorian correction for 100 years are not leap}
c4:=c3 div 4; {Gregorian correction for the overshoot in each 400 years}
dd := dd - c1 + c2 - c3 + c4;
get_dow3 := (dd + c) mod 7;
end;
begin
y:=2000;
m:=1;
d:=1;
dow:=5;
repeat
writeln(d:2,'-',m:2,'-',y:2,':',dow:2,'/',get_dow3(d,m,y));
if dow <> get_dow3(d,m,y) then begin
writeln('...mismatch - press ENTER...');
readln;
end;
inc(dow);
dow := dow mod 7;
inc(d);
leapday := (m = 2) and (d = 29) and ((y mod 4) = 0);
if leapday and ((y mod 100) = 0) and not ((y mod 400) = 0) then leapday:=false;
if d>dd[m] then
if not leapday then begin
d:=1;
inc(m);
if m>12 then begin
m:=1;
inc(y);
end;
end;
until keypressed and (readkey=#27);
end.
-------------
$MOD52
day equ 30h
month equ 31h
year equ 32h
dow equ 33h
TestDow:
mov dow,#2
mov year,#0
mov month,#3
sjmp TestDowX2
TestDowX1:
mov month,#1
TestDowX2:
mov day,#1
TestDowX3:
mov r5,day
mov r6,month
mov r7,year
call DayOfWeek
cjne a,dow,Fail
inc dow
mov a,dow
cjne a,#7,TestDowX4
mov dow,#0
TestDowX4:
inc day
mov a,month
add a,#TestDowTab-TestDowX5-1
movc a,@a+pc
TestDowX5:
cjne a,day,TestDowX6
sjmp TestDowX3
TestDowX6:
jnc TestDowX3
mov a,month
cjne a,#2,TestDowX7
mov a,day
cjne a,#29,TestDowX7
mov a,year
anl a,#3
jz TestDowX3
TestDowX7:
inc month
mov a,month
cjne a,#12+1,TestDowX2
inc year
mov a,year
cjne a,#100,TestDowX1
sjmp Pass
TestDowTab:
db 31,28,31,30,31,30,31,31,30,31,30,31
Fail:
ljmp Fail
Pass:
sjmp Pass
;calculates day of week
;good since 01.03.2000 until 31.12.2099
;input: r7 - year (00-99 for 2000-2099)
; r6 - month (01-12)
; r5 - day (01-31, as appropriate for given month)
;no sanity check performed
;returns in acc 00-06 for Monday-Sunday
;uses b
;
DayOfWeek:
mov a,r6
cjne a,#3,DayOfWeekX1
DayOfWeekX1:
mov a,r7
subb a,#0
mov b,a
rr a
rr a
anl a,#03Fh
clr c
subb a,b
mov b,a
mov a,r7
rl a
add a,b
mov b,a
mov a,r6
add a,#DayOfWeekTab-DayOfWeekX2-1
movc a,@a+pc
DayOfWeekX2:
add a,r5
add a,b
add a,#4
mov b,#7
div ab
mov a,b
ret
DayOfWeekTab:
db 0,3,4,0,2,5,0,3,6,1,4,6
end
Další informace o konferenci Hw-list