Hello, Guest the thread was called771 times and contains 13 replays

last post from JeeK at the

Wochentage und Zeitumstellung ermitteln

  • Hallo zusammen,


    ich habe mich in den letzten Tagen mit dem Thema Wochentagsberechnung und Terminberechnung für die Sommerzeit/Winterzeit-Zeitumstellung und der Umsetzung in V2 BASIC beschäftigt.

    Grundlage ist der Algorithmus von Georg Gläser wie in Wikipedia beschrieben: https://de.wikipedia.org/wiki/Wochentagsberechnung


    Kurioserweise musste ich den in der Formel enthaltenen Faktor 2,6 auf 2,61 ändern, damit V2 BASIC nicht bei manchen Monaten und Jahren Rechenfehler macht.

    Für die Terminberechnung der Zeitumstellung frage ich beginnend ab Monatsende die Monate März und Oktober rückwärts zählend ab bis der erste (bzw. monatsletzte) Sonntag erreicht ist.


    Ich habe den leisen Verdacht, der eine oder andere Forumleser hat noch viel kürzere, straffere und schnellere Programme zum Thema beizusteuern.

    Weitere Beiträge oder auch Verbesserungsvorschläge zur bestehenden Lösung sind herzlich willkommen. :-)

  • Kurioserweise musste ich den in der Formel enthaltenen Faktor 2,6 auf 2,61 ändern, damit V2 BASIC nicht bei manchen Monaten und Jahren Rechenfehler macht.

    In Zeile

    50 wt = d + int(2.61 * m - 0.2) + y + int(y/4) + int(c/4) - 2 * c

    ist meiner Meinung nach das int beim Ausdruck (2.61 * m - 0.2) zu viel. Modulo 7 wird von der Realzahl berechnet.
    Trotzdem ist die Modulofunktion, wenn man sie mit W-(W/7)*7 berechnet fehleranfällig hinsichtlich Fließkommaabweichungen. Daher hab ich die Korrektor bei der Modulorechnung vorgenommen, etwa 0.01 addiert.

    Zum Experimentieren hab ich wota-test.prg, wo in Teil ab Zeile 500 ein Jahr durchgerechnet wird und dabei die bisherige und die neue Berechnung parallel gemacht und verglichen werden. Bei Abweichung stoppt das Programm (quasi mit einer Debug-Ausgabe).


    Die Testsequenz ab 3000 berechnet die 12 Modulo-7-Werte wie sie im Wikipedia-Artikel stehen, um zu gewährleisten, dass die Modulo-Berechnung den richtigen ganzzahligen Anteil ergibt.

    Ich habe den leisen Verdacht, der eine oder andere Forumleser hat noch viel kürzere, straffere und schnellere Programme zum Thema beizusteuern.

    Weitere Beiträge oder auch Verbesserungsvorschläge zur bestehenden Lösung sind herzlich willkommen.

    Da habe ich mir erlaubt bisschen zu "optimieren", also eigentlich nur eleganter zu machen.

    • Die Wochentag werden über ein Array wt$() ermittelt statt einer langen IF-THEN-Abfolge. Das Array wird in 1000 initialisiert und die Wochentage in DATA-Werten in 2000.
    • Die Monatsverschiebung kann man auch mit einer Formel berechnen: an sich reicht ein -2 und korrigiert den Wert (wenn er von oben wieder herum kommt um +12, also statt 0 oder -1 kommt dann 12 oder 11). Das macht die Klammer mit dem logischen Ausdruck in m=m-2-12*(m<3) die zu -1 wird, wenn der Ausdruck wahr ist, sonst ab 0 bleibt. D.h. -12*-1 -> 12 falls m < 3.
    • Die Auswertung ab Zeile 20 ist nun eine Unteroutine, die entweder interaktiv in 17 oder für die Reihenberechnung in 520 aufgerufen wird.
    • Die Jahreskorrektur bei Monatswert 11 und 12 ist schlicht
    • Die Fehlerbehandlung ab 200 für nicht gültige Monate wird vorgezogen, da sie nicht nebenher abfällt, wie bei der IF-THEN-Serie.
    • Die Eingabe von Tag und Monat sorgt gleich für die Umwandlung auf eine Ganzzahl.
    • In Zeile 3 kann man auswählen, ob eine interaktive Einzelrechnung oder die Reihenberechnung erfolgen soll.

    Siehe wota-jk.prg. Der Source dazu schaut so aus:

    Danke für die Idee und den Beitrag - immer wieder spannend und unterhaltsam wieder die Gelegenheit zu bekommen in BASIC V2 zu hacken ... :D

  • Ich kann das beisteuern.

    Ich bin mir nicht sicher, aber das war mal in einer 64'er drin.

  • Hallo zusammen!


    Vielen Dank für das interessante Feedback und Jeeks Optimierung (ja, eigentlich weiß ich ja, was DATAs sind.. ;)).


    Beim systematischen Testen von Daten fiel mir auf, dass mit der bestehenden Formel Wochentage um genau 3 verschoben sind (z.B. Donnerstag statt Montag), wenn das betreffende Jahr "rundes Jahrhundert + 1" ist und der angegebende Monat Januar oder Februar ist. Also, 1.1.2001, 15.2.1801, solche Werte. Ab 1.3. ist die Welt wieder in Ordnung, auch bei solchen Jahren.


    Im Wikipedia-Artikel habe ich mich nach der intitalen Formel

    {\displaystyle w=(d+\lfloor 2{,}6\cdot m-0{,}2\rfloor +y+\left\lfloor {\frac {y}{4}}\right\rfloor +\left\lfloor {\frac {c}{4}}\right\rfloor -2c){\bmod {7}}}


    gerichtet und nach empirischen Tests am C64 aus der 2,6 eine 2,61 gemacht, für den Modulo ein eigenes Unterprogramm beigesteuert (es ist eigentlich von Mike, nicht von mir) und in Ermangelung einer Gaußklammer (Floor)-Funktion einfach INT(wert) benutzt, da negative Werte, die man z.B. von -2,4 nach -3 "runden" muss, nie vorkommen.


    Im Wikipedia wird zum Programmieren aber ein abgewandelter Algorithmus in der Sprache des Programms LabView empfohlen, der wahrscheinlich das von mir gefundene Problem schon behoben hat:


    Code
    1. if (m < 3) y = y - 1; w = ((d + floor (2.6 * ((m + 9) % 12 + 1) - 0.2) + y % 100 + floor (y % 100 / 4) + floor (y / 400) - 2 * floor (y / 100) - 1) % 7 + 7) % 7 + 1;


    Ich wollte aber beim ursprünglichen Konzept bleiben und habe einen Workaround geschrieben. Sind also Daten betroffen wie 1901, 2001, etc. und der Monat ist Jan oder Feb, wird dies nun korrigiert. Wenn man das Programm austrickst und dreistellige Jahreszahlen einfach mit einer führenden Null erzwingt (z.B. 0901), dann weicht bei 0901, 0801 und Jan oder Feb als Monat der Wochentag systematisch um 4 statt um 3 Tage ab. Da hab ich jetzt nix mehr dran gemacht, obwohl es möglich wäre. Ich könnte theoretisch auch Wochentage vor dem Jahr Null berücksichtigen, aber eigentlich hat mich sowas interessiert wie "an welchem Wochentag ist dieses Jahr Weihnachten", "an welchem Wochentag hat meine Frau Geburtstag" oder auch "an welchem Wochentag fiel die Berliner Mauer". Das Jahr 1000 als vierstellige Grenze reicht mir.


    Bitte findet anbei die gefixte Version mit Quellcode als Text. Wenn ich Zeit finde, baue ich die Änderung in Jeeks Code ein, bzw. wir versuchen es mal parallel und schauen, was hinterher schöner aussieht. :P


    Dierch-Jentz


    Vielen Dank für Deine Einsendung. Leider funktioniert das Programm nicht richtig. Ich habe die Daten 01.01.2001 und 31.01.2020 abgefragt und sie waren beide falsch. Wahrscheinlich funktionieren aber die 1980er und 1990er Jahre problemlos. :D


    P.S.:

    Das Zeitumstellungsprogramm funktioniert soweit ich überblicken kann immer richtig, da der hier gefixte Sonderfall bei der Zeitumstellungsberechnung nie eintritt. Betroffen sind davon ja die Monate März und Oktober, Januar und Februar kommen darin nicht vor, daher kommt es auch bei Jahren wie 2001, 1901, zu richtigen Werten.

  • Da ich Beitrag #5 nicht mehr editieren kann, ersatzweise ein Hinweis:


    In Zeile 67 hat sich ein Bug eingeschlichen, es heißt nicht


    67 z=val(yt$):n=1000:gosub 100


    sondern


    67 z=val(yt$):n=100:gosub 100


    n muss 100 sein, sonst kann ich nicht auf 1901 oder 1801 abfragen. Klappen tut so nur 2001.


    Ich habe aktuell keine Möglichkeit, ein PRG zu generieren, ich poste den korrekten Quellcode hier als Text.

  • Ich hab mal in der GO64 ein Programm für den "Ewigen Kalender" als Beispiel für strukturiertes Programmieren in mehreren Folgen entwickelt. Wie ihr am Screenshot seht, berechnet es das Geburtsdatum von Dierch-Jentz korrekt. Es beruhte nicht auf einer einzigen Rechenvorschrift, sondern zog Tabellen zuhilfe (die dienten eigentlich zur Berechnung des Osterdatums). Allerdings berücksichtigt das Programm auch die Einführung unseres Kalenders (erst im Jahre 1582) und kann alle Daten vorher im bis dahin verwendeten julianischen Kalender anzeigen. Und es berechnet die Anzahl Tage, die zwischen zwei Daten liegen (das geht mit der Zahl oben im Kopf des Kalenders). Hier der Screenshot:



    Für die Darstellung wird ein eigener Zeichensatz aktiviert.


    Arndt


    (Edit: Falsches Datum eingegeben)

  • man sollte auch auf Tabellen zugreifen?

    Die Tabellen funktionieren halt, da kommen eben nie Rundungen und sowas vor. Eine kompakte Rechenvorschrift hatte ich damals aber gar nicht erst angeschaut. (Ich war so fasziniert von den Tabellen! Die hatte ich aus irgendeinem alten Buch, weiß nicht mehr, welches.) :-)


    Arndt


    Edit: Der Kurs in der GO lief so um die Jahrtausendwende, meine ich...

  • Danke für die interessanten Beiträge.


    Ich habe schon wieder einen Flüchtigkeitsfehler drin gehabt. In Posting #6 passt zwar der Wert n=100, aber in der Formel drüber steht noch 2,64 statt 2,61. Klar rechnet er den Geburtstag von Dierch-Jentz dann falsch.

    Jetzt passt es. Den Code packe ich gelegentlich in das von Jeek optimierte Format.

  • Gefällt mir sehr gut. Für meine Projektdokumentation hab ich das erst jetzt fertig "aufgearbeitet". :D
    Dabei hab ich mir nur erlaubt es BASIC-technisch auch noch etwas zu überarbeiten (die Reihenabfragen waren mir zu unelegant, auf Formel oder Array ausgelagert).

    Das Ergebnis ist nun nicht mehr explizit der Variable WT$ zugewiesen, sondern kann per Tabelle gleich mit WT$(X0) ermittelt werden (mit nummerischem Wochentag als Index im Bereich von 0 bis 6).

    Auch die Abfrage auf gültige Werte erfolgt gleich bei der Eingabe. Die Abfrage später während der Auswertung hab ich aber gelassen (falls man die Routine in einem anderen Kontext verwenden sollte).


    wota-4.prg

    wota-4.bas.txt