Seite 1 von 1

Osterfunktion mit Jahr als Parameter

Verfasst: Do, 05. Jan 2023 13:40
von UliTs
Hallo allerseits,

bestimmt hat schon jemand so etwas (ähnliches) programmiert. Ostern (und diverse andere kirchliche Feiertage, ist der Abstand zu Ostern immer gleich?) hat jedes Jahr ein anderes Datum. Ich könnte eine Funktion, die das Datum in Abhängigkeit vom Jahr als Rückgabewert hat gut brauchen:

Code: Alles auswählen

function OsterSonntag( pJahr )
local dDatum
...
return( dDatum )
Dabei würde es in meinem Fall reichen, wenn die Funktion in diesem Jahrhundert einwandfrei funktioniert.
Hat jemand so etwas schon geschrieben und könnte es hier veröffentlichen oder alternativ mir per PN zur Verfügung stellen?

Vielleicht Jan?

Edit:
Habe gerade im Delphiforum eine ganz gute Seite gefunden, mit der man es (vermutlich innerhalb weniger Minuten) selbst programmieren kann: http://www.arndt-bruenner.de/mathe/scripts/osterdatum.htm
Uli

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Do, 05. Jan 2023 13:47
von Tom
Keine Ahnung, wo ich diesen steinalten, aber nach wie vor funktionierenden Code herhabe. Man ruft die Funktion mit allen Tagesdaten vom Beginn bis zum Ende des Jahres auf. Feste Feiertage sind ja einfach. Ostern hat irgendwas mit den Mondphasen und so zu tun. 8)

Code: Alles auswählen

FUNCTION BeweglicheFeiertage(ft_datum)
LOCAL ft_jahr := Year(ft_datum), ft_k1, ft_k2, ft_k3, ft_k4, ft_tt, ft_mm, ft_text := ''

        ft_k1:=INT(ft_jahr/100)-INT(ft_jahr/400)+4
        ft_k2:=ft_k1-INT(ft_jahr/300)+11
        ft_k3:=MOD(MOD(ft_jahr,19)*19+ft_k2,30)
        ft_k4:=MOD(MOD(ft_jahr,4)*2+(4*ft_jahr)+(6*ft_k3)+ft_k1,7)+ft_k3-9
        IF ft_k4<1
                ft_tt:=31+ft_k4
                ft_mm:=3
        ELSE
                IF((ft_k4==26) .OR. ((ft_k3==28) .AND. (ft_k4==25) .AND. ;
                   (11*MOD(ft_k2+1,30)<19)))
                   ft_k4:=ft_k4-7
                ENDIF
                ft_tt:=ft_k4
                ft_mm:=4
        ENDIF

        ft_ostern:=     CTOD(STR(ft_tt,2,0)+"."+STR(ft_mm,2,0)+"."+ ;
                                        RIGHT(STR(YEAR(ft_datum)),4))
        IF ft_datum==ft_ostern-2
                ft_text:="Karfreitag"
        ELSEIF ft_datum==ft_ostern
                ft_text:="Ostersonntag"
        ELSEIF ft_datum==ft_ostern+1
                ft_text:="Ostermontag"
        ELSEIF ft_datum==ft_ostern+49
                ft_text:="Pfingstsonntag"
        ELSEIF ft_datum==ft_ostern+50
                ft_text:="Pfingstmontag"
        ELSEIF ft_datum==ft_ostern+39
                ft_text:="Christi Himmelfahrt"
        ELSEIF ft_datum==ft_ostern+60
                ft_text:="Fronleichnam"
        ENDIF
RETURN ft_text

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Do, 05. Jan 2023 13:49
von Tom
Siehe auch hier: https://www.xbaseforum.de/viewtopic.php?p=54946#p54946
Da wird der Rest ebenfalls erklärt. Bisschen runterscrollen.

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Do, 05. Jan 2023 13:50
von Jan
Hallo Uli,

öhm ... wie kommst Du denn jetzt ausgerechnt auf mich?

Aber Du hast recht - ich habe genau diese Funktion. Ergänzt um diverse andere Funktionen, die einen ganzen Schwung Feiertage brechnen. Die sind ja teilweise fixe Tage, teilweise abhängig von Ostern, oder teilweise nach festen Rgeln (wie letzter Donnerstag im Oktober, was jetzt fiktiv ist).

Code: Alles auswählen

FUNCTION feiertag(nJahr, lGregorianisch)

LOCAL nGold        := 0
LOCAL nJahrhundert := 0
LOCAL nCorx        := 0
LOCAL nCorz        := 0
LOCAL nSonntag     := 0
LOCAL nEpakte      := 0
LOCAL nMond        := 0
LOCAL nMonat       := 0
LOCAL nTag         := 0

UnUsed(lGregorianisch)

nJahr := Val(Var2Char(nJahr))

IF nJahr > 1582
   * <<nGold>> ist die Goldene Nummer des Jahres im 19 Jahres Metonic Zyklus
   nGold := nJahr % 19 + 1
   * <<nJahrhundert>> Jahrhundert
   nJahrhundert := INT (nJahr / 100) + 1
   * Korrektur:
   * <<nCorx>> ist die Anzahl der Jahre in denen Schaltjahre aufgehoben werden um mit der Sonne konform zu bleiben
   nCorx := Int((3 * nJahrhundert) / 4 - 12)
   * <<nCorz>> ist eine spezielle Korrektur um Ostern mit dem Mondumlauf zu synchronisieren
   nCorz := Int((8 * nJahrhundert + 5) / 25 - 5)
   * <<nSonntag>> Sonntag finden
   nSonntag := Int((5 * nJahr) / 4 - nCorx - 10)
   * Epakte <<nEpakte>> finden (Erscheinen des Vollmondes spezifizieren)
   nEpakte = Int((11 * nGold + 20 + nCorz - nCorx) % 30)
   IF nEpakte < 0
      nEpakte += 30
   ENDIF
   IF ((nEpakte = 25) .AND. (nGold > 11)) .OR. (nEpakte = 24)
      ++nEpakte
   ENDIF
   * Vollmond finden - der <<nMond>>te des März ist ein "kalendarischer" Vollmond
   nMond := 44 - nEpakte
   IF nMond < 21
      nMond += 30
   ENDIF
   * Zum Sonntag
   nMond := Int(nMond + 7 - ((nSonntag + nMond) % 7))
   * Monat und Tag erhalten
   IF nMond > 31
      nMonat := 4
      nTag = nMond - 31

    ELSE
      nMonat := 3
      nTag := nMond
   ENDIF
ENDIF

RETURN CToD(Right("00" + LTrim(Str(Int(nTag))), 2) + "." + ;
            Right("00" + LTrim(Str(nMonat)), 2) + "." + ;
            Str(nJahr, 4))

Jan

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Do, 05. Jan 2023 14:51
von Marcus Herz
Es gibt da eine Formel von gauss. Bin nächste Woche wieder im Büro. Dann kann ich die reinstellen. Hab's als xbase Code und SQL Funktion

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Do, 05. Jan 2023 14:57
von Jan
Marcus,

wenn ich mich recht erinnere ist mein Code nach Gauss (ist schon ewig her das ich die gebaut hatte, so genau weiß ich das nicht mehr)

Jan

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Mo, 09. Jan 2023 10:28
von Marcus Herz
Witzig:
Es gibt tatsächlich mehrere Versionen der Gausschen Formel. Jans Version bezieht sich auf die 2. Erweiterung, meine auf das Original. Beide kommen aber zum selben Ergebnis.

Hier noch die SQL Funktion für ADS:

Code: Alles auswählen

CREATE FUNCTION Ostern
   (
   jahr INTEGER
   )
   RETURNS DATE
BEGIN
  declare @x integer;
  declare @d integer;
  declare @e integer;
  declare @off1 integer;
  declare @off2 integer;
  declare @monat integer;

  @Off1 = 0;
  @Off2 = 0;

  @x = jahr / 100 - 16;

  if @x = 1 then
    @Off1 = 22;
    @Off2 = 2;
  elseif @x = 2 then
    @Off1 = 23;
    @Off2 = 3;
  elseif @x = 3 then
    @Off1 = 23;
    @Off2 = 4;
  elseif @x = 4 or @x = 5 then
    @Off1 = 24;
    @Off2 = 5;
  elseif @x = 6 then
    @Off1 = 24;
    @Off2 = 6;
  elseif @x = 7 then
    @Off1 = 25;
  end if;

  @d = ((19 * (jahr % 19) + @off1) % 30);
  @e = ((2 * (jahr % 4) + 4 * (jahr % 7) + 6 * @d + @off2) % 7);
  @off1 = @d + @e;

  if  @off1 < 10  then
    @off1 = @off1 + 22;
    @Monat  = 3;
  else
    @Monat  = 4;
    @off1   = @off1 - 9;
    if @off1 = 26 then
      @off1  = 19;

    elseif ( @off1 = 25 and @d = 28 and  @e = 6 and (jahr % 19) = 10 ) then
      @off1  = 18;
    end if;
  end if;
RETURN cast(CREATETIMESTAMP( jahr, @monat, @off1, 12,0,0,0 ) AS SQL_DATE);

END;

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Mo, 09. Jan 2023 10:31
von Jan
Hallo Marcus,

mit den beiden Erweiterungen hatte Carl Friedrich Gauß ja mehr oder weniger seltene Ausnahmen mit eingebaut. Ob die wirklich jeder braucht sei mal dahin gestellt. Aber ich brauche die unbedingt.

Jan

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Mo, 09. Jan 2023 11:40
von Tom
Die Formel ist in die Funktion eingearbeitet, die ich weiter oben gepostet habe. https://www.xbaseforum.de/viewtopic.php ... 32#p143632

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Mo, 09. Jan 2023 11:56
von UliTs
Dann hier auch noch die Delphi-Version, die ich aus Euren Lösungen geschrieben habe :) .

Code: Alles auswählen

function OsterSonntag( nJahr: integer ): TDate;
var k1,k2,k3,k4,nTag,nMonat: integer;
var dOsterSonntag: TDate;
begin
  k1 := (nJahr div 100) - (nJahr div 400) + 4;
  k2 := k1 - (nJahr div 300) + 11;
  k3 := (( nJahr mod 19 ) * 19 + k2) mod 30;
  k4 := (( (nJahr mod 4) * 2 + (4*nJahr) + (6*k3) + k1 ) mod 7) + k3 - 9;

  if k4<1 then begin
    nTag   := 31 + k4;
    nMonat := 3;
  end else begin
    if (k4=26) or ((k3=28) and (k4=25) and ((11 * (k2+1 mod 30)) < 19)) then begin
      k4 := k4 - 7;
    end;
    nTag   := k4;
    nMonat := 4;
  end;
  dOsterSonntag := EncodeDate( nJahr,nMonat,nTag );
  Result := dOsterSonntag;
end;

Re: Osterfunktion mit Jahr als Parameter

Verfasst: Do, 12. Jan 2023 16:30
von nightcrawler
In Willingen habe ich diese Funktion (ADS SQL) vorgestellt. Nur zur Vollständigkeit.

Code: Alles auswählen

CREATE FUNCTION jde.Ostersonntag(jahr INTEGER) RETURNS Date 
BEGIN
  DECLARE a INTEGER, b INTEGER, c INTEGER, d INTEGER, e INTEGER, f INTEGER;
  DECLARE ts TIMESTAMP;
  a = Mod(jahr,19);
  b = Jahr/100;
  c = (8*b+13)/25-2;
  d = b-(Jahr/400)-2;
  e = MOD(19*a+MOD(15-c+d,30),30);
  IF e=28 THEN
    IF a>10 THEN
      e=27;
    END;
  ELSEIF e=29 THEN
    e=28;
  END;
  f = MOD(d+6*e+2*MOD(jahr,4)+4*MOD(jahr,7)+6,7);
  ts = CREATETIMESTAMP(jahr,3,1,0,0,0,0);
  ts = TIMESTAMPADD(SQL_TSI_DAY,e+f+21,ts);  
  RETURN CAST(ts AS SQL_DATE);
END;  
Anwendung:

Code: Alles auswählen

SELECT jde.Ostersonntag(2017) FROM SYSTEM.IOTA;