DateAdd für Werktage

Moderator: ModerationP

DateAdd für Werktage

Beitragvon Gast » 11. Mai 2021, 15:16

Hallo,
mit DateAdd sollen bestimmte Termine in der Zukunft festgelegt werden.
Wie kann man sicherstellen, dass es keine Samstage, Sonntage oder Feiertage sind?
Gruß Carlo
Gast
 

Re: DateAdd für Werktage

Beitragvon KlausMz » 11. Mai 2021, 15:46

Hallo,
mit einer Kalendertabelle funktioniert das prima.

Im Anhang findest Du ein Beispiel.
Bei Fragen bitte melden.

Um das Beispiel herunterladen zu können, musst Du Dich im Forum anmelden.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Gruß
Klaus . . . . . Feedback wäre wünschenswert.
Ich möchte bitte keine unaufgeforderten PN. Fragen bitte im Forum.
Benutzeravatar
KlausMz
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 40104
Registriert: 06. Okt 2003, 15:09
Wohnort: Irgendwo in der Pfalz

Re: DateAdd für Werktage

Beitragvon cardur » 13. Mai 2021, 13:00

Hallo,
danke für das Beispiel. Ich glaube, das ist verwendbar.
Vielleicht schaffe ich es noch, die Feiertage automatisch eintragen zu können. Erinnere mich, dass der Gregorianische Kalender und die Feiertage von Ostern eines jeden Jahres abhängen.
Aber momentan klappt dies noch nicht
Code: Alles auswählen
EinDatum=#4/15/2022#
?EinDatum
15.04.2022
?dlookup("TDatum","AlleArbeitstage","TDatum=" & Eindatum)

Obwohl TDatum und EinDatum vom Typ Datum sind, wird DLookup nicht richtig verarbeitet. Man muss EinDatum wohl zerlegen, was umständlich wäre.
Oder gibt es eine andere Variante, einen bestimmten Tag auf Arbeitstag zu prüfen?
Gruß Carlo
cardur
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 11
Registriert: 13. Mai 2021, 10:21

Re: DateAdd für Werktage

Beitragvon KlausMz » 13. Mai 2021, 13:36

Hallo,
da muss nix zerlegt werden. Für ein Datumsvergleich muss ein Datum entweder im ISO Format (YYYY-MM-DD) oder im US Format (MM-TT-YYYY) verglichen werden. Unabhängig von der Eingabe und der Darstellung. Außerdem würde ich zählen, wird 1 ausgegeben ist es ein Arbeitstag, bei 0 keiner. Ich bevorzuge ISO, das ist deutlicher zu erkennen.

Code: Alles auswählen
EinDatum=#4/15/2022#
?EinDatum
15.04.2022
EinDatum=Format(EinDatum, "\#yyyy\-mm\-dd\#")
?EinDatum
#2022-04-15#
?Dcount("TDatum","AlleArbeitstage","TDatum=" & EinDatum)
 1

Code: Alles auswählen
EinDatum=#4/16/2022#
?EinDatum
16.04.2022
EinDatum=Format(EinDatum, "\#yyyy\-mm\-dd\#")
?EinDatum
#2022-04-16#
?Dcount("TDatum","AlleArbeitstage","TDatum=" & EinDatum)
 0

Durch eine kleinen Zusatz in der Dcount Zeile kannst Du auch direkt Wahr/True bzw. Falsch/False ausgeben lassen.
Für den 16.04.2022
Code: Alles auswählen
?Dcount("TDatum","AlleArbeitstage","TDatum=" & EinDatum) > 0
Falsch
Gruß
Klaus . . . . . Feedback wäre wünschenswert.
Ich möchte bitte keine unaufgeforderten PN. Fragen bitte im Forum.
Benutzeravatar
KlausMz
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 40104
Registriert: 06. Okt 2003, 15:09
Wohnort: Irgendwo in der Pfalz

Re: DateAdd für Werktage

Beitragvon cardur » 13. Mai 2021, 16:35

Hallo,
?Dcount("TDatum","AlleArbeitstage","TDatum=" & EinDatum) > 0

Falsch, also kein Arbeitstag, könnte auch ausgegeben werden, obwohl es doch ein Arbeitstag ist, wenn einDatum nicht in "AlleArbeitstage" enthalten ist.
Spräche das nicht für DLookup? Da würde NULL geliefert, während bei DCount 0 kommt, was zweideutig ist. Also entweder nicht in der Datensatzquelle oder kein Arbeitstag, falls einDatum in der Quelle ist.
Gruß Carlo
cardur
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 11
Registriert: 13. Mai 2021, 10:21

Re: DateAdd für Werktage

Beitragvon KlausMz » 13. Mai 2021, 16:46

Hallo,
wenn einDatum nicht in "AlleArbeitstage" enthalten ist.
ein solcher Fall kann nicht eintreten, wie soll das gehen ?
Die Kalendertabelle muss ein ausreichendenden Zeitraum umfassen, das ist zwingend.
Um Falscheingaben zu vermeiden, muss das eingegebene Datum geprüft werden. Datumswerte die nicht im Bereich der Kalendertabelle (tblAlleTage) sind, dürfen nicht zugelassen werden.
Gruß
Klaus . . . . . Feedback wäre wünschenswert.
Ich möchte bitte keine unaufgeforderten PN. Fragen bitte im Forum.
Benutzeravatar
KlausMz
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 40104
Registriert: 06. Okt 2003, 15:09
Wohnort: Irgendwo in der Pfalz

Re: DateAdd für Werktage

Beitragvon cardur » 13. Mai 2021, 16:58

Hallo,
Datumswerte die nicht im Bereich der Kalendertabelle (tblAlleTage) sind, dürfen nicht zugelassen werden.

Also die Prüfung dann mit Dcount?
Aber dann hat man ja wieder das Problem 0 statt NULL
Gruß Carlo
cardur
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 11
Registriert: 13. Mai 2021, 10:21

Re: DateAdd für Werktage

Beitragvon KlausMz » 13. Mai 2021, 17:21

Hallo,
ich verstehe gerade Dein Problem nicht.
Die Prüfung ob ein Datum innerhalb der Kalendertabelle liegt hat mit der Prüfung ob Arbeitstag nichts zu tun.
Erst Prüfung auf Plausibilität, dann Prüfung auf Arbeitstag.
Auch die Plausiblitätsprüfung kann mit Dcount erfolgen.

Wenn das Datum plausibel war (innerhalb der Kalendertabelle) ist die Ausgabe von Falsch/Wahr eindeutig.

Schema für eine Funktion "Arbeitstag():
Code: Alles auswählen
Public Function Arbeitstag(D As Date) As Boolean
    If DCount("TDatum", "tblAlleTage", "TDatum=" & Format(D, "\#yyyy\-mm\-dd\#")) = 0 Then
        MsgBox "Ungültiges Datum"
        Exit Sub
    End If
Arbeitstag = DCount("TDatum", "AlleArbeitstage", "TDatum=" & Format(D, "\#yyyy\-mm\-dd\#")) > 0
End Function

Ungetestet
Die Funktion liefert dann True oder False
Gruß
Klaus . . . . . Feedback wäre wünschenswert.
Ich möchte bitte keine unaufgeforderten PN. Fragen bitte im Forum.
Benutzeravatar
KlausMz
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 40104
Registriert: 06. Okt 2003, 15:09
Wohnort: Irgendwo in der Pfalz

Re: DateAdd für Werktage

Beitragvon cardur » 13. Mai 2021, 18:01

Hallo,
Wenn das Datum plausibel war (innerhalb der Kalendertabelle) ist die Ausgabe von Falsch/Wahr eindeutig.

Ich habe dies gemacht und beobachtet:
1) Im Formular 1 als Startjahr 2022 und als EndeJahr 2023 eingegeben. In tblAlleTage stehen also alle Tage vom 1.1.2022 bis 31.12.2023. OK
2) Im Direktbereich: ?Arbeitstag(cdate("15.5.2022")) liefert Falsch. OK, da der 15. Mai 2022 ein Sonntag ist.
3) Im Direktbereich: ?Arbeitstag(cdate("15.5.2044")) liefert "Ungültiges Datum" OK, aber auch Falsch
Bei 3) wird zwar die richtige Meldung der Msgbox gezeigt, aber gleichzeitig auch Falsch ausgeworfen, obwohl exit Function ausgeführt wird
Der Rückgabewert steht also auf false.
Daher kann der Rückgabewert nicht ausgewertet werden, da man mit false nicht unterscheiden kann, ob das Datum in tblAlleTage fehlt oder es ein Arbeitstag ist.
Gruß Carlo
cardur
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 11
Registriert: 13. Mai 2021, 10:21

Re: DateAdd für Werktage

Beitragvon cardur » 13. Mai 2021, 18:09

Hallo,
vielleicht auch noch wichtig:
das tblAlleTage nur 2 Jahre umfasst, basiert auf der Überlegung evtl. eine Combo zur Filterung einzusetzen, also weniger Einträge zu haben.
Also StartJahr und EndeJahr sollen dynamisch gesetzt werden, um nicht eine so lange Tabelle zu haben.
StartJahr = year(date) + 1 und EndeJahr= year(date) + 2. So wären die Einträge einer Combobox als Filter geringer.
Bisher habe ich dies:
Code: Alles auswählen
 If Date >= DateSerial(Year(Date), 12, 24) Then
    Call fncAlleTageFuellen(Year(Date) + 1, Year(Date) + 2)
  End If

Das würde funktionieren, wenn man in der Zeit vom 24.12. – 31.12. eines Jahres das Formular öffnet, um in tblAlleTage die Daten der zwei folgenden Jahre zu haben.
Wird das Formular aber erst am 1.1. des Folgejahres oder später geöffnet, so wird 1 Jahr übersprungen.
Wie kann man das vermeiden?
Gruß Carlo
cardur
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 11
Registriert: 13. Mai 2021, 10:21

Re: DateAdd für Werktage

Beitragvon KlausMz » 13. Mai 2021, 18:21

Hallo,
erstelle die Kalendertabelle mit ausreichenden Jahren. Das können 50 Jahre sein (wenn sinnvol), es ist aber relativ bedeutungslos. 50 Jahre sind ca. 18.250 Datensätze. Das ist eine Kleinigkeit für Access.
Zur Auswahl des Datums per Kombi wird die Datenherkunft das Kombis auf z.B. 2 Jahre (aktuelles Jahr und folgendes Jahr) gefiltert. Das Feld TDatum ist indiziert, da wirst Du keine merkliche Verzögerung haben beim Öffnen des Kombis.

Mein Vorschlag für die Funktion Arbeitstage ist ja keine endgültige Version. Es sollte nur die Möglichkeiten aufzeigen.

Da die Dateneingabe mit einem Formular folgt wäre hier etwas anders vorzugehen.
Etwa so:
Code: Alles auswählen
Private Sub Anfangdatum_BeforeUpdate(Cancel As Integer)
    If DCount("TDatum", "tblAlleTage", "TDatum=" & Format(Me.Anfangdatum, "\#yyyy\-mm\-dd\#")) = 0 Then
        MsgBox "Ungültiges Datum"
        Me.Anfangdatum.Undo
        Cancel = True
        Exit Sub
    End If
    If Arbeitstag(Me.Anfangdatum) = False Then
        MsgBox "Kein Arbeitstag"
        Me.Anfangdatum.Undo
        Cancel = True
    End If
End Sub

Damit ist es unmöglich ein ungültiges Datum einzegeben. Ebenso kann kein Datum eingegeben werden, das kein Arbeitstag ist.
Ob das für Deine Anforderung passt kann ich nicht sagen.

Warum filterst Du das Kombi nicht so, dass es nur Arbeitstage anzeigt?
Das wäre doch das einfachste.
Gruß
Klaus . . . . . Feedback wäre wünschenswert.
Ich möchte bitte keine unaufgeforderten PN. Fragen bitte im Forum.
Benutzeravatar
KlausMz
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 40104
Registriert: 06. Okt 2003, 15:09
Wohnort: Irgendwo in der Pfalz

Re: DateAdd für Werktage

Beitragvon Bitsqueezer » 13. Mai 2021, 21:56

Hallo,

Daher kann der Rückgabewert nicht ausgewertet werden, da man mit false nicht unterscheiden kann, ob das Datum in tblAlleTage fehlt oder es ein Arbeitstag ist.


Und wenn Du doch herausgefunden hast, daß "Boolean" offensichtlich nicht genug ist, warum änderst Du den Datentyp nicht einfach, um mehr Informationen zu erhalten?

Du könntest etwa eine Enum erstellen mit einer Liste an Rückmeldungen und den Rückgabewert der Funktion als diese Enum einstellen. Dann kann der Aufrufer anhand des Rückgabewertes entscheiden, was nun zu tun ist - und Du kannst so viele Arten von Fehlermeldungen zurückgeben, wie Du magst.

Gruß

Christian
Bitsqueezer
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 8276
Registriert: 21. Jun 2007, 12:17

Re: DateAdd für Werktage

Beitragvon cardur » 14. Mai 2021, 11:43

Hallo,
@Klaus
Ob das für Deine Anforderung passt kann ich nicht sagen.
Der zu prüfende Tag stammt aus einer OptionGroup: Werte von versch. Zeiträumen (Wochen, Monate bis zu 1 Jahr. Aber mit der großen Tabelle und deinem Code läuft es.
Warum filterst Du das Kombi nicht so, dass es nur Arbeitstage anzeigt? Das wäre doch das einfachs-te.
Bei der großen z.B. 30-Jahre-Tabelle hat man schon nach 1 Jahr Arbeitstage, die nicht mehr aktuell sind und in der Combobox nur stören. Daher die Idee der Beschränkung auf 2 Jahre mit einer jeweiligen Aktualisierung am Jahresende.
@Christian
den Rückgabewert der Funktion als diese Enum einstellen

Ich habe das mal versucht (ich glaube, da ist viel Umweg drin). Ist folgendes das, was du meinst?
Gruß Carlo
Code: Alles auswählen
Public Enum enmArbeitstag
  arbUngueltig
  arbKeinArbeitstag
  arbIstArbeitstag
End Enum

Public Function pfncArbeitstag(strEinDatum As String) As enmArbeitstag
  Dim dtmTag As Date
  dtmTag = CDate(strEinDatum)
 
  If DCount("TDatum", "tblAlleTage", "TDatum=" & Format(strEinDatum, "\#yyyy\-mm\-dd\#")) = 0 Then
    pfncArbeitstag = arbUngueltig
    Exit Function
  End If
 
  If Arbeitstag(dtmTag) = False Then
    pfncArbeitstag = arbKeinArbeitstag
    txtTermin = fncNaechsterArbTag(dtmTag) 'CDate(strEinDatum))
  Else
    txtTermin = CDate(strEinDatum) 'Datum, lang formatiert
    pfncArbeitstag = arbIstArbeitstag
  End If
End Function

Private Sub cmdDatumInput_Click()
  Dim strEinDatum As String
  Dim intArbeitstag As enmArbeitstag
 
  txtTermin = Null
  strEinDatum = Trim(InputBox("Datum zur Prüfung eingeben", "Datumcheck", "15.04.2022"))' Arbeitstag; 16.4. kein AT
  If strEinDatum = "" Then Exit Sub
  intArbeitstag = pfncArbeitstag(strEinDatum)
  Select Case intArbeitstag
    Case arbKeinArbeitstag
      MsgBox "Datum ist kein Arbeitstag"
    Case arbUngueltig
      MsgBox "Datum ist ungültig"
    Case arbIstArbeitstag
      MsgBox "Datum ist ein Arbeitstag"
  End Select
  End Sub
cardur
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 11
Registriert: 13. Mai 2021, 10:21

Re: DateAdd für Werktage

Beitragvon KlausMz » 14. Mai 2021, 12:58

Hallo,
Bei der großen z.B. 30-Jahre-Tabelle hat man schon nach 1 Jahr Arbeitstage, die nicht mehr aktuell sind und in der Combobox nur stören.
Den Einwand verstehe ich nun gar nicht. Du kannst doch für die Combobox eine Abfrage verwenden die nur die sinnvollen Datensätze zur Auswahl anbietet. Die Combobox (bzw. deren Datenherkunft) kannst Du auch mit der Optionsgruppe filtern. Die Größe der Tabelle ist da völlig bedeutungslos.
Damit wird auch der komplette Code überflüssig, weil nur Arbeitstage ausgewählt werden können.

PS:
Hier.
Code: Alles auswählen
Dim strEinDatum As String

und hier:
Code: Alles auswählen
... (strEinDatum As String) ...

Warum macht Du aus einem Datum einen String.
In meinem Beispiel ist das jedenfalls nicht.
Ein Datum ist ein Datum und bleibt Datum.
Gruß
Klaus . . . . . Feedback wäre wünschenswert.
Ich möchte bitte keine unaufgeforderten PN. Fragen bitte im Forum.
Benutzeravatar
KlausMz
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 40104
Registriert: 06. Okt 2003, 15:09
Wohnort: Irgendwo in der Pfalz

Re: DateAdd für Werktage

Beitragvon cardur » 14. Mai 2021, 14:50

Hallo,
Die Combobox (bzw. deren Datenherkunft) kannst Du auch mit der Optionsgruppe filtern.

Bevor ich das angehe, ist mit "Filtern" gemeint, das Recordset mit strSQL = Select... festzulegen oder die Variante me.Filter="...?
Wie müsste das aussehen, auch um einfach den Filter zurücksetzen zu können?
Warum macht Du aus einem Datum einen String?

Es gibt im Code Format(strEinDatum, "\#yyyy\-mm\-dd\#")
In der Hilfe steht zur Format-Funktion: Gibt einen Wert vom Typ Variant (String) zurück, der einen entsprechend den Anweisungen in einem Formatausdruck formatierten Ausdruck enthält.
Typ Variant (String) hatte ich so gedeutet, dass ein String übergeben werden muss und kein string vom Typ Datum (oder wie man das ausdrücken muss?) Aber es geht auch mit dtmTag (dtmTag = cdate(strEinDatum)). Ist da die Beschreibung der Hilfe ungenau oder lege ich da zuviel rein?
Gruß Carlo
cardur
Im Profil kannst Du frei den Rang ändern
 
Beiträge: 11
Registriert: 13. Mai 2021, 10:21

Nächste

Zurück zu Access Forum (provisorisch)

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste