Windows & Linux Unabhängig Filetime als GMT String

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Windows & Linux Unabhängig Filetime als GMT String

Beitrag von gocher »

Hallo zusammen,
unter Windows kenne ich einen Weg (nicht sehr schön geht aber), Unter Unix leider nicht!
Hat jemand einen besseren Weg und/oder einen Weg für Unix, etc?

Code: Alles auswählen

function FormatGMTDateTime(const DTFormat: string; const dt: TDateTime; GMTFormat: string = ''): string;
  function LastSunday(): TDateTime;
  begin
    result := EncodeDate(YearOf(dt), MonthOf(dt), DaysInMonth(dt));
    while DayOfTheWeek(result)<>DaySunday do result := result-1;
  end;
var
  h: integer;
  TZInfo: TTimeZoneInformation;
  fs: TFormatSettings;
begin
  GetLocaleFormatSettings(GB_LCID, fs);
  GetTimeZoneInformation(TZInfo);
  h := (TZInfo.Bias + TZInfo.StandardBias) DIV 60;
  case MonthOf(dt) of
  4,5,6,7,8,9 : dec(h);
  3 : if dt>=LastSunday() then dec(h);
  10 : if dt<LastSunday() then dec(h);
  end;
  if GMTFormat='' then
    result := FormatDateTime(DTFormat, IncHour(dt, h), fs)
  else
    result := FormatDateTime(DTFormat, IncHour(dt,h), fs) +
              IIF(GMTFormat[1]=' ', ' ') +
              IIF((pos('GMT', GMTFormat)>0) and (h=0), 'GMT',
                IIF(h<0,'+','-') + Format('%.2d', [Abs(h)]) +
                IIF(pos(':', GMTFormat)>0, ':') +
                IIF((pos('0000',GMTFormat)>0) or (pos('00:00',GMTFormat)>0), '00'));
end;
 
function FileTimeToDateTime(ft: FILETIME) : TDateTime;
var
  st : SYSTEMTIME;
  lt : FILETIME;
begin
  FillChar(st, SizeOf(st), 0);
  FillChar(lt, SizeOf(lt), 0);
  FileTimeToLocalFileTime(ft, lt);
  FileTimeToSystemTime(lt, st);
  result := SystemTimeToDateTime(st);
end;
 
function FileTimeToGMTDateTime(Filename: string; const DTFormat: string = 'ddd, dd mmm yyyy  hh:nn:ss "GMT"'): string;
var
  fh : THandle;
  fLastWriteTime : TFileTime;
  dt: TDateTime;
begin
  result := '';
  if FileExists(Filename) then
  begin
    fh := FileOpen(Filename, fmOpenRead or fmShareDenyNone);
    try
      if fh >0 then // <> INVALID_HANDLE_VALUE then
        if GetFileTime(fh, nil, nil, @fLastWriteTime) then
        begin
          dt := FileTimeToDateTime(fLastWriteTime);
          result := FormatGMTDateTime(DTFormat, dt);
        end;
    finally
      FileClose(fh);
    end;
  end;
end;
Zuletzt geändert von gocher am Mi 6. Jun 2012, 20:59, insgesamt 1-mal geändert.
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

Heinrich Wolf
Beiträge: 323
Registriert: Di 12. Apr 2011, 13:21
OS, Lazarus, FPC: WinXP + VMWare Player mit Fedora14, L 1.1, FPC 2.7.1
CPU-Target: 1core 1,8GHz 32Bit
Wohnort: Fürth
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT

Beitrag von Heinrich Wolf »

Hallo,

auf Windows bist Du mit GetTimeZoneInformation grundsätzlich richtig. Aber Du solltest auch TimeZoneInformation.StandardDate und TimeZoneInformation.DaylightDate auswerten. Die geben an, von wann bis wann Sommerzeit ist. Dann bist Du unabhängig von Deiner eigenen Berechnung über den Monat und letzten Sonntag. Und den Bias solltest Du nicht mit div 60 auf volle Stunden reduzieren. Es gibt nämlich auch Länder mit halbstündlichem oder noch krummerem Bias. Siehe auf der Weltkarte anbei, auch wenn diese schon sehr alt ist, die lila Regionen.

Hier ist die Beschreibung der Daten aus GetTimeZoneInformation:
http://msdn.microsoft.com/en-us/library ... s.85).aspx

Nachträgliche Info:
Bei einer unveränderten Datei auf Windows bewirkt das Umstellen der Systemuhr um ein halbes Jahr, dass sich die Anzeige des Zeitstempels dieser Datei um 1 Stunde verändert! Das sehe ich als groben Fehler von Windows an. Mit dieser Erkenntnis kann man alle Umrechnungsversuche mit GetTimeZoneInformation vergessen und bei dem Code bleiben, den gocher am 6.6. um 22:46 gepostet hat.

Für Unix brauchst Du mit

Code: Alles auswählen

uses
{$ifdef Unix}
  LibC,
  BaseUnix,
{$else}
  Windows,
{$endif}
einen anderen Programmcode. LibC wird zwar als deprecated bezeichnet, aber ich kenne keinen Ersatz. FpStat() liefert Dir in einer Struktur u.a. 3 time_t Werte (32 Bit LongWord Sekunden seit 1.1.1970 0:00:00 GMT). gmtime() macht daraus eine Struktur mit Feldern für h:mm:ss ... in GMT und strftime() formatiert Dir die Zeit. Diese Funktionen sind eher aus der C Bibliothek bekannt, aber auch in fpc verfügbar. Die man pages von Linux geben dazu eine ganze Menge Info (auf der Shell: $ man stat; $ man gmtime; $ man strftime).

Code: Alles auswählen

procedure TMainForm.ButtonClick(Sender: TObject);
  var
  {$ifdef Unix}
          s       : stat;
          tm      : ptm;
          b       : array[0 .. 30] of char;
  {$else}
          i       : Integer;
          Year,
          y,
          Month,
          Day     : Word;
          t       : tTimeZoneInformation;
          d,
          dd, ds  : tDateTime;
  {$endif}
  begin
    Zeit.Text := '';
    if OpenDialog.execute then
      begin
        Zeit.Text := OpenDialog.FileName;
        {$ifdef Unix}
          if FpStat(OpenDialog.FileName, s) <> 0 then
            Zeit.Text:=
              Zeit.Text + ' ' + SysErrorMessage(fpGetErrno) + ' in FpStat'
          else
            begin
              tm := gmtime(@s.st_mtime);
              if tm <> Nil then
                if strftime(b, sizeof(b), '%d.%m.%Y %T', tm) > 0 then
                  Zeit.Text:= Zeit.Text + ' ' + b + ' GMT';
            end;
        {$else}
          i := FileAge(OpenDialog.FileName);
          if i < 0 then
            Zeit.Text :=
              Zeit.Text + ' ' + SysErrorMessage(GetLastError) + ' in FileAge'
          else
            if GetTimeZoneInformation(t) = $FFFFFFFF then
              begin
                i := -1;
                Zeit.Text :=
                  Zeit.Text + ' ' + SysErrorMessage(GetLastError)
                  + ' in GetTimeZoneInformation';
              end;
          if i >= 0 then
            begin
              d := FileDateToDateTime(i);
              DecodeDate(d, Year, Month, Day);
              d := d + t.Bias / 24 / 60;
              if t.DaylightDate.wYear <> 0 then
                dd := SystemTimeToDateTime(t.DaylightDate)
              else
                begin
                  dd := EncodeDate(Year, t.DaylightDate.wMonth, 1) - 1;
                  dd := dd + (t.DaylightDate.wDayOfWeek + 8 - DayOfWeek(dd))
                             mod 7 + (t.DaylightDate.wDay - 1) * 7;
                  DecodeDate(dd, y, Month, Day);
                  while Month > t.DaylightDate.wMonth do
                    begin
                      dd := dd - 7;
                      DecodeDate(dd, y, Month, Day);
                    end;
                  dd := dd + EncodeTime(t.DaylightDate.wHour,
                                        t.DaylightDate.wMinute,
                                        t.DaylightDate.wSecond,
                                        t.DaylightDate.wMilliseconds);
                end;
              if t.StandardDate.wYear <> 0 then
                ds := SystemTimeToDateTime(t.StandardDate)
              else
                begin
                  ds := EncodeDate(Year, t.StandardDate.wMonth, 1) - 1;
                  ds := ds + (t.StandardDate.wDayOfWeek + 8 - DayOfWeek(dd))
                             mod 7 + (t.StandardDate.wDay - 1) * 7;
                  DecodeDate(ds, y, Month, Day);
                  while Month > t.StandardDate.wMonth do
                    begin
                      ds := ds - 7;
                      DecodeDate(ds, y, Month, Day);
                    end;
                  dd := dd + EncodeTime(t.StandardDate.wHour,
                                        t.StandardDate.wMinute,
                                        t.StandardDate.wSecond,
                                        t.StandardDate.wMilliseconds);
                end;
              if (dd < d) and (d < ds) then
                d := d + t.DaylightBias / 24 / 60
              else
                d := d + t.StandardBias / 24 / 60;
              Zeit.Text :=
                Zeit.Text + ' ' + FormatDateTime('dd.mm.yyyy hh:nn:ss', d)
                + ' GMT';
            end;
        {$endif}
      end;
  end;
Gruß
Heiner
aus einem alten Diercke Weltatlas
aus einem alten Diercke Weltatlas
Zuletzt geändert von Heinrich Wolf am So 10. Jun 2012, 20:35, insgesamt 6-mal geändert.

Heinrich Wolf
Beiträge: 323
Registriert: Di 12. Apr 2011, 13:21
OS, Lazarus, FPC: WinXP + VMWare Player mit Fedora14, L 1.1, FPC 2.7.1
CPU-Target: 1core 1,8GHz 32Bit
Wohnort: Fürth
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT

Beitrag von Heinrich Wolf »

nach all den Ergänzungen am letzten Eintrag trigger ich mal den Versand einer Mail an die, welche den Thread beobachten.

gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von gocher »

Hallo Heinrich,

ich bin noch am tüfteln, meine Routine sieht gerade so aus:

Code: Alles auswählen

function FileTimeToGMT(const AFilename: string): string;
var
{$ifdef windows}
  fh : THandle;
  fs: TFormatSettings;
  wt: TFileTime;
  st: SYSTEMTIME;
  dt: TDateTime;
{$else}
  st: stat;
  tm: ptm;
{$endif}
begin
  result := '';
  if FileExists(AFilename) then
  begin
{$ifdef windows}
    fh := FileOpen(AFilename, fmOpenRead or fmShareDenyNone);
    try
      if fh > 0 then
        if GetFileTime(fh, nil, nil, @wt) then
        begin
          fs := DefaultFormatSettings;
          FillChar(st, SizeOf(st), 0);
          FileTimeToSystemTime(wt, st);
          dt := SystemTimeToDateTime(st);
          result := FormatDateTime('ddd, dd mmm yyyy  hh:nn:ss "GMT"', dt, fs);
        end;
    finally
      FileClose(fh);
    end;
{$else}
    if FpStat(AFilename, st) = 0 then
    begin
      tm := gmtime(@st.st_mtime);
      if tm <> Nil then
      begin
        setLength(result, 30);
        strftime(result, 30, '%a, %d %b %Y  %X GMT', tm);
      end;
    end;
{$endif}
  end;
end;
Unter Windows 7 klappt es, unter Unix kann ich es zur Zeit nicht testen!
Danke schon einmal für deine Infos!
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

Benutzeravatar
theo
Beiträge: 11350
Registriert: Mo 11. Sep 2006, 19:01

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von theo »

gocher hat geschrieben:Unter Windows 7 klappt es, unter Unix kann ich es zur Zeit nicht testen!
Naja, auf 64bit Linux geht das nicht, wegen der Abhängigkeit von LibC.

gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von gocher »

theo hat geschrieben:Naja, auf 64bit Linux geht das nicht, wegen der Abhängigkeit von LibC.
Naja, da liegt gerade mein Problem ich suche nach einer Lösung für Windows Server, Windows 7 und Linux sowohl für 32 als auch 64bit!
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

Heinrich Wolf
Beiträge: 323
Registriert: Di 12. Apr 2011, 13:21
OS, Lazarus, FPC: WinXP + VMWare Player mit Fedora14, L 1.1, FPC 2.7.1
CPU-Target: 1core 1,8GHz 32Bit
Wohnort: Fürth
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von Heinrich Wolf »

@gocher,
Hallo, wo ist denn bei Deinem neuen Windows Code die Umrechnung auf GMT? Er zieht bei jeder Zeit zwei Stunden von der deutschen Zeit ab. Aber welcher Befehl tut das? Und bei deutscher Winterzeit ist es falsch. Da darf er nur 1 Stunde abziehen. Ich hab in der Unit LibTar eine vielversprechende Funktion FileTimeGMT() gefunden. Aber die rechnet genauso falsch wie Dein neuer Code.

Nachträgliche Info:
Bei einer unveränderten Datei auf Windows bewirkt das Umstellen der Systemuhr um ein halbes Jahr, dass sich die Anzeige des Zeitstempels dieser Datei im Windows Explorer um 1 Stunde verändert! Das sehe ich als groben Fehler von Windows an. Mit dieser Erkenntnis kann man alle Umrechnungsversuche mit GetTimeZoneInformation vergessen und bei dem Code bleiben, den gocher am 6.6. um 22:46 gepostet hat oder lediglich FileTimeGMT verwenden.

@theo & all
Auch mich stört, dass die LibC nicht unter 64 Bit verfügbar ist, nicht nur in diesem Projekt. Aber auch 64 Bit braucht doch sicher den ptm Typen und mehr. Nur, was ist der Ersatz für die LibC?

Heiner
Zuletzt geändert von Heinrich Wolf am So 10. Jun 2012, 20:37, insgesamt 3-mal geändert.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von mse »

MSEgui hat localtimetoutc() und utctolocaltime() (lib/common/kernel/msedate.pas). Entsprechende Funktionen müssten doch auch für Lazarus/FCL/FPC-RTL zur Verfügung stehen? In der Mailinglist war mal die Rede davon.
Zudem benutzen die MSEgui File-Funktionen grundsätzlich UTC. In Lokalzeit wird lediglich zur Anzeige gewandelt falls gewünscht. Die Datum-Widgets haben eine Option, welche die Umwandlung aktiviert.

Martin

gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von gocher »

Heinrich Wolf hat geschrieben:@gocher,
Hallo, wo ist denn bei Deinem neuen Windows Code die Umrechnung auf GMT? Er zieht bei jeder Zeit zwei Stunden von der deutschen Zeit ab. Aber welcher Befehl tut das? Und bei deutscher Winterzeit ist es falsch. Da darf er nur 1 Stunde abziehen. Ich hab in der Unit LibTar eine vielversprechende Funktion FileTimeGMT() gefunden. Aber die rechnet genauso falsch wie Dein neuer Code.
Ich habe da was gefunden http://msdn.microsoft.com/en-us/library ... 85%29.aspx
eingebaut in meinem Code funktioniert das bei mir unter Windows 7

Code: Alles auswählen

FileTimeToSystemTime(wt, st);
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

Heinrich Wolf
Beiträge: 323
Registriert: Di 12. Apr 2011, 13:21
OS, Lazarus, FPC: WinXP + VMWare Player mit Fedora14, L 1.1, FPC 2.7.1
CPU-Target: 1core 1,8GHz 32Bit
Wohnort: Fürth
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von Heinrich Wolf »

Hallo,

wir haben nun einige Funktionen zusammengetragen, die Datei Zeitstempel in GMT liefern sollen. Allerdings tun einige nicht, was sie versprechen. Wenn ich zwei Zeitstempel in einem deutschen Windows Explorer sehe:
1. Jan 2012 11:00
1. Jun 2012 11:00
Dann müsste in GMT folgendes herauskommen:
1. Jan 2012 10:00
1. Jun 2012 9:00
Aber einige Funktionen, einschließlich FileTimeToSystemTime aus der Windows API liefern jetzt im Juni
1. Jan 2012 9:00
1. Jun 2012 9:00
Ich hab's nicht getestet, aber liefern die im Januar dann
1. Jan 2012 10:00
1. Jun 2012 10:00
?

Heiner

gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von gocher »

Hallo Heinrich,

also bei Dir unter Windows XP läuft also die Funktion FileTimeToSystemTime nicht richtig :( !
Das erklärt natürlich wieso ich mir vor ca. 5 Jahren die Arbeit gemacht habe diese lange Variante zu schreiben, da muss ich mir wohl doch noch die Arbeit machen systemabhängig die Berechnungsroutine einzuschalten denn wenn es unter Windows XP nicht läuft dann läuft es unter Windows Server 2003 auch nicht!
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

Heinrich Wolf
Beiträge: 323
Registriert: Di 12. Apr 2011, 13:21
OS, Lazarus, FPC: WinXP + VMWare Player mit Fedora14, L 1.1, FPC 2.7.1
CPU-Target: 1core 1,8GHz 32Bit
Wohnort: Fürth
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von Heinrich Wolf »

Heinrich Wolf hat geschrieben:Hallo,

wir haben nun einige Funktionen zusammengetragen, die Datei Zeitstempel in GMT liefern sollen. Allerdings tun einige nicht, was sie versprechen. Wenn ich zwei Zeitstempel in einem deutschen Windows Explorer sehe:
1. Jan 2012 11:00
1. Jun 2012 11:00
Dann müsste in GMT folgendes herauskommen:
1. Jan 2012 10:00
1. Jun 2012 9:00
...
Ich hab's nicht getestet, aber liefern die im Januar dann
1. Jan 2012 10:00
1. Jun 2012 10:00
?

Heiner
Ich hab grad mal zum Test meine Windows Uhr umgestellt auf Januar. Es kommt mit FileTimeToSystemTime genauso falsch raus wie ich befürchtet hab.

Nachträgliche Info:
Bei einer unveränderten Datei auf Windows bewirkt das Umstellen der Systemuhr um ein halbes Jahr, dass sich die Anzeige des Zeitstempels dieser Datei im Windows Explorer um 1 Stunde verändert! Das sehe ich als groben Fehler von Windows an.

Heiner
Zuletzt geändert von Heinrich Wolf am So 10. Jun 2012, 20:38, insgesamt 2-mal geändert.

gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von gocher »

So nun noch einmal geändert, leider ergibt die Kombination aus FileAge & FileDateToDateTime nicht das Lokale Datum/Zeit, sondern ist abhängig davon in welcher Zeit man sich aktuell befindet. Der folgende Code funktioniert wieder unter Windows 7!

Code: Alles auswählen

{$ifdef windows}
  tsRFC = 'ddd, dd mmm yyyy  hh:nn:ss "GMT"';
  tsISO = 'yyyy"-"mm"-"dd"T"hh":"nn":"ss"+00:00"';
{$else}
  tsRFC = '%a, %d %b %Y  %X GMT';
  tsISO = '%Y-%B-%dT%X+00:00';
{$endif}
 
function LocalTimeToGMTTime(const LocalTime: TDateTime; RefTime: TDateTime = 0): TDateTime;
var
  TZInfo: TTimeZoneInformation;
  iBias: integer;
begin
  if RefTime = 0 then RefTime := LocalTime;
  GetTimeZoneInformation(TZInfo);
  iBias := TZInfo.Bias + TZInfo.StandardBias;
  case MonthOf(RefTime) of
    3: if LocalTime >= EndOfTheWeek(EndOfTheMonth(Now)-7) then
       iBias := TZInfo.Bias + TZInfo.DaylightBias;
    4,5,6,7,8,9:
       iBias := TZInfo.Bias + TZInfo.DaylightBias;
    10: if LocalTime < EndOfTheWeek(EndOfTheMonth(Now)-7) then
       iBias := TZInfo.Bias + TZInfo.DaylightBias;
  end;
  result := LocalTime + (iBias / 1440);
end;
 
function FileTimeToGMT(const AFilename: string; const frmtstr: string = tsRFC): string;
var
{$ifdef windows}
  fs: TFormatSettings;
  wt: integer;
  dt: TDateTime;
{$else}
  st: stat;
  tm: ptm;
{$endif}
begin
  result := '';
  if FileExists(AFilename) then
  begin
{$ifdef windows}
    wt := FileAge(AFilename);
    if wt > 0 then
    begin
      fs := DefaultFormatSettings;
      dt := FileDateToDateTime(wt);
      dt := LocalTimeToGMTTime(dt, Now());
      result := FormatDateTime(frmtstr, dt, fs);
    end;
{$else}
    if FpStat(AFilename, st) = 0 then
    begin
      tm := gmtime(@st.st_mtime);
      if tm <> nil then
      begin
        if frmtstr = tsRFC then
          setLength(result, 30)
        else if frmtstr = tsISO then
          strftstr(result, 25);
        strftime(result, length(result), frmtstr, tm);
      end;
    end;
{$endif}
  end;
end;
Und dies wäre dann der Code um ein korrektes Datum zu wandeln, also z.B. Now().

Code: Alles auswählen

function DateTimeToGMT(const Adt: TDateTime; const frmtstr: string = tsRFC): string;
var
  fs: TFormatSettings;
  dt: TDateTime;
begin
  fs := DefaultFormatSettings;
  dt := LocalTimeToGMTTime(Adt);
  result := FormatDateTime(frmtstr, dt, fs);
end;
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

Heinrich Wolf
Beiträge: 323
Registriert: Di 12. Apr 2011, 13:21
OS, Lazarus, FPC: WinXP + VMWare Player mit Fedora14, L 1.1, FPC 2.7.1
CPU-Target: 1core 1,8GHz 32Bit
Wohnort: Fürth
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von Heinrich Wolf »

Hi,

@gocher
mit Deinem letzten Code ist der Zeitraum für Sommerzeit aber immer noch hart codiert und nicht aus GetTimeZoneInformation übernommen. Das ergibt falsche Ergebnisse für nicht-deutsche Regionen oder Jahre vor 1995.

@all
Unix Betriebssystemaufrufe liefern die Zeitstempel als GMT. Das ist eindeutig. Zur Anzeige müssen die Zeitstempel umgerechnet werden. Dafür gibt es die localtime() Funktion. Unix benutzt dazu pro Region eine Datei mit einer Liste aller Zeitumstellungen. Ich biete auf meiner Download Seite eine Pascal Unit für Delphi und Lazarus (Linux und Windows) an, mit denen Zeitberechnungen (GMT/Localtime Umwandlung, Feiertage, Mondphasen, ...) möglich sind: http://www.Wolf-Fuerth.de/deltime.zip Dabei ist u.a. ein "tzfile" Demo Programm, welches bei Unix die Zeitumstellungsdatei ausliest. Den interessantesten Teil von dessen Ausgabe aus meinem deutschen Linux habe ich als Dateianhang hier hochgeladen. Man sieht darin, dass die Sommerzeit in den 90er Jahren nicht bis Oktober, sondern nur bis September dauert und dass es in den Kriegsjahren eine doppelte Sommerzeit gab (4 Zeitumstellungen im Jahr).

Bei einer unveränderten Datei auf Windows bewirkt das Umstellen der Systemuhr um ein halbes Jahr, dass sich die Anzeige des Zeitstempels dieser Datei im Windows Explorer um 1 Stunde verändert! Das sehe ich als groben Fehler von Windows an. Windows berechnet also den BIAS falsch auf Basis der aktuellen Zeit und nicht richtig auf Basis der umzurechnenden Zeit. Bei Umstellung der Uhr z.B. auf das Jahr 1990 verwendet GetTimeZoneInformation außerdem dieselben Sommerzeitparameter, was falsch ist. Meine deltime Unit (Link siehe oben) bietet eine Prozedur GetDayLightDates an, welche zum Jahr bis zu 4 Zeitumstellungen liefert und die Abweichungen im deutschsprachigen Raum vor dem Jahr 1995 berücksichtigt.

Heiner
Dateianhänge
Sommerzeit.txt
(8.07 KiB) 134-mal heruntergeladen
Zuletzt geändert von Heinrich Wolf am So 10. Jun 2012, 20:41, insgesamt 2-mal geändert.

gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Re: Windows & Linux Unabhängig Filetime als GMT String

Beitrag von gocher »

Tja, da habe ich doch mal einfach die Routine umgestellt und in meine Funktion eingebaut und bei mir unter Windows 7 liefert sie falsche Werte :( !
Oder ist da noch ein Fehler ?

Code: Alles auswählen

function LocalTimeToGMTTime(const LocalTime: TDateTime; RefTime: TDateTime = 0): TDateTime;
var
  t: TTimeZoneInformation;
  dd, ds: TDateTime;
  Year, Month, Day, y: Word;
begin
  result := LocalTime;
  if GetTimeZoneInformation(t) <> $FFFFFFFF then
  begin
    DecodeDate(result, Year, Month, Day);
    result := result + t.Bias / 24 / 60;
 
    if t.DaylightDate.wYear <> 0 then
      dd := SystemTimeToDateTime(t.DaylightDate)
    else
    begin
      dd := EncodeDate(Year, t.DaylightDate.wMonth, 1) - 1;
      dd := dd + (t.DaylightDate.wDayOfWeek + 8 - DayOfWeek(dd))
                      mod 7 + (t.DaylightDate.wDay - 1) * 7;
      DecodeDate(dd, y, Month, Day);
      while Month > t.DaylightDate.wMonth do
      begin
        dd := dd - 7;
        DecodeDate(dd, y, Month, Day);
      end;
      dd := dd +
        EncodeTime(t.DaylightDate.wHour, t.DaylightDate.wMinute,
                   t.DaylightDate.wSecond, t.DaylightDate.wMilliseconds);
    end;
    if t.StandardDate.wYear <> 0 then
      ds := SystemTimeToDateTime(t.StandardDate)
    else
    begin
      ds := EncodeDate(Year, t.StandardDate.wMonth, 1) - 1;
      ds := ds + (t.StandardDate.wDayOfWeek + 8 - DayOfWeek(dd))
                    mod 7 + (t.StandardDate.wDay - 1) * 7;
      DecodeDate(ds, y, Month, Day);
      while Month > t.StandardDate.wMonth do
      begin
        ds := ds - 7;
        DecodeDate(ds, y, Month, Day);
      end;
      dd := dd +
        EncodeTime(t.StandardDate.wHour, t.StandardDate.wMinute,
                   t.StandardDate.wSecond, t.StandardDate.wMilliseconds);
     end;
     if (dd < result) and (result < ds) then
       result := result + t.DaylightBias / 24 / 60
     else
       result := result + t.StandardBias / 24 / 60;
  end;
end;
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

Antworten