Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Den letzten Donnerstag eines Monats (https://www.delphipraxis.net/194580-den-letzten-donnerstag-eines-monats.html)

HPB 8. Dez 2017 16:16

Den letzten Donnerstag eines Monats
 
Guten Tag Delphianer,
wie kann man immer z. B. den letzten Donnerstag eines Monats ermitteln?
Eine Routine in Delphi gibt es wohl dazu nicht?
Vielen Dank im Voraus für evtl. Hilfen.
HPB

LTE5 8. Dez 2017 16:17

AW: Den letzten Donnerstag eines Monats
 
Vielleicht hilft dir das

Last Monday of Month

HPB 8. Dez 2017 16:26

AW: Den letzten Donnerstag eines Monats
 
Zitat:

Zitat von LTE5 (Beitrag 1388338)
Vielleicht hilft dir das

Last Monday of Month

Das sieht sehr viel Versprechend aus. Ich werde es morgen mal testen.

jobo 8. Dez 2017 16:27

AW: Den letzten Donnerstag eines Monats
 
Wenn das Projekt bereits mit einer Datenbank arbeitet, kann man die idR. auch dafür einsetzen, vor allem wenn dieser "Donnerstag" sowieso im Zusammenhang mit irgendwelchen Arbeitszeiten in einem Unternehmen steht.

LTE5 8. Dez 2017 16:33

AW: Den letzten Donnerstag eines Monats
 
Ohne Datenbank vielleicht so

Delphi-Quellcode:
procedure LastThursday(Date: TDate); overload;
begin
 LastThurday(DateUtils.YearOf(Date), DateUtils.MonthOf(Date));
end;

procedure LastThursday(Year, Month: Word); overload;
var
 i, tmp, Day, DaysMonth: Integer;
begin
 DaysMonth := DaysInAMonth(Year, Month);
 Day := DaysMonth;

 while Day > 1 do // geht sicher auch kürzer, denn man braucht ja nur maximal 7 Tage ab Monatsende rückwärts zu prüfen
  begin
   tmp := (Day + 5) mod 7;

   if tmp = 5 then
    begin
     ShowMessage('Letzter Donnerstag im Monat: ' + FormatDateTime('dd/mm/yyyy', EncodeDate(Year, Month, Day)));
     Break;
    end;

   Dec(Day);
  end;
end;

procedure TForm1.Button7Click(Sender: TObject);
begin
 LastThurday(2017, 12);

 LastThurday(DateUtils.YearOf(Date), DateUtils.MonthOf(Date));

 LastThurday(Date);
end;
Zitat:

Eine Routine in Delphi gibt es wohl dazu nicht?
Jetzt schon.

Das geht noch 10x schöner und besser, das ist klar. Das ist dann aber Herr Raabes Job - der Code-Optimierer in Person.

ConstantGardener 8. Dez 2017 19:14

AW: Den letzten Donnerstag eines Monats
 
Delphi-Quellcode:
function TForm2.LetzterDonnerstag(AYear, AMonth: Word): TDate;
var ADate : TDate;
    ADay : Word;
begin
 ADate:=IncMonth(EncodeDate(AYear,AMonth,1))-1;                 // letzer Tag des Monats
 ADay :=DayOfTheWeek(ADate);                                    // ist was für ein Tag ?
 if ADay<4 then                                                
  result:=ADate+(4-ADay)-7                                       // Montag-Mittwoch ?
 else
  result:=ADate+(4-ADay)
end;

evtl. so?

Solutor 25. Dez 2017 17:39

AW: Den letzten Donnerstag eines Monats
 
Dieser Funktion übergibt man das Jahr, den Monat und den Wochentag von dem man wissen möchte wann der letzte davon im Monat ist.
Als Ergebnis bekommt man das Datum (TDatetime) dieses letzen Tages.
Die Wochendatge sind nach der alten Weise vergeben. 1-7 wovon 1 der Sonntag ist.

Für das geforderte Problem würde man die 5 für Donnerstag als letzten Parameter übergeben.

Da hier keine Schleifen, sondern nur eine verkettete If Abfrage sowie eine Addition, bzw. Subtraktion verwendet wird,
dürfte diese Funktion auch recht schnell sein.

Delphi-Quellcode:
Function GetLastWeekDayOfMonth(yyyy,mm,d:Integer):TDatetime;
Var Adate:TDatetime;
    y,m,z:Integer;
begin
   z:=DayOfWeek(DateUtils.EndOfAMonth(yyyy,mm));
   if z=d then
   begin
      Result:=DateUtils.EndOfAMonth(yyyy,mm);
   end
   else
   if z>d then
   begin
      z:=z-d;
      Result:=DateUtils.EndOfAMonth(yyyy,mm)-z;
   end
   else
   begin
      z:=z-d;
      Result:=DateUtils.EndOfAMonth(yyyy,mm)-z-7;
   end;
end;

LTE5 25. Dez 2017 18:09

AW: Den letzten Donnerstag eines Monats
 
Deine Funktion ist etwa 60% schneller als die im Beitrag dadrüber.

Amateurprofi 26. Dez 2017 01:30

AW: Den letzten Donnerstag eines Monats
 
Zitat:

Zitat von LTE5 (Beitrag 1389647)
Deine Funktion ist etwa 60% schneller als die im Beitrag dadrüber.


Naja, wenn es um Schnelligkeit geht dann so:

Delphi-Quellcode:
// WeekDay 0=Mo, 6=So
FUNCTION LastWeekDayOfMonth(Year,Month,WeekDay:Integer):TDateTime;
const DIM:Array[1..12] of byte=(31,28,31,30,31,30,31,31,30,31,30,31);
var Day,DN,DoW,Y:Integer;
begin
   Y:=Year;
   Day:=DIM[Month]+Ord((Month=2) and ((Year mod 4=0) and (Year mod 100<>0) or (Year mod 400=0)));
   DN:=Year*365+Day+31*(Month-1);
   If Month>2 then Dec(DN,(23+4*Month) div 10)
      else if Year<>0 then Dec(Year)
         else Dec(DN);
   Inc(DN,Year div 4 - Year div 100 + Year div 400);
   DoW:=(5+DN) mod 7;
   if WeekDay>DOW then Dec(Day,7-WeekDay+DoW) else Dec(Day,Dow-WeekDay);
   Result:=EncodeDate(Y,Month,Day);
end;
Kurz zur Funktion, falls es jemanden interessiert:
In der Funktion wird u.A. DN berechnet. DN ist die Anzahl der Tage, die seit dem fiktiven Datum 01.01.0000 vergangen sind, wobei angenommen wird, dass der Gregorianische Kalender schon immer gegolten hätte.
Der 01.01.0000 hätte also die Nummer 0.

Auf meinem Rechner (i7 2600K 3.4 GHz) arbeitet diese Funktion deutlich schneller.
Bei unten stehendem Test brauchte diese Funktion 187 ms, die aus #7 2262 ms.
Das mag auf anderen Rechnern anders sein.

Hinzu kommt, dass die Funktion aus #7 in bestimmten Fällen falsche Resultate liefert.
Für Dezember 1899 und Montag liefert #7 den 26.12.1899, richtig wäre der 25.12.1899 (Geburtstag von Humphrey Bogart).
Auch für Dienstag bis Freitag im Dezember 1899 tritt diese Verschiebung um einen Tag auf.
Ansonsten arbeitet sie im Zeitraum 1583 bis 2500 korrekt.
Was mir ebenfalls nicht an #7 gefällt, ist, dass sie nicht ein Datum sondern einen Zeitpunkt liefert (nämlich 23:59:59 am jeweiligen Tag) was vermutlich auch die Quelle des Fehlers ist.

Hier die Prozedur mit der ich getestet habe.

Delphi-Quellcode:
PROCEDURE TMain.Test;
var Err,I,Year,Month,DoW1,DoW2:Integer; DT1,DT2:TDateTime; DS1,DS2:String;
    T0,T1,T2:Cardinal;
begin
   // Prüfung ob beide Funktionen identische Ergebnisse bringen
   Err:=0;
   for Year:=1583 to 2500 do
      for Month:=1 to 12 do
         for DoW1:=0 to 6 do begin
            DT1:=LastWeekDayOfMonth(Year,Month,DoW1);
            DS1:=FormatDateTime('dd.mm.yyyy',DT1);
            if DoW1<6 then DoW2:=DoW1+2 else DoW2:=1;
            DT2:=GetLastWeekDayOfMonth(Year,Month,DoW2);
            DS2:=FormatDateTime('dd.mm.yyyy',DT2);
            if DS1<>DS2 then begin
               Inc(Err);
               ShowMessage(IntToStr(Year)+' '+IntToStr(Month)+#13+
                           IntToStr(DoW1)+' '+DS1+#13+
                           IntToStr(DoW2)+' '+DS2);
            end;
         end;
   ShowMessage(IntToStr(Err));
   // Performance Vergleich
   T0:=GetTickCount;
   for I:=1 to 50 do
      for Year:=1583 to 2500 do
         for Month:=1 to 12 do
            for DoW1:=0 to 6 do
               DT1:=LastWeekDayOfMonth(Year,Month,DoW1);
   T1:=GetTickCount;
   for I:=1 to 50 do
      for Year:=1583 to 2500 do
         for Month:=1 to 12 do
            for DoW2:=1 to 7 do
               DT2:=GetLastWeekDayOfMonth(Year,Month,DoW2);
   T2:=GetTickCount;
   ShowMessage(IntToStr(T1-T0)+#13+IntToStr(T2-T1));
end;

blawen 26. Dez 2017 11:29

AW: Den letzten Donnerstag eines Monats
 
Zitat:

Zitat von Amateurprofi (Beitrag 1389657)
Naja, wenn es um Schnelligkeit geht dann so:

Delphi-Quellcode:
// WeekDay 0=Mo, 6=So
FUNCTION LastWeekDayOfMonth(Year,Month,WeekDay:Integer):TDateTime;
const DIM:Array[1..12] of byte=(31,28,31,30,31,30,31,31,30,31,30,31);

Wie sieht es mit Schaltjahren aus? Diese werden nicht berücksichtigt - oder übersehe ich etwas?


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:30 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz