Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   FMX - DX10 - Falsche Wochennummer im TCalendar (https://www.delphipraxis.net/187809-fmx-dx10-falsche-wochennummer-im-tcalendar.html)

Harry Stahl 6. Jan 2016 00:48

FMX - DX10 - Falsche Wochennummer im TCalendar
 
Wie ich leider gerade feststellen musste, zeigt die FMX-TCalendar-Komponente die falsche Wochennummer an (für diese Woche, den 6. Januar schon die 2. Woche, ist aber tatsächlich die erste, das Jahr 2015 hatte 53 Wochen).

Siehe Meldung bei QC hier: https://quality.embarcadero.com/browse/RSP-13358

Nur gut, dass ich die MAC-Version meines Termin- und Aufgabenprogramms noch unter Beta-Status veröffentlicht habe, mit falschen Wochenzahlen ist das echt mies:cry:

Ich hatte gerade mal versucht, die Quelle des Übels auszumachen, damit ich das evtl. selber mit einem Fix beheben kann.

Irgendwie komme ich aber nicht an die Stelle ran. Die FMX-Calendar-Komponente wird vermutlich mit einem Style gezeichnet, dazu werden wohl Botschaften verschickt, ich weiß aber nicht wohin und welche Stelle ich quasi abhören müsste, um an die konkrete Zeichenroutine zu kommen. Ein Debugg-Versuch (z.B. ab OnPainting) führte leider nicht zum Ziel.

Hat da evtl. Jemand eine Idee?

Sir Rufo 6. Jan 2016 01:53

AW: FMX - DX10 - Falsche Wochennummer im TCalendar
 
Delphi-Quellcode:
unit FMX.Calendar.Style;
Zeile 584f :stupid:

Man beachte den Kommentar in Zeile 583:
Delphi-Quellcode:
  // WeekOfTheYear doesn't consider a current Locale. So for 01.01.2017 returns 52.
  if MonthOf(FDateTime) = MonthJanuary then
    FirstWeekOfMonth := 1
  else
    FirstWeekOfMonth := WeekOfTheYear(RecodeDay(FDateTime, 1));
Da hat also ein Programmierer von Emba einen (angeblichen) Fehler in der Funktion
Delphi-Quellcode:
WeekOfTheYear
festgestellt. Aber anstatt diesen Fehler einmal intern an das
Delphi-Quellcode:
System.DateUtils
-Team zu melden (ja, dafür hätte er wohl 4 Wochen Kaffee für alle holen müssen) denkt er sich eine ganz tolle Methode aus:

Jedes Jahr startet mit der Woche 1 :roll:

Aber seine wir froh, dass er nicht einfach die
Delphi-Quellcode:
WeekOfTheYear
-Routine "gefixt" hat :mrgreen:

@Harry

Melde doch mal diesen
Delphi-Quellcode:
WeekOfTheYear
"Fehler" und verweise stumpf und vor allem erbost auf den Kommentar. Die stellen selber Fehler fest und korrigieren die nicht. Mal sehen was passiert ... ob wir das Geschrei bis hier hören können? :stupid:

HolgerX 6. Jan 2016 10:39

AW: FMX - DX10 - Falsche Wochennummer im TCalendar
 
Hmm..

Stellt sich die Frage, was liefert WeekOfYear für den 1.1.2016?

Muss eigentlich KW 53 sein, so wie (richtig) 1.1.2017 noch zur KW 52 gehört ;)

Blubber Blubber (noch zu Früh)

"WeekOfTheYear"

Und bei Delphi 6 gibt es die 'angebliche' Fehlerbehandlung noch nicht ;)

Bernhard Geyer 6. Jan 2016 11:41

AW: FMX - DX10 - Falsche Wochennummer im TCalendar
 
Zitat:

Zitat von HolgerX (Beitrag 1326119)
Und bei Delphi 6 gibt es die 'angebliche' Fehlerbehandlung noch nicht ;)

Es ist ja ein FXM-Problem. in der VCL passt es ja.

p80286 6. Jan 2016 13:17

AW: FMX - DX10 - Falsche Wochennummer im TCalendar
 
Entschuldigt, aber ich glaube ihr sucht falsch.
Zitat:

Das Jahr umfasst mindestens 52 Wochen, die v. a. im Geschäftsleben als Kalenderwochen (KW) durchnummeriert werden, wobei es bei den Wochen-Nummerierungen verschiedene Definitionen gibt. Je nach angewandter Regel kann die erste Woche des Jahres unterschiedlich sein:
ISO (DIN/ÖNORM/SN): die Woche, die den ersten Donnerstag des Jahres enthält (ISO 8601, früher DIN 1355-1). Äquivalent sind folgende Definitionen (da ISO 8601 den Montag als ersten Tag der Woche definiert): die Woche, die den 4. Januar enthält
die Woche, in der der 1. Januar ein Montag, Dienstag, Mittwoch oder Donnerstag ist, sonst die darauf folgende Woche
die erste Woche, in die mindestens vier Tage des neuen Jahres fallen bzw. die erste Woche, in die mehr Tage auf das neue Jahr fallen als auf das alte Jahr

USA: jene, in die der 1. Januar fällt
Selten: die erste vollständige Woche des Jahres
https://de.wikipedia.org/wiki/Woche

Je nach Sichtweise ist das also nicht unbedingt falsch.

Gruß
K-H

Sir Rufo 6. Jan 2016 13:20

AW: FMX - DX10 - Falsche Wochennummer im TCalendar
 
Nein, wir suchen nicht falsch, denn ab Februar wird die Wochennummer wieder so angezeigt wie die VCL Komponente das macht.

Die FMX-Variante ist grundsätzlich falsch implementiert.

Harry Stahl 6. Jan 2016 19:31

AW: FMX - DX10 - Falsche Wochennummer im TCalendar
 
Super, erst mal Danke für die Ausweisung der Stelle.

Allerdings reicht es leider nicht, die 3 Zeilen zu löschen, wie von Dir auf QC vorgeschlagen, denn dann zählt die Woche mit 54,55 Woche in Januar 2016 weiter (entscheidend ist die Zeichenroutine, die da unten weiter geht).

Das ist mein aktueller Stand eines Workarounds (muss jetzt runter, haben Besuch), scheint zu funktionieren:

Delphi-Quellcode:
procedure TStyledCalendar.FillWeeksNumbers;
var
  I: Integer;
  CaptionControl: ICaption;
  FirstWeekOfMonth: Byte;
  WeekCorrection, MNr: Integer;
begin
  if FWeeks = nil then
    Exit;

  FWeeks.Visible := Model.WeekNumbers;

  // WeekOfTheYear doesn't consider a current Locale. So for 01.01.2017 returns 52.
   if ((MonthOf(FDateTime) = MonthJanuary)) then begin
     if (Weekoftheyear (FDateTime) <> 53) then begin
       FirstWeekOfMonth := WeekOfTheYear(RecodeDay (FDateTime, 1));
     end else begin
       FirstWeekOfMonth := 1;
     end;
   end else begin
     FirstWeekOfMonth := WeekOfTheYear(RecodeDay (FDateTime,1));
   end;

  // First week in FDay may be a last week of previous month. So we need to keep offset for correct counting of weeks.
  WeekCorrection := (DefineItemIndexOfFirstDayInCurrentMonth - 1) div 7;
  for I := 0 to FWeeks.ControlsCount - 1 do
    if Supports(FWeeks.Controls[I], ICaption, CaptionControl) then begin
      MNr := FirstWeekOfMonth + I - WeekCorrection;
      // Year 2015 has 53 Weeks; If Drawing parts of January in DEC-Calendar, start again with "1" in drawing
      if MNr > 53 then begin
        FirstWeekOfMonth := 0;
        MNr := 1;
      end;

      // eg. Dez. 2016 has 52 Weeks, so start after that again with "1" in drawing
      if ((MonthOf(FDateTime) = MonthDecember)) then begin
        if (MNr = 53) and (WeeksInAYear (YearOf (FDateTime)) =52) then begin
          FirstWeekOfMonth := 0;
          MNr := 1;
        end;
      end;

      // No 53.week in second week-Row in January possible
      if ((MonthOf(FDateTime) = MonthJanuary)) then begin
        if (MNr = 53) and (I = 1) then begin
          FirstWeekOfMonth := 0;
          MNr := 1;
        end;
      end;

      CaptionControl.Text := MNr.ToString;
 end;
end;
Wird erforderlich, um Umbrüche der Wochennummern im Dez/Januar richtig auszugeben.

Edit: Den letzten IF-Block habe ich gerade (22:10) noch ergänzt.

Sir Rufo 6. Jan 2016 19:44

AW: FMX - DX10 - Falsche Wochennummer im TCalendar
 
Ähm, dieser Workaround ist noch schlimmer als der Bug im Original-Code.

Diese Änderungen reichen (einfaches Auskommentieren)
Delphi-Quellcode:
  // WeekOfTheYear doesn't consider a current Locale. So for 01.01.2017 returns 52.
  // if MonthOf(FDateTime) = MonthJanuary then
  //   FirstWeekOfMonth := 1
  // else
    FirstWeekOfMonth := WeekOfTheYear(RecodeDay(FDateTime, 1));

Harry Stahl 6. Jan 2016 21:27

AW: FMX - DX10 - Falsche Wochennummer im TCalendar
 
Liste der Anhänge anzeigen (Anzahl: 3)
Also noch mal, Dein Vorschlag korrigiert zwar die falsche Berechnung an dieser Stelle, aber nicht die Ausgabe der Wochennummern insgesamt für den Kalender.

Deine "Korrektur" bringt u.a. die in den anliegenden Screenshots ersichtlichen fehlerhaften Ausgaben als Ergebnis (fehlerhafte Wochennummern in gelb).

Ich gebe ja gerne zu, dass in der halben Stunde Zeit, die ich gerade hatte, der Workaround sicher nicht optimal geschrieben ist, sieht aber nach kurzen Tests (Vergleich einiger Jahre mit einem richtigen Kalender) vom Ergebnis erst mal ganz gut aus.

Für alternative (schönere Lösungen) bin ich aber immer gerne zu haben.:wink:

Davon mal abgesehen sollte der WA aber schnell von EMBA kommen, ist hier ja nicht unsere Aufgabe, deren Arbeit zu machen.

Sir Rufo 6. Jan 2016 23:00

AW: FMX - DX10 - Falsche Wochennummer im TCalendar
 
Nun ja, es ist eigentlich kein Hexenwerk, sondern nur logisches Vorgehen.
Delphi-Quellcode:
procedure TStyledCalendar.FillWeeksNumbers;
var
  I: Integer;
  CaptionControl: ICaption;
  LMonday : TDate;
begin
  if FWeeks = nil then
    Exit;

  FWeeks.Visible := Model.WeekNumbers;
 
  // Vom Monatsanfang den Wochenanfang ermitteln
  LMonday := StartOfTheWeek( StartOfTheMonth( FDateTime ) );
  // für jede Zeile
  for I := 0 to FWeeks.ControlsCount-1 do
  begin
    // die Wochennummer ermitteln
    if Supports(FWeeks.Controls[I], ICaption, CaptionControl) then
      CaptionControl.Text := WeekOfTheYear(lMonday).ToString;
    // Tag eine Woche weiterzählen
    lMonday := IncWeek( lMonday );
  end;
end;
Sorry for being short :mrgreen:

Für die Überprüfung kann man auch gerne dieses kleine Konsolen-Programm starten (zeigt das Kalandar-Blatt) für den aktuellen Monat an.
Delphi-Quellcode:
program MonthCalendar;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.DateUtils,
  System.SysUtils;

procedure OutputMonthCalendarFor( const aDate: TDate; aRows: Integer = 6; aWeekNumbers: Boolean = true );
var
  lFirstMonday: TDate;
  lDay       : TDate;
  row, day   : Integer;
begin
  lFirstMonday := StartOfTheWeek( StartOfTheMonth( aDate ) );

  if aWeekNumbers
  then
    write( '   ' );
  WriteLn( FormatDateTime( 'mmmm yyyy', aDate ):26 );
  WriteLn;

  lDay := lFirstMonday;
  if aWeekNumbers
  then
    write( '  ' );
  for day := 1 to 7 do
    begin
      write( FormatDateTime( '" "ddd" "', lDay ) );
      lDay := IncDay( lDay, 1 );
    end;
  WriteLn;

  lDay   := lFirstMonday;
  for row := 0 to aRows - 1 do
    begin
      if aWeekNumbers
      then
        write( WeekOfTheYear( lDay ):2, ' ' );
      for day := 0 to 6 do
        begin
          if lDay = DateOf( aDate )
          then
            write( '<', DayOf( lDay ):2, '>' )
          else
            write( ' ', DayOf( lDay ):2, ' ' );
          lDay := IncDay( lDay, 1 );
        end;
      WriteLn;
    end;
end;

begin
  try
    OutputMonthCalendarFor( Date );
  except
    on E: Exception do
      WriteLn( E.ClassName, ': ', E.Message );
  end;
  ReadLn;

end.
Sieht dann so aus
Code:
                   Januar 2016

    Mo  Di  Mi  Do  Fr  Sa  So
53  28  29  30  31   1   2   3
 1   4   5 < 6>  7   8   9  10
 2  11  12  13  14  15  16  17
 3  18  19  20  21  22  23  24
 4  25  26  27  28  29  30  31
 5   1   2   3   4   5   6   7


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:56 Uhr.
Seite 1 von 2  1 2      

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