Discussion:
Wochentag bestimmen
(zu alt für eine Antwort)
Franz Bachler
vor 17 Jahren
Permalink
Hallo Leute,

Hat jemand von Euch eine Funktion, welche den Wochentag ermittelt?
(in AnsiC wenn möglich, C++ nur im "Notfall")

Eingabe von Tag, Monat und Jahr (4stellig) und Rückgabe von
1 = Sonntag, 2 = Montag, ., usw.

Ev. Vielleicht noch eine "Luxusversion", die das Datum auf Gültigkeit prüft:

Rückgabe von 0 bei einem ungültigem Datum wie z.B.

29. Februar 2007, 31. April, 32. Dezember usw.

Besten Dank!

Franz Bachler
--
Franz Bachler
A-3250 Wieselburg
E-Mail: fraba (at) gmx.at
Homepage: http://members.aon.at/fraba
oder http://home.pages.at/fraba
Andreas Burmester
vor 17 Jahren
Permalink
Post by Franz Bachler
Hat jemand von Euch eine Funktion, welche den Wochentag ermittelt?
(in AnsiC wenn möglich, C++ nur im "Notfall")
mktime().
Post by Franz Bachler
Eingabe von Tag, Monat und Jahr (4stellig)
In einer `struct tm' deren `tm_mday', `tm_mon' und `tm_year' setzen,
mktime() rufen, ...
Post by Franz Bachler
und Rückgabe von 1 = Sonntag, 2 = Montag, ., usw.
... `tm_wday' auslesen.
Testen, ob mktime() `(time_t)-1' retourniert oder die gesetzten
Mitglieder veraendert hat.

b.
Andreas Burmester
vor 17 Jahren
Permalink
Post by Franz Bachler
Hat jemand von Euch eine Funktion, welche den Wochentag ermittelt?
Oder FAQ 17.27 lesen.

b.
Franz Bachler
vor 17 Jahren
Permalink
Hallo,

schön, aber ich möchte wirklich eine selbstgebastelte Funktion, die man
unter *allen* Ansi-C-Compilern selbst kompilieren kann, sei es gcc (mit
DJGPP), Borland, M$ usw. - auch für Linux!

Unter Turbo Pascal habe ich da mal was gefunden. (siehe weiter unten)
Eigentlich bräuchte man das nur in C umzuschreiben und die "Luxusversion"
ließe sich noch später ergänzen.

Bitte um Verständnis für den Pascal-Source-Code-Eintrag und keine Flames
wegen "off-topic".

Danke!



PROGRAM Ewiger_Kalender;

USES Crt;

TYPE Tag_Typ = ARRAY [1 .. 7] OF STRING[11];
Monats_Typ = ARRAY [1 .. 12] OF STRING[11];

VAR d,m,y,t,s: Integer;
k,l,o,p,z,z1,z2,z3,z4,z5: Real;
tag: Tag_Typ;
monat: Monats_Typ;

FUNCTION ReadInt(anzahl:Byte):Integer;

VAR
eingabe,puff : String;
cf : Text;
savex,savey : Byte;
contr,zahl : Integer;

BEGIN
IF anzahl>4 THEN anzahl:=4;
AssignCrt(cf);
SetTextBuf(cf,puff,anzahl+2);
Reset(cf);
savex:=WhereX; savey:=WhereY;
REPEAT
GotoXY(savex,savey);
ClrEoL;
ReadLn(cf,eingabe);
IF savey=Hi(WindMax)+1 THEN Dec(savey);
Val(eingabe,zahl,contr);
UNTIL contr=0;
Close(cf);
GotoXY(savex+Length(eingabe),savey);
ReadInt:=zahl;
END;

BEGIN
Tag[1]:='Sonntag';
Tag[2]:='Montag';
Tag[3]:='Dienstag';
Tag[4]:='Mittwoch';
Tag[5]:='Donnerstag';
Tag[6]:='Freitag';
Tag[7]:='Samstag';
Monat[1]:='J"nner';
Monat[2]:='Februar';
Monat[3]:='M"rz';
Monat[4]:='April';
Monat[5]:='Mai';
Monat[6]:='Juni';
Monat[7]:='Juli';
Monat[8]:='August';
Monat[9]:='September';
Monat[10]:='Oktober';
Monat[11]:='November';
Monat[12]:='Dezember';
S:=1;
Clrscr;
TextColor(2);
Writeln(' E W I G E R K A L E N D E R');
Writeln(' =============================');
Writeln;
Writeln;
Textcolor(4);
Writeln(' Dieses Programm ermittelt den Wochentag eines Datums.');
Writeln(' Bitte kein Jahr vor 1753 eingeben (Gregor. Kalender)!');
Writeln(' Durch Eingabe einer 0 k"nnen Sie das Programm beenden.');
REPEAT
Writeln;
Writeln;
Textcolor(3);
Writeln(' Bitte Datum eingeben: ');
Writeln;
REPEAT
Textcolor(5);
Write(' Tag: ');
Textcolor(7);
D:=Readint(2);
Writeln;
IF D=0 THEN
BEGIN
Writeln;
Writeln;
Exit;
END;
UNTIL d<32;
Writeln;
REPEAT
Textcolor(5);
Write(' Monat: ');
Textcolor(7);
M:=Readint(2);
Writeln;
IF M=0 THEN
BEGIN
Writeln;
Writeln;
Exit;
END;
UNTIL m<13;
Writeln;
REPEAT
Textcolor(5);
Write(' Jahr: ');
Textcolor(7);
Y:=Readint(4);
Writeln;
IF Y=0 THEN
BEGIN
Writeln;
Writeln;
Exit;
END;
UNTIL (y>1752) AND (y<3000);
Writeln;
Writeln;
k:=int(0.6+(1/m));
l:=y-k;
o:=m+12*k;
p:=l/100;
z1:=int(p/4);
z2:=int(p);
z3:=int((5*l)/4);
z4:=int(13*(o+1)/5);
z5:=z4+z3-z2+z1+d-1;
z:=z5-(7*int(z5/7))+1;
t:=trunc(z);
writeln(' Der ',D,'. ',Monat[m],' ',Y,' f"llt auf einen ',tag[t],'!');
writeln;
UNTIL s=0;
END.
Daniel Fischer
vor 17 Jahren
Permalink
Franz Bachler!
Post by Franz Bachler
schön, aber ich möchte wirklich eine selbstgebastelte Funktion, die man
unter *allen* Ansi-C-Compilern selbst kompilieren kann, sei es gcc (mit
DJGPP), Borland, M$ usw. - auch für Linux!
Und was ist da jetzt das Problem mit den drei Lösungen aus der FAQ?
Post by Franz Bachler
Bitte um Verständnis für den Pascal-Source-Code-Eintrag und keine
Flames wegen "off-topic".
Ok, werde nicht flamen, aber ein wenig in der Ecke stehen und was von
Quiche grummeln.


Gruß
Daniel
Marcel Müller
vor 17 Jahren
Permalink
Post by Franz Bachler
schön, aber ich möchte wirklich eine selbstgebastelte Funktion,
OK, wenn es unbedingt selbstgebastelt sein muss, dann viel Spaß beim
Implementieren des Gregorianischen Kalenders.
Wenn man sich auf das Intervall 1901-2099 beschränkt, kann man sich die
Ausnahmeregelungen für die Schaltjahre schenken, da 2000 die Ausnahme
von der Ausnahme war.
Post by Franz Bachler
die man
unter *allen* Ansi-C-Compilern selbst kompilieren kann, sei es gcc (mit
DJGPP), Borland, M$ usw. - auch für Linux!
Dann würde ich mal ganz schnell in den Sourcecodes der LIBC-Runtime
nachschauen, wie die das gemacht haben. In der bereits erwähnten
Funktion ist das Problem letztlich auch gelöst.


Marcel
Thomas Rachel
vor 17 Jahren
Permalink
Post by Marcel Müller
OK, wenn es unbedingt selbstgebastelt sein muss, dann viel Spaß beim
Implementieren des Gregorianischen Kalenders.
Wenn man sich auf das Intervall 1901-2099 beschränkt, kann man sich die
Ausnahmeregelungen für die Schaltjahre schenken, da 2000 die Ausnahme
von der Ausnahme war.
Warum sollte man sich das sparen? Eine einzige gesparte Modulo-Operation
(% 400) ist nicht wirklich viel...


Thomas
Claus Reibenstein
vor 17 Jahren
Permalink
Post by Thomas Rachel
Warum sollte man sich das sparen? Eine einzige gesparte Modulo-Operation
(% 400) ist nicht wirklich viel...
Es sind zwei gesparte Modulo-Operationen (% 100 und % 400) und zwei
logische Verknüpfungen :-)

Gruß. Claus
Andreas Burmester
vor 17 Jahren
Permalink
Post by Franz Bachler
schön, aber ich möchte wirklich eine selbstgebastelte Funktion, die man
unter *allen* Ansi-C-Compilern selbst kompilieren kann, sei es gcc (mit
DJGPP), Borland, M$ usw. - auch für Linux!
0. Lerne zu zitieren.
1. war von einem "wirklich" und "selbstgebastelt" in Deiner Frage keine
Rede.
2. ist mktime() "unter *allen* Ansi-C-Compilern" vorhanden.
3. Studiere die Sourcen von mktime().
4. bist Du dem Hinweis auf die FAQ nicht gefolgt.

b.
Franz Bachler
vor 17 Jahren
Permalink
Habe da was unter Delphi gefunden:

http://www.delphipraxis.net/post818955.html

// t = Tag, m = Monat, j = Jahr
t := StrToInt (Edit1.Text);
m := StrToInt (Edit2.Text);
j := StrToInt (Edit3.Text);

// Zusatzangaben vom Aufgabenblatt
y := j mod 100;
c := j div 100;

// Rechnung
w := (t+(13*(m+1))div 5 + y + y div 4 + c div 4 - 2*c) mod 7;

// Problem für Zahlen die Kleiner 0 Werden --> Entsteht im Januer und
Februar
while w < 0 do
w := w + 7;

das kann man leicht in C umwandeln.

Oder auch hier ist die Formel versteckt:

http://www.hib-wien.at/leute/wurban/mathematik/Freitag13.pdf
Franz Bachler
vor 17 Jahren
Permalink
So habe jetzt sogar zwei funktionsfähige Varianten ermittelt und getestet:

/* gibt Wochentag zurueck */
/* 1 = Sonntag, 2 = Montag, ... , 7 = Samstag */

int dayofweek(int t,int m,int j)

{
int w,y,c;
if (m<=2) { m=m+12; j=j-1; }
y=j % 100;
c=j / 100;
w=(t+(13*(m+1))/5 + y + y/4 - c + 4) % 7;
while (w<1)
w=w+7;
return(w);
}

int dayofweek(int d,int m,int y)

{
int k,l,o,t,z1,z2,z3,z4,z5,z6;
double p,z;
z=(0.6+(1.0/m));
k=(int) z;
l=y-k;
o=m+12*k;
p=l/100.0;
z=p/4.0;
z1=(int) z;
z2=(int) p;
z=(5.0*l)/4.0;
z3=(int) z;
z=(13.0*(o+1)/5.0);
z4=(int) z;
z5=z4+z3-z2+z1+d-1;
z=z5/7.0;
z6=(int) z;
t=z5-(7*z6)+1;
return(t);
}
Marcel Müller
vor 17 Jahren
Permalink
Post by Franz Bachler
/* gibt Wochentag zurueck */
/* 1 = Sonntag, 2 = Montag, ... , 7 = Samstag */
int dayofweek(int t,int m,int j)
{
int w,y,c;
if (m<=2) { m=m+12; j=j-1; }
y=j % 100;
c=j / 100;
w=(t+(13*(m+1))/5 + y + y/4 - c + 4) % 7;
while (w<1)
w=w+7;
return(w);
}
Hier kommt kein einziger Tag richtig raus.

Die zweite Variante funktioniert, wie es aussieht, wobei mich das ob der
double-Rundung wundert.


Marcel
Franz Bachler
vor 17 Jahren
Permalink
Post by Marcel Müller
Hier kommt kein einziger Tag richtig raus.
Ja das stimmt; ist mir dummerweise nicht gleich aufgefallen. Aber zum Glück
hat Franz Zimmer eine richtige Version veröffentlicht. Danke nochmals an ihn
bei dieser Gelegenheit!
Post by Marcel Müller
Die zweite Variante funktioniert, wie es aussieht, wobei mich das ob der
double-Rundung wundert.
Interessant woher sie stammt: Anfang der 80er Jahre gab es eine Sendung
namens "Computerbox" im österr. Fernsehen und da wurden halt mit dem C64
Basic-Programme erstellt. Da war auch das Kalenderprogramm dabei. Das
Listing habe ich mir per Post schicken lassen und später auf dem MSX
programmiert. Irgendwann wurde es von mir in Pascal konvertiert. Und jetzt
nach mehr als 20 (!) Jahren in C, weil halt jetzt das Interesse auf einmal
da war. Wie sie genau funktioniert ist mir auch ein Rätsel.

Weiters habe ich jetzt ein Programm programmiert, welches ermittelt, auf
welche Wochentage die 13. eines Monats fallen (Stichwort: "Freitag der 13.")
Hier z.B. das Ergebnis für 2008:

Der 13. Juni 2008 ist ein Freitag

3 Tage fallen auf einen Sonntag - das sind 25.00000 Prozent
1 Tage fallen auf einen Montag - das sind 8.33333 Prozent
1 Tage fallen auf einen Dienstag - das sind 8.33333 Prozent
2 Tage fallen auf einen Mittwoch - das sind 16.66667 Prozent
2 Tage fallen auf einen Donnerstag - das sind 16.66667 Prozent
1 Tage fallen auf einen Freitag - das sind 8.33333 Prozent
2 Tage fallen auf einen Samstag - das sind 16.66667 Prozent

Das Ergebnis ist mit beiden Routinen das gleiche. Wobei die erste Routine 3x
so schnell ist (ist auch logisch, weil nur Integer-Arithmetik).

Download unter http://members.aon.at/fraba/datum.zip

Grüsse
Franz
Roland Damm
vor 17 Jahren
Permalink
Moin,
Post by Franz Bachler
Post by Marcel Müller
Die zweite Variante funktioniert, wie es aussieht, wobei mich
das ob der double-Rundung wundert.
Wie sie genau funktioniert ist mir auch ein
R�tsel.
Ganz am Anfang schon mal das 1.0/m ist faszinieren, der Kerhrwert
des Monats... Wie kommt man auf sowas?

CU Rollo
Franz Bachler
vor 17 Jahren
Permalink
Hallo!
Post by Franz Bachler
Wie sie genau funktioniert ist mir auch ein Rätsel
Ganz am Anfang schon mal das 1.0/m ist faszinierend, der Kehrwert
des Monats... Wie kommt man auf sowas?
Man muß offensichtlich den Gesamtzusammenhang betrachten:

z=(0.6+(1.0/m));
k=(int) z;


Jänner: z: 0.6 + 1.0/1 = 1.6 k=1
Februar: z: 0.6 + 1.0/2 = 1.1 k=1
März: z: 0.6 + 1.0/3 = 0.933.. k=0

also Jänner + Februar k=1, ab März k=0

die neue Variante macht das mit

if (m < 3) { m += 13; y--; } else m++;

Irgendwie wird da der Jahresanfang verschoben, damit der 28. oder 29.
Februar quasi der letzte Tag im "Pseudojahr" ist und das "neue" Jahr
definiert beginnt. Somit wird der Wochentag vom 1. März ermittelt und von da
an weitergezählt.

Wie gesagt, die alte Variante war mal Basic, wurde dann Pascal und
schließlich C.

Aber sie funktioniert!

Grüsse
Franz
Franz Zimmer
vor 17 Jahren
Permalink
Hi Franz,

FB> schoen, aber ich moechte wirklich eine selbstgebastelte Funktion, die man
FB> unter *allen* Ansi-C-Compilern selbst kompilieren kann, sei es gcc (mit
FB> DJGPP), Borland, M$ usw. - auch fuer Linux!

da gab es bis 7/97 das Projekt der C-Snippets fuer lauter so kleine Goodies:
Solche Wissens-Sammlungen weiterhin zu pflegen scheint aber genauso
unmodern geworden zu sein, wie dem Lieferumfang von Compilern
didaktisch brauchbare Handbuecher beizulegen.

/* +++Date last modified: 05-Jul-1997 */

/*
** DOW.C
**
** Public domain by VinhHao Nguyen, 03/94
**
** Note: This function is redundant with the function of the same name
** in DAYNUM.C. Which one to use?
**
** If you're already using any functions in SCALDATE.C, DAYNUM.C,
** or TODAY.C, ignore this file and use the other dow().
**
** If you need a stand-alone DOW() function without using any of
** the rest of the SCALDATE package, use this file.
*/

#if ISO_CAL /* monday == 0 */
#define ADJ 5
#else /* sunday == 0 */
#define ADJ 6
#endif

unsigned DOW(unsigned y, unsigned m, unsigned d)
{
if (m < 3)
{
m += 13;
y--;
}
else m++;
return (d + 26 * m / 10 + y + y / 4 - y / 100 + y / 400 + ADJ) % 7;
}

freundliche Gruesse
Franz
Franz Bachler
vor 17 Jahren
Permalink
Der letzte Beitrag von Franz Zimmerl enthielt endlich die richtige gesuchte
Formel.

Darauf aufbauend konnte die gewünschte Luxusversion vollendet werden:

/* gibt Wochentag zurueck */
/* 1 = Sonntag, 2 = Montag, ... , 7 = Samstag */
/* 0 = Datum ungueltig z.B. 29.2.2007, 32.12.2007 */
/* -1 = Jahr kleiner als 1753 oder groesser als 9999 */

int dayofweek(int d, int m, int y)

{
int mon_tag[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int s=0;
if (y % 4==0) s=1;
if (y % 100==0) s=0;
if (y % 400==0) s=1;
if (s) mon_tag[2]=29;
if (y<1753 || y>9999) return(-1);
if (m<1 || m>12) return(0);
if (d<1 || d>mon_tag[m]) return(0);
if (m < 3) { m += 13; y--; } else m++;
s = d + 26 * m / 10 + y + y / 4 - y / 100 + y / 400 + 6;
s = s % 7 + 1;
return(s);
}
Franz Bachler
vor 17 Jahren
Permalink
Hallo,

es geht noch kompakter:

/* 1 = Sonntag, 2 = Montag, ... , 7 = Samstag */
/* 0 = Datum ungültig z.B. 29.2.2007, 32.12.2007 */
/* -1 = Jahr kleiner als 1583 oder größer als 4000 */

int dayofweek(int d, int m, int y)

{
int s=0, mon_tag[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
if ((y % 4==0 && y % 100!=0) || y % 400==0) s=1;
if (y<1583 || y>4000) return(-1);
if (m<1 || m>12 || d<1 || d>mon_tag[m+s]) return(0);
if (m < 3) { m += 13; y--; } else m++;
s = d + 26 * m / 10 + y + y / 4 - y / 100 + y / 400 + 6;
return(s % 7 + 1);
}

Den Bruch "26 * m / 10" kann man auch auf "13 * m / 5 " kürzen.

Grüsse
Franz
Thomas Rachel
vor 17 Jahren
Permalink
Hallo,
...
Selbst dieses Array kann man noch einsparen. Ich habe grade in einer
alten Datei von 1997 folgenden Algorithmus gefunden:

function wotag(j:integer;m,t:byte):twotag;
var
k,l,o: integer;
p:real;
z1,z2,z3,z4:word;

begin
k := trunc(0.6+(1/M)); { Jan od. Feb. -> 1 }
l := j-k; { relevantes Jahr f. Schaltj. }
o := m + 12 * k; { Monat für Jahr l }
p := l / 100; { Jahr100 f. relev. J. }
z1 := trunc(p/4); { 'Jahr400' }
z2 := trunc(p); { Jahr100 }
z3 := (5*l) div 4;
z4 := 13*(o+1) div 5;
wotag := twotag((z4+z3-z2+z1+t-1) mod 7);
end;


Hm. Ist OffT, weil Pascal. Ich übersetze (und verbessere) daher mal:

/* Rückgabewert: 0=So, 1=Mo ... 6=Sa */
int wotag(int j, int m, int t)
{
int k,l,o;
int p;
int z1,z2,z3,z4;

k = (m<=2); // Jan od. Feb. -> 1
l = j-k; // relevantes Jahr f. Schaltj.
o = m + 12 * k; // Monat für Jahr l
p = l / 100; // Jahr100 f. relev. J.
z1 = p/4; // 'Jahr400'
z2 = p; // Jahr100
z3 = (5*l) / 4;
z4 = 13*(o+1) / 5;
return (z4+z3-z2+z1+t-1) % 7;
}

int outp(j,m,t)
{
printf("%04d-%02d-%02d: %d\n",j,m,t,wotag(j,m,t));
if (t==28)
outp(j,m,t+1);
}

/* Mist. Zum Testen brauch ich doch ein Array... */
char tg[]={0,31,28,31,30,31,30,31,31,30,31,30,31,30};
int main()
{
int j,m,t;
for (j=2000; j<2010; j++) {
for (m=1; m<=12; m++) {
outp(j,m,1);
outp(j,m,tg[m]);
}
}
}


Thomas
Harald Luessen
vor 17 Jahren
Permalink
...
Beim 30.02.2008 oder 31.03.2008 sehe ich da ein Problem.
Besser vielleicht so:

int dayofweek(int d, int m, int y)
{
int s = 0;
int mtag[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31,31};
if (y < 1583 || y > 4000)
return -1;
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)
s = 1;
if (m < 1 || m > 12 || d < 1 || d > mtag[m] + s * (m == 2))
return 0;
if (m < 3)
{ m += 12; y--; }
s = d + 26 * (m + 1) / 10 + y + y / 4 - y / 100 + y / 400 + 6;
return s % 7 + 1;
}

Harald

Lesen Sie weiter auf narkive:
Loading...