letzter Tag im Monat / letzter Werktag im Monat

Anfängerfragen zum Programmieren mit PureBasic.
AddMe
Beiträge: 46
Registriert: 04.05.2009 23:24

letzter Tag im Monat / letzter Werktag im Monat

Beitrag von AddMe »

Hallo Zusammen,

leider habe ich folgendes Problem:

ich weis nicht, wie ich es anstellen kann, eine Funktion zu schreiben,
die mir den letzten Tag des Monats, wenn ich nur den Monat und das Jahr angebe errechnet.

Das gleiche gilt für den letzten Werktag im Monat, jedoch müsste ich dazu noch berücksichtigen, ob der letzte Werktag auf einen Feiertag fällt.

Diesen Code habe ich VB genutzt. Krieg es in PB einfach nicht hin. Besonders, was die Feiertage angeht.

Code: Alles auswählen

Option Explicit

Sub letzten_Werktag_ermitteln()
'letzten Werktag im Monat ermitteln
Dim d As Date
Dim i As Long

d = Now

'letzte Tag im Monat
d = DateSerial(Year(d), Month(d) + 1, 0)

For i = 1 To 3
   'prüfen ob letzte Tag im Monat Sa/So
    If Weekday(d) = 1 Or Weekday(d) = 7 Then
       'wenn ja, ein Tag davor
        d = DateSerial(Year(d), Month(d) + 1, 0) - i
    Else
        Exit For
    End If
Next i
Wäre toll, wenn mir jemand helfen könnte

Gruß
Michael
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

der Code den du da hast benutzt eine spezifische Funktion von VB, die in PB nicht existiert.
da musst du dir selber was basteln.

zum Beispiel: ersten tag des Folgemonats nehmen, in einen Date-Wert umrechnen, eine Stunde abziehen, und zurück parsen.

Code: Alles auswählen

OpenConsole()

Repeat
PrintN("")
 Print("Jahr: ")
 Y$ = Input()
 Y = Val( Y$ )
 If Y < 1974 Or Y > 2033
  Y = 0
 EndIf
Until Y > 0

Repeat
PrintN("")
 Print("Monat: ")
 M$ = Input()
 M = Val( M$ )
 If M < 1 Or M > 12
  M = 0
 EndIf
Until M > 0

M + 1
If M > 12
  M = 1
  Y + 1
EndIf

Y$ = RSet( Str( Y ), 4, "0" )
M$ = RSet( Str( M ), 2, "0" )

Date$ = Y$ + "/" + M$ + "/" + "01"
PrintN("")
PrintN( "Erster Tag des Folgemonats:" + Date$ )
PrintN("")

DateVal = ParseDate( "%yyyy/%mm/%dd", Date$ )

DateVal - 3600   ; eine Stunde abziehen

PrintN("Letzter Tag des Monats:")
PrintN( Str(Year(DateVal)) +"/"+ Str(Month(DateVal)) +"/"+ Str(Day(DateVal)))
PrintN("")


Input()
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
AddMe
Beiträge: 46
Registriert: 04.05.2009 23:24

Beitrag von AddMe »

Hallo Kaeru Gaman,
Kaeru Gaman hat geschrieben:der Code den du da hast benutzt eine spezifische Funktion von VB, die in PB nicht existiert.
da musst du dir selber was basteln.
vielen Dank für Deine Antwort. Echt klasse. :allright:
Genau diese Funktion hatte ich in PB gesucht, nur nicht gefunden. Ich dachte, dass ich nur nicht nach dem richtigen Namen gesucht habe.

Das herausfindes des Werktages ist damit kein Problem mehr.

Hättest Du noch eine Idee, wie ich herausfinde ob dieser Letzte Werktag ein Feiertag ist?

Ich hatte hierzu auch wiederum eine Funktion. Mir fällt es halt einfach nur noch ziemlich schwer das in PB umzusetzen.

Code: Alles auswählen

Option Explicit
'// ----------------------------------------------------------------
'// Feiertagsberechnung nach dem Algorithmus von Carl Friedrich Gauß
'// ----------------------------------------------------------------
Type DtFeiertage
     Jahreszahl         As Long
     Ostern             As Date
     Neujahr            As Date
     DreiKoenige        As Date
     Rosenmontag        As Date
     Aschermittwoch     As Date
     Karfreitag         As Date
     Ostersonntag       As Date
     Ostermontag        As Date
     Maifeiertag        As Date
     ChrHimmelfahrt     As Date
     Pfingstsonntag     As Date
     Pfingstmontag      As Date
     Fronleichnam       As Date
     MariaeHimmelfahrt  As Date
     DtEinheit          As Date
     Reformationstag    As Date
     Allerheiligen      As Date
     Heiligabend        As Date
     Weihnachten1       As Date
     Weihnachten2       As Date
     Sylvester          As Date
End Type
 
Dim m_uDTF As DtFeiertage
 
Sub Beispiel()
 
    Call BerechneFeiertage(Year(Now))
    Debug.Print "Die Feiertage für   "; Year(Now); vbCrLf
    Debug.Print "Neujahr             "; Format(m_uDTF.Neujahr, "Long Date")
    Debug.Print "Hl. Drei Könige     "; Format(m_uDTF.DreiKoenige, "Long Date")
    Debug.Print "Rosenmontag         "; Format(m_uDTF.Rosenmontag, "Long Date")
    Debug.Print "Aschermittwoch      "; Format(m_uDTF.Aschermittwoch, "Long Date")
    Debug.Print "Karfreitag          "; Format(m_uDTF.Karfreitag, "Long Date")
    Debug.Print "Ostersonntag        "; Format(m_uDTF.Ostersonntag, "Long Date")
    Debug.Print "Ostermontag         "; Format(m_uDTF.Ostermontag, "Long Date")
    Debug.Print "Maifeiertag         "; Format(m_uDTF.Maifeiertag, "Long Date")
    Debug.Print "Christi Himmelfahrt "; Format(m_uDTF.ChrHimmelfahrt, "Long Date")
    Debug.Print "Pfingstsonntag      "; Format(m_uDTF.Pfingstsonntag, "Long Date")
    Debug.Print "Pfingstmontag       "; Format(m_uDTF.Pfingstmontag, "Long Date")
    Debug.Print "Fronleichnam        "; Format(m_uDTF.Fronleichnam, "Long Date")
    Debug.Print "Mariä Himmelfahrt   "; Format(m_uDTF.MariaeHimmelfahrt, "Long Date")
    Debug.Print "Tag der dt. Einheit "; Format(m_uDTF.DtEinheit, "Long Date")
    Debug.Print "Reformationstag     "; Format(m_uDTF.Reformationstag, "Long Date")
    Debug.Print "Allerheiligen       "; Format(m_uDTF.Allerheiligen, "Long Date")
    Debug.Print "Heiligabend         "; Format(m_uDTF.Heiligabend, "Long Date")
    Debug.Print "Weihnachten1        "; Format(m_uDTF.Weihnachten1, "Long Date")
    Debug.Print "Weihnachten2        "; Format(m_uDTF.Weihnachten2, "Long Date")
    Debug.Print "Sylvester           "; Format(m_uDTF.Sylvester, "Long Date")
'// ----------------------------------------------------------------
'// Ausgabe:
'// ----------------------------------------------------------------
'// Neujahr             Mittwoch, 1. Januar 2003
'// Hl. Drei Könige     Montag, 6. Januar 2003
'// Rosenmontag         Montag, 3. März 2003
'// Aschermittwoch      Mittwoch, 5. März 2003
'// Karfreitag          Freitag, 18. April 2003
'// Ostersonntag        Sonntag, 20. April 2003
'// Ostermontag         Montag, 21. April 2003
'// Maifeiertag         Donnerstag, 1. Mai 2003
'// Christi Himmelfahrt Donnerstag, 29. Mai 2003
'// Pfingstsonntag      Sonntag, 8. Juni 2003
'// Pfingstmontag       Montag, 9. Juni 2003
'// Fronleichnam        Donnerstag, 19. Juni 2003
'// Mariä Himmelfahrt   Freitag, 15. August 2003
'// Tag der dt. Einheit Freitag, 3. Oktober 2003
'// Reformationstag     Freitag, 31. Oktober 2003
'// Allerheiligen       Samstag, 1. November 2003
'// Heiligabend         Mittwoch, 24. Dezember 2003
'// Weihnachten1        Donnerstag, 25. Dezember 2003
'// Weihnachten2        Freitag, 26. Dezember 2003
'// Sylvester           Mittwoch, 31. Dezember 2003
'// ----------------------------------------------------------------
End Sub
 
Sub BerechneFeiertage(Jahreszahl As Integer)
 
'// Als Refrenzdatum zunächst m_uDTF.Ostern berechnen
    If Not Ostern_berechnen(Jahreszahl) Then Exit Sub
 
'// Neujahr setzen (fester Feiertag am 1. Januar)
    m_uDTF.Neujahr = DateSerial(Jahreszahl, 1, 1)
 
'// Hl. Drei Könige setzen (fester Feiertag am 6. Januar)
    m_uDTF.DreiKoenige = DateSerial(Jahreszahl, 1, 6)
 
'// Rosenmontag berechnen (beweglicher Feiertag; 48 Tage vor Ostern)
    m_uDTF.Rosenmontag = m_uDTF.Ostern - 48
 
'// Aschemittwoch berechnen (beweglicher Feiertag; 46 Tage vor Ostern)
    m_uDTF.Aschermittwoch = m_uDTF.Ostern - 46
 
'// Karfreitag berechnen (beweglicher Feiertag; 2 Tage vor Ostern)
    m_uDTF.Karfreitag = m_uDTF.Ostern - 2
 
'// Ostersonntag = m_uDTF.Ostern!
    m_uDTF.Ostersonntag = m_uDTF.Ostern
 
'// Ostermontag berechnen (beweglicher Feiertag; 1 Tag nach Ostern)
    m_uDTF.Ostermontag = m_uDTF.Ostern + 1
 
'// Maifeiertag setzen (fester Feiertag am 1. Mai)
    m_uDTF.Maifeiertag = DateSerial(Jahreszahl, 5, 1)
 
'// Christi Himmelfahrt berechnen (beweglicher Feiertag; 39 Tage nach Ostern)
    m_uDTF.ChrHimmelfahrt = m_uDTF.Ostern + 39
 
'// Pfingstsonntag berechnen (beweglicher Feiertag; 49 Tage nach Ostern)
    m_uDTF.Pfingstsonntag = m_uDTF.Ostern + 49
 
'// Pfingstmontag berechnen (beweglicher Feiertag; 50 Tage nach Ostern)
    m_uDTF.Pfingstmontag = m_uDTF.Ostern + 50
 
'// Fronleichnam berechnen (beweglicher Feiertag; 60 Tage nach Ostern)
    m_uDTF.Fronleichnam = m_uDTF.Ostern + 60
 
'// Mariä Himmelfahrt setzen (fester Feiertag am 15. August)
    m_uDTF.MariaeHimmelfahrt = DateSerial(Jahreszahl, 8, 15)
 
'// Tag der deutschen Einheit setzen (fester Feiertag am 3. Oktober)
    m_uDTF.DtEinheit = DateSerial(Jahreszahl, 10, 3)
 
'// Reformationstag setzen (fester Feiertag am 31. Oktober)
    m_uDTF.Reformationstag = DateSerial(Jahreszahl, 10, 31)
 
'// Allerheiligen setzen (fester Feiertag am 1. November)
    m_uDTF.Allerheiligen = DateSerial(Jahreszahl, 11, 1)
 
'// Heiligabend setzen (fester 'Feiertag' am 24. Dezember)
    m_uDTF.Heiligabend = DateSerial(Jahreszahl, 12, 24)
 
'// Erster Weihnachtstag setzen (fester 'Feiertag' am 25. Dezember)
    m_uDTF.Weihnachten1 = DateSerial(Jahreszahl, 12, 25)
 
'// Zweiter Weihnachtstag setzen (fester 'Feiertag' am 26. Dezember)
    m_uDTF.Weihnachten2 = DateSerial(Jahreszahl, 12, 26)
 
'// Sylvester setzen (fester 'Feiertag' am 31. Dezember)
    m_uDTF.Sylvester = DateSerial(Jahreszahl, 12, 31)
 
End Sub
 
Function Ostern_berechnen(ByVal lYear As Long) As Boolean
 
'// Berechnung mit Hilfe des Algorithmus von Gauß
    On Error GoTo Err_Ostern_berechnen
 
    Dim i1  As Integer
    Dim i2  As Integer
    Dim i3  As Integer
    Dim i4  As Integer
    Dim i5  As Integer
    Dim iTZ As Integer                            '// iTZ = Tageszahl
 
    i1 = lYear Mod 19                             '// Formel nach Gauß
    i2 = lYear Mod 4                              '// Werte für die Jahre
    i3 = lYear Mod 7                              '// 1900 - 2099
 
    i4 = (19 * i1 + 24) Mod 30
    i5 = (2 * i2 + 4 * i3 + 6 * i4 + 5) Mod 7
    iTZ = 22 + i4 + i5                            '// Ermittelt den Tag
    If iTZ > 31 Then                              '// März oder April
        iTZ = iTZ - 31                            '// Wenn April, dann - 31 Tage
        If iTZ = 26 Then iTZ = 19                 '// Wenn 26.4. dann 19.4.
        If (iTZ = 25 And i4 = 28 And i1 > 10) Then iTZ = 18
        m_uDTF.Ostern = DateSerial(lYear, 4, iTZ) '// Ostern im April
    Else
        m_uDTF.Ostern = DateSerial(lYear, 3, iTZ) '// Ostern im Maerz
    End If
    Ostern_berechnen = True
 
Exit_Ostern_berechnen:
    Exit Function
 
Err_Ostern_berechnen:
    Ostern_berechnen = False
    GoTo Exit_Ostern_berechnen
 
End Function

Nochmals vielen Dank für Deine Hilfe

Gruß
Michael[/code]
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Re: letzter Tag im Monat / letzter Werktag im Monat

Beitrag von AND51 »

> letzten Tag des Monats
Das ist einfach. Kann man als Macro realisieren.

> letzten Werktag im Monat
Hab ich auch gemacht, allerdings ohne Berücksichtigung von Feiertagen. War mir auf die Schnelle zu umständlich. Kannst du an der gekennzeichneten Stelle selber einfügen.
Momentan gibt die Prozedur nur den Arbeitstag zurück, d. h. wenn der Tag nicht Samstag oder Sonntag ist.

Code: Alles auswählen

Macro letzterTagImMonat(monat, jahr)
	AddDate(AddDate(Date(jahr, monat, 1, 0, 0, 0), #PB_Date_Month, 1), #PB_Date_Day, -1)
EndMacro

Procedure letzterArbeitstagImMonat(monat, jahr)
	monat=letzterTagImMonat(monat, jahr)
	; Hier Code für Feiertage einfügen
	While DayOfWeek(monat) = 0 Or DayOfWeek(monat) = 6
		monat=AddDate(monat, #PB_Date_Day, -1)
	Wend
	ProcedureReturn monat
EndProcedure

Debug FormatDate("%hh:%ii:%ss %dd.%mm.%yyyy", letzterTagImMonat(5, 2009))
Debug FormatDate("%hh:%ii:%ss %dd.%mm.%yyyy", letzterarbeitstagImMonat(5, 2009))
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Re: letzter Tag im Monat / letzter Werktag im Monat

Beitrag von Kaeru Gaman »

AND51 hat geschrieben:

Code: Alles auswählen

	AddDate(AddDate(Date(jahr, monat, 1, 0, 0, 0), #PB_Date_Month, 1), #PB_Date_Day, -1)
:lol: so einfach kann's gehen...
ich hätte mir wohl erstmal die ganze Lib anschaun sollen...
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

> erstmal die ganze Lib anschaun
Easy, wenn man die ganzen Befehle auswendig kennt. :)

Das Gute an dieser Lösung ist, dass AddDate() automatisch Schaltjahre und 28/29/30/31-tägige Monate berücksichtigt. Dadurch kann man ohne Sorgen vom Folgemonat 1 Tag abziehen. Find ich besser, als nur eine Stunde abzuziehen, da die Uhrzeit des gesuchten Tages dann 0:00 Uhr ist und nicht wie bei deiner Variante 23:00. So kann man besser eigene Uhrzeiten hinzufügen, falls gewünscht.

Was man vielleicht noch graziöser lösen könnte, ist die 2. Prozedur, in der solange 1 Tag abgezogen wird, bis der Tag ein Werktag ist. Mir fiel auf die Schnelle keine Bit-Operation ein. Sowas finde immer absolut beeindruckend. Finde es übrigens sub-optimal, dass DayOfWeek() 0 und 6 für Sonntag und Samstag zurückgibt. 1-5 und 6-7 für Mo-Fr und Sa-So fänd ich besser.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> Find ich besser, als nur eine Stunde, da die Uhrzeit des gesuchten Tages dann 0:00 Uhr ist und nicht wie bei deiner Variante 23:00. So kann man besser eigene Uhrzeiten hinzufügen, falls gewünscht.

na, dass ist doch marginal, dann rechnet man eben -86400 statt -3600 ... /:->

> in der solange 1 Tag abgezogen wird, bis der Tag ein Werktag ist.
:?:

Code: Alles auswählen

   LastDay = letzterTagImMonat( monat , jahr )
   If DayOfWeek(LastDay) = 0
    LastDay = AddDate(LastDay, #PB_Date_Day, -2)
   ElseIf DayOfWeek(LastDay) = 6
    LastDay = AddDate(LastDay, #PB_Date_Day, -1)
   EndIf
... was ich an deiner Variante jetzt wirklich suboptimal fand, dass du den "LastDay" als "monat" bezeichnet hast,
zumal du über diese Variable zuvor den fraglichen monat importiert hattest.....
gezielte Irreführung durch Fehlbenennung von Variablen?


> Mir fiel auf die Schnelle keine Bit-Operation ein.

kanns doch garnicht geben.
Bits funktionieren auf Basis 2, nicht auf Basis 7...

> dass DayOfWeek() 0 und 6 für Sonntag und Samstag zurückgibt.

0-6 ist ja nicht verkehrt, allerdings stimme ich dir zu, dass das Interval mal auf Mo-So geändert werden sollte. (ISO 8601)
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

> dann rechnet man eben -86400 statt -3600
Hauptsache, man macht das via AddDate(), denn das berücksichtigt, wie gesagt, verschieden tätige Monate.

> dass du den "LastDay" als "monat" bezeichnet hast
So braucht man nicht erst eine neue Variable definieren. Sollte (wenn auch marginal) performanter sein, dachte ich mir.
Betrachtet man einen Algorithmus als "Black Box", in die man nicht hineinschauen kann, sondern der man nur Input/Output geben/entnehmen kann, dann dürfte das Innenleben (sprich, die Variablen) egal sein.

> Bits funktionieren auf Basis 2, nicht auf Basis 7
Das weiß ich. Ich meinte aber, dass mir gerade keine Rechenoperation einfiel, womit ich den Output von DayOfWeek() von 0-7 auf 1-7 umbiegen kann. Oder noch besser, so dass ich 0 für Mo-Fr, 1 für Sa und 2 für So rausbekomme, damit ich es direkt in AddDate() einsetzen kann.

Ein Bit-Trick ist z. B. das umwandeln von Buchstaben zwischen Groß- und Kleinschreibung, indem man !32 auf den ASCII-Wert appliziert. Habs im englischen Forum gesehen, sowas find ich faszinierend.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> Hauptsache, man macht das via AddDate(), denn das berücksichtigt, wie gesagt, verschieden tätige Monate.

hä?

bullshit!

wenn ich ein Date als LONG-Wert in Sekunden habe, und davon 86400 Sekunden abziehe, dann bin ich beim vorherigen Tag, schiet-egal wie der Tag geparst wird!

*koppschüttel*


> Betrachtet man einen Algorithmus als "Black Box"
... postet man iohn nicht als Beispiel für Anfänger.

Postet man hingegen einen Code als Beispiel für Anfänger, achtet man darauf, seine Variablen anständig zu benamsen.


> dass mir gerade keine Rechenoperation einfiel, womit ich den Output von DayOfWeek() von 0-7 auf 1-7 umbiegen kann.

Code: Alles auswählen

((( DayOfWeek( __RequestedDate__ ) + 6 ) % 7 ) + 1 )


> Ein Bit-Trick ist z. B. das umwandeln von Buchstaben zwischen Groß- und Kleinschreibung, indem man !32 auf den ASCII-Wert appliziert.

was natürlich nur für die 26 international standartisierten Zeichen zutrifft.

aber ich weiß was du meinst.

Code: Alles auswählen

PlayerX = ( PlayerX + PlayerSpeedX ) & 1024
begrenzt die Koordinate auf 1024 mit sidewrap, unabhängig vom Vorzeichen der Geschwindigkeit.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

> davon 86400 Sekunden abziehe, dann bin ich beim vorherigen Tag

Habs grad mal getestet, du hast Recht:

Code: Alles auswählen

; AND51
Debug FormatDate("%hh:%ii:%ss %dd.%mm.%yyyy", letztertagImMonat(2, 2008))
; Kaeru Gaman
Debug FormatDate("%hh:%ii:%ss %dd.%mm.%yyyy", Date(2008, 3, 1, 0, 0, 0)-86400)
Bin davon ausgegangen, dass deine Methode ein ungültiges Datum ergeben müsste, keine Ahnung, wieso.

Sowas wie dein Bit-Trick habe ich gesucht, danke! Beim Betrachten deines Terms frage ich mich aber, ob der implementierungswürdig ist, oder ob der bisherige Code genauso schnell ist.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Antworten