Kalender / Anahl der Arbeitstage für 5/6-Tage woche

Sonstiges (nicht kategorisierbar)

Moderator: Moderatoren

Antworten
kuhno
UDF-Programmierer
UDF-Programmierer
Beiträge: 54
Registriert: Sa, 07. Jan 2006 17:30
Wohnort: Braunschweig
Kontaktdaten:

Kalender / Anahl der Arbeitstage für 5/6-Tage woche

Beitrag von kuhno »

Hallo zusammen,

für eine Auswertung benötige ich die Anzahl der Arbeitstage und die Zahl der Wochenfeiertage im Monat.

Beispiel : November hat 30 Tage, 26 Arbeitstage bei 6-Tage-Woche und keinen allemeingültige Wochenfeiertag.

Im Moment behlfe ich mir, dass ich eine Tabelle mit diesen Daten per Hand eingebe. Nun möchte ich das gern automatich machen. In den Tools III habe ich nix darüber gefunden. Gibt es sowas oder muss ich mir darüber Gedanken und ein Programm machen?

Gruß
Manfred
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16502
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Manfred,
Du wirst keine Möglichkeit haben, als das von Hand zu machen!
Natürlich kannst Du die Tage des Monats durch 7 teilen, die Zahl als Ganzzahl mit 6 multiplizieren, und dann hast Du schon mal die "ganzen" Wochen.
Effektiver wäre es sicherlich, die Anzahl der einzelnen Sonntage zu ermitteln und von der Zahl der Tage des Monats abzuziehen.
Damit hast Du jedoch die Feiertage nicht berücksichtigt.
Die musst Du selber pflegen!
Es gibt die festen Feiertage - die sind einfach!
Der Rest ist eigentlich immer bezogen auf Ostern - und der Termin ist variabel und in jedem Jahr anders. Dies muss man berechnen und dann davon ausgehend die variablen Feiertage berücksichtigen.
Problematisch wird es nur mit den "regionalen" Feiertagen, die nur in bestimmten Regionen gelten - da wirst Du also nicht umhin kommen, dies in einer Datei zu pflegen und anzupassen!

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16502
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hier mal einige links:
Feiertag in Deutschland (auch bewegliche)
Berechnung Ostern

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Kalender / Anahl der Arbeitstage für 5/6-Tage woche

Beitrag von AUGE_OHR »

hi,
kuhno hat geschrieben: Beispiel : November hat 30 Tage, 26 Arbeitstage bei 6-Tage-Woche und keinen allemeingültige Wochenfeiertag.
woher weiss das Programm das der November 30 Tage hat ? :)

ich fange jeweils mit dem 1st des Monats an und sehe mir an was für
ein Wochentag es ist.

Code: Alles auswählen

cMonat := STRZERO(nMonat,2)
dFDOM := CTOD( "01." + cMonat + "." + cJAHR ) // FistDayOfMonth
nDay := DOW( dFDOM )
damit kann ich schon mal die Tage bis zum nächsten Sonntag ausrechnen

nun zähle ich 1 Monat dazu - 1 Tag. (Jahrewechsel wenn Monat > 12)

Code: Alles auswählen

IF nMonat = 12
...
ENDIF
cMonat := STRZERO(nMonat+1,2)
dLDOM := CTOD( "01." + cMonat + "." + cJAHR ) // LastDayOfMonth
dLDOM := dLDOM -1
nDay := DOW( dLDOM )
nDPM := VAL(SUBSTR(DTOS(dLOM),7,2)) // DayPerMonth
Damit stehe ich also auf dem letzten Tag des Monat und brauche mir
auch keine Gedanken über Schaltjahre zu machen.

gruss by OHR
Jimmy
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14641
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 87 Mal
Kontaktdaten:

Beitrag von Jan »

Ich hab ein Clipperprogramm zur exakten Berechnung von Ostern. Wenn jemand den Code benötigte: Nachricht an mich.

Und wie Martin schon sagt: Ein guter Teil der religiösen Feiertage hängt an dieser Berechnung (wie Pfingsten = Ostern + 50 Tage). Aber Datumsberechnungen sind ja nun einmal eine große Stärke von Xbase++

Jan
Benutzeravatar
Koverhage
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2470
Registriert: Fr, 23. Dez 2005 8:00
Wohnort: Aalen
Hat sich bedankt: 102 Mal
Danksagung erhalten: 3 Mal
Kontaktdaten:

Beitrag von Koverhage »

Jimmy,

wie viele Tage ein Monat hat ist doch relativ einfach zu ermitteln:

nTage := day(ctod("01.12.2007")-1)

Für die allgemein gültigen Feiertage, hier müsste man die speziellen der einzelnen Bundesländer noch hinzufügen und das jeweilige Bundesland als Parameter übergeben

static function ist_Feiertag(dPruefDat)
local pnJahr := year(dPruefDat)
local cJahr := str(pnJahr,4)
local nAktTag := day(dPruefDat)
local nAktMon := month(dPruefDat)
local lRetCode := .f.
* Ostern:
local ostern := ctod(oster_berech(pnJahr)+cJahr)
* Buß- und Bettag
local nBBTag := dow(ctod("24.12."+cJahr)) - 1
local dBBDatum := ctod("31.12."+cJahr) - 39 - nBBTag

do case
case nAktTag = 1 .and. nAktMon = 1 // Neujahr
lRetCode := .t.
case nAktTag = 6 .and. nAktMon = 1 // Heilige Drei Könige
lRetCode := .t.
case nAktTag = 1 .and. nAktMon = 5 // Maifeiertag
lRetCode := .t.
case nAktTag = 15 .and. nAktMon = 8 // Maria Himmelfahrt
lRetCode := .t.
case nAktTag = 3 .and. nAktMon = 10 // Tag der deutschen Einheit
lRetCode := .t.
case nAktTag = 1 .and. nAktMon = 11 // Allerheiligen
lRetCode := .t.
case nAktTag = 25 .and. nAktMon = 12 // 1. Weihnachtsfeiertag
lRetCode := .t.
case nAktTag = 26 .and. nAktMon = 12 // 2. Weihnachtsfeiertag
lRetCode := .t.
case ostern-2 = dPruefdat // Karfreitag
lRetCode := .t.
case ostern = dPruefdat // Ostersonntag
lRetCode := .t.
case ostern+1 = dPruefdat // Ostermontag
lRetCode := .t.
case ostern+49 = dPruefdat // Pfingstsonntag
lRetCode := .t.
case ostern+50 = dPruefdat // Pfingstmontag
lRetCode := .t.
case ostern+39 = dPruefdat // Himmelfahrt
lRetCode := .t.
case ostern+60 = dPruefdat // Fronleichnam
lRetCode := .t.
endcase
return lRetCode
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14641
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 87 Mal
Kontaktdaten:

Beitrag von Jan »

Ich hab gerade den Code für Ostern rausgesucht. Ist nicht viel, also pack ich das mal direkt hier rein.

Ostern (gültig erst ab 1582)

Code: Alles auswählen

FUNCTION feiertag(nJahr)
LOCAL nGold, nJahrhundert, nCorx, nCorz, nSonntag, nEpakte, nMond, nMonat := 0, nTag := 0
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 "kalendarischr" 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))
Buß- und Bettag:

Code: Alles auswählen

FUNCTION busstag(nAktjahr)
LOCAL busstag := CTOD("25.12." + ALLTRIM(STR(nAktjahr))), tag := 7
DO WHILE tag <> 1
   busstag --
   tag := DOW(busstag)
ENDDO
RETURN busstag - 35 - 4
Un der Muttertag. ist zwar sowieso ein Sonntag, aber wenn wir gerade mal dabei siend...

Code: Alles auswählen

FUNCTION muttertag(nAktjahr)
LOCAL muttertag := CTOD("30.04." + ALLTRIM(STR(nAktjahr))), tag := 7
DO WHILE tag <> 1
   muttertag ++
   tag := DOW(muttertag)
ENDDO
RETURN muttertag + 7
Und ein paar Feiertage:

Code: Alles auswählen

Epiphanis            "06.01."  // Hlg. 3 Könige
Quinquagesima        DTOC(feiertag(aktjahr) - 50)  // 50 Tage vor Ostern
Septuagesima         DTOC(feiertag(aktjahr) - 63)  // 9 Sonntage vor Ostern
Quadragesima         DTOC(feiertag(aktjahr) - 40)  // 40 Tage vor Ostern
Sexagesima           DTOC(feiertag(aktjahr) - 56)  // 8 Sonntage vor Ostern
Estomihi             DTOC(feiertag(aktjahr) - 49)  // 7 Sonntage vor Ostern
Invocavit            DTOC(feiertag(aktjahr) - 42)  // 6 Sonntage vor Ostern
Reminiscere          DTOC(feiertag(aktjahr) - 35)  // 5 Sonntage vor Ostern
Oculi                DTOC(feiertag(aktjahr) - 28)  // 4 Sonntage vor Ostern
Laetare              DTOC(feiertag(aktjahr) - 21)  // 3 Sonntage vor Ostern
Judica               DTOC(feiertag(aktjahr) - 14)  // 2 Sonntage vor Ostern
Palmsonntag/Palmarum DTOC(feiertag(aktjahr) - 7)   // 1 Sonntag vor Ostern
Gründonnerstag       DTOC(feiertag(aktjahr) - 4)   // Donnerstag vor Ostern
Karfreitag           DTOC(feiertag(aktjahr) - 3)   // Freitag vor Ostern
Ostersonntag         DTOC(feiertag(aktjahr))
Quasimodogeniti      DTOC(feiertag(aktjahr) + 7)   // 1 Sonntag nach Ostern
Misericordias Domini DTOC(feiertag(aktjahr) + 14)  // 2 Sonntage nach Ostern
Jubilate             DTOC(feiertag(aktjahr) + 21)  // 3 Sonntage nach Ostern
Cantate              DTOC(feiertag(aktjahr) + 28 )  // 4 Sonntage nach Ostern
Rogate               DTOC(feiertag(aktjahr) + 35)  // 5 Sonntage nach Ostern
Muttertag            IIF(aktjahr >= 1907, ;        // 2 Sonntag im Mai
                         DTOC(muttertag(aktjahr)), ;
                         " ab 1907")
Himmelfahrt          DTOC(feiertag(aktjahr) + 39)  // 40 Tage nach Ostern
Exaudi               DTOC(feiertag(aktjahr) + 42)  // 6 Sonntage nach Ostern
Pfingstsonntag       DTOC(feiertag(aktjahr) + 49)  // 50 Tage nach Ostern
Trinitatis           DTOC(feiertag(aktjahr) + 56)  // 1 Sonntag nach Pfingsten
Fronleichnam         DTOC(feiertag(aktjahr) + 60)  // 2 Donnerstage nach Pfingsten
Buß- und Bettag      DTOC(busstag(aktjahr))        //
Totensonntag         DTOC(busstag(aktjahr) + 4)    // Sonntag nach Bußtag
Jan

Nachtrag: Hatte den Buß- und Bettag vergessen. Und dann auch noch den Muttertag.
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Beitrag von AUGE_OHR »

hi,
Koverhage hat geschrieben: wie viele Tage ein Monat hat ist doch relativ einfach zu ermitteln:
nTage := day(ctod("01.12.2007")-1)
sag ich doch +1 Monat -1 Tag.

Wo jetzt ja die berechnungen bekannt sind, wäre die Frage wie ihr
einen solchen Kalendar darstellt ?

gruss by OHR
Jimmy
kuhno
UDF-Programmierer
UDF-Programmierer
Beiträge: 54
Registriert: Sa, 07. Jan 2006 17:30
Wohnort: Braunschweig
Kontaktdaten:

Beitrag von kuhno »

Hallo zusammen,

danke für alle Vorschläge, aber da werde ich bei dem Vorschlag von Martin bleiben, zumal das ganze ja nur einmal im Jahr aktualisiert werden muss.

Gruß

Manfred
Wonderer
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 107
Registriert: Do, 06. Jul 2006 13:24

Re: Kalender / Anahl der Arbeitstage für 5/6-Tage woche

Beitrag von Wonderer »

danke schon mal für die Vorarbeit mit diesem Thread, jetzt bin ich allerdings etwas verwundert ob mein Code auch wirklich so korrekt ist.

ohne Betrachtung der Feiertage habe ich folgendes:

Code: Alles auswählen

function getCountWorkdays( dDateFrom, dDateTo )		// Anzahl der Werktage bis ZielDatum
local	aWeekdays := { "Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag","Sonntag" }, ;
		nWeekdayNo := 1, ;
		nWorkdays, ;
	    nRefDay    := 5, ;
	    nDifDays, nDiv, nDivInt, ;
	    bDebug := .f.

    // Position des Start-Datums in der Woche (Offset)
    nWeekdayNo := AScan( aWeekdays, CDow( dDateFrom ) )

	// Anzahl der Tage von-bis (inklusive Start-/Endtag)
    nDifDays := dDateTo - dDateFrom + 1

	// Offset einrechnen
    nDifDays += (nWeekdayNo-1)
    // Anzahl der Wochen ermitteln
    nDiv := nDifDays / 7
    nDivInt := int(nDiv)

    // Werktage berechnen (Rechung mit 2Tagen pro Woche kein Werktag)
    nWorkdays := nDifDays - (nWeekdayNo-1) - (nDivInt*2)

return nWorkdays
Jetzt habe ich dann noch die Gauß-Formel versucht analog eines VB-Codes zu schreiben.
Auch da bin ich mir jetzt nicht sicher ob das so stimmt (wegen dem Casten zu Ganzzahl).

Code: Alles auswählen

function getEasterSunday( nYear )
local a, b, c, d, e, f, dDateResult

	if nYear==0
		nYear := Year( Date() )
	endif

	a := int(nYear % 19)
	b := int(nYear / 100)
	c := (8 * b + 13) / 25 -2
	d := int(b - (nYear / 400) - 2)
	e := int((19 * int(nYear % 19) + int((15 - c + d) % 30)) % 30)
	if e==28
		if a>10
			e:=27
		endif
	elseif e==29
		e := 28
	endif
	f := int((d + 6 * e + 2 * int(nYear % 4) + 4 * int(nYear % 7) + 6) % 7)

	dDateResult := CtoD( "1.3."+ltrim(str(nYear)) )
	dDateResult += (e + f + 22 - 1)

return dDateResult
Anhand dieses Datums kann ich dann die restlichen Feiertage einbeziehen mit:

Code: Alles auswählen

if dDateFrom<=dHoliday .and. dDateTo>=dHoliday
  nWorkdays--
endif
Quelle VB-GaußFormel: https://msdn.microsoft.com/de-de/library/bb979477.aspx

Wie schon gesagt bin ich mir nicht sicher wegen dem Casten zu Int.
Ich nehme an ohne die Konvertierung bekomme ich nicht die gleichen Werte da im VB alles Datentyp Long ist?

Danke schon mal falls ihr dafür etwas Zeit habt...
Antworten