Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Konvertierung UnixTimeStamp nacht TDateTime und zurück (https://www.delphipraxis.net/196625-konvertierung-unixtimestamp-nacht-tdatetime-und-zurueck.html)

Ghostwalker 5. Jun 2018 03:58

Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
Moinmoin,

im Rahmen eines Projektes brauch ich die Umrechnung von TDatetime-Werten nach UnixTimeStamp und zurück. Das ganze aber manuell ohne Dateutils. Da die Funktionen aus der Codelib Hier, nicht so wirklich funktionieren (erstens wird von der Deutschen Zeitzone ausgegangen, 2 wird der Zeitteil nicht wirklich korrekt berechnet), hab ich mich dazu entschlossen, das ganze selbst um zusetzen.

Die Umrechnung eines TDatetime-Wertes zu einem Unixtimestamp funktioniert auch schon:
Delphi-Quellcode:
const
  cSecPerDay = 86400;
  cMSecPerDay = 86400000;
  cDelphiEpoche = -2209161600; //30.12.1899 als UTS

function DateTimeToUnixtimestamp(const value:TDateTime):Int64;
var
  TimePart : extended;
  Zeit : int64;
  datum: int64;

begin
  zeit := Trunc(Abs(Frac(value))*cSecPerDay); //Zeitanteil in Sekunden
  timepart := frac(Abs(Frac(value))*cMSecPerDay); //Millisekunden
  datum := trunc(int(value)*cSecPerDay); //Anzahl der Tage mit Bezug Delphi-Epoche in Sekunden
  result := cDelphiEpoche+(datum+zeit);
  if (timepart > 0.5) then //Korrektur bei 500+ Millisekunden
    inc(result);
end;
Leider will die Umkehrfunktion (also von Unixtimestamp nach TDatetime) nicht so wirklich funktionieren.

Delphi-Quellcode:
function UnixTimeStampToDateTime(const value:int64):TDateTime;
var
  datum    : int64;
  base,rest    : int64;
  zeit,timepart      : Extended;

  base := cDelphiEpoche - value;
  datum := base DIV cSecPerDay;
  rest := base MOD cSecPerDay;
  timepart := cMSecPerDay/ABS(rest);
  zeit := cSecPerDay/Abs(rest);
  if (Frac(abs(Timepart))>0.5) then
    zeit := cSecPerDay/(base - (datum*cSecPerday))+1;
  result := datum+zeit;
end;
Ein Unterschied von 1 sek (+/-) wär ok, da ein Unixtimestamp keine Millisekunden berücksichtigt. Leider bekomme ich aber Unterschieder von teilweise mehreren Tagen.

Kann mir da jemand auf die Sprünge helfen ?


Anmerkung: Das ganze sollte sowohl mit positiven als auch negativen Werten klarkommen.

samso 5. Jun 2018 06:53

AW: Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
Die Zeitzone würde ich gesondert behandeln. D.h. ich würde den Datetimewert vor der Konvertierung in UTC umrechnen und dann in die Unixtimestamp umrechnen. Im umgekehrten Fall würde ich den berechneten Datetimewert wieder in lokale Zeit umrechnen, falls das erforderlich sein sollte. Hier mein Vorschlag für die Umrechnung von UTC-Datetimewerte in die Unixtimestamp und zurück (nur grob mit einigen Testdaten von https://www.freeformatter.com/epoch-...converter.html getestet):

Delphi-Quellcode:
uses
  System.SysUtils;
(*
{ Days between TDateTime basis (12/31/1899) and Unix time_t basis (1/1/1970) }

  UnixDateDelta = 25569;
*)

function UnixTimeToDatetime(UnixTime: Int64): TDatetime;
begin
  Result := UnixTime/SecsPerDay + UnixDateDelta;
end;

function DatetimeToUnixTime(Datetime: TDatetime): Int64;
var
  t: TDatetime;
begin
  t := Datetime - UnixDateDelta;
  if t>=0
  then
    Result := trunc(t*SecsPerDay + 0.5)
  else
    Result := trunc(t*SecsPerDay - 0.5);
end;

KodeZwerg 5. Jun 2018 07:29

AW: Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
Warum nicht die Funktionen aus DateUtils.pas verwenden?

Delphi-Quellcode:
uses nichts;

const
  UnixDateDelta = 25569;
  SecsPerDay   = 86400;


function DateTimeToUnix(const AValue: TDateTime): Int64;
begin
  Result := Round((AValue - UnixDateDelta) * SecsPerDay);
end;

function UnixToDateTime(const AValue: Int64): TDateTime;
begin
  Result := AValue / SecsPerDay + UnixDateDelta;
end;

Ghostwalker 5. Jun 2018 07:47

AW: Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
@samso

Nah drann.

Bei den (Test)-Daten hauts nicht hin:

So, 23.08.1733 18:33:44
-60759,7734259259
-7458672376

Bei DateTimeToUnix fehlen 2 Sekunden. Bei UnixToDateTime mehr als ein Tag. :)

@KodeZwerk
Das ganze soll möglichst unabhängig von anderen (auch Delphi-Eigenen) Units laufen.

btw leided deine Variante unter dem gleichen Problem wie Samso's

KodeZwerg 5. Jun 2018 07:48

AW: Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
Zitat:

Zitat von KodeZwerg (Beitrag 1403909)
Delphi-Quellcode:
uses nichts;

Wieviel mehr kann man denn unabhängig sein? Nja egal, bin raus.

Ghostwalker 5. Jun 2018 08:15

AW: Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
@KodeZwerg
Da ich die Starter verwende hab ich keine .pas zu den Delphiegenen Units :)

Lustig ist nur, das die von dir gepostet variante bei oben genannten Datum das gleiche fehlerhafte
Ergebnis liefert.

Die orginal Funktion dagegen haut hin.

So wie es aussieht hackt es bei Daten vor dem 30.12.1899 00:00:00 (also der "Delphi-Epoche")

KodeZwerg 5. Jun 2018 08:20

AW: Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
Wenn man sich die SysUtils.pas anschaut, vielleicht ist das von Bedeutung für Dein Problem.
Delphi-Quellcode:
{ Days between 1/1/0001 and 12/31/1899 }

  DateDelta = 693594;

{ Days between TDateTime basis (12/31/1899) and Unix time_t basis (1/1/1970) }

  UnixDateDelta = 25569;

KodeZwerg 5. Jun 2018 08:22

AW: Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
Zitat:

Zitat von Ghostwalker (Beitrag 1403914)
Da ich die Starter verwende hab ich keine .pas zu den Delphiegenen Units

Was ich oben schrieb war/ist Original Code von DateUtils.pas aus Delphi 2009.

samso 5. Jun 2018 08:27

AW: Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
Ja, das 1899-Problem habe ich nun auch erkannt. Das sollte schon mal besser sein:
Delphi-Quellcode:
function DatetimeToUnixTime(Datetime: TDatetime): Int64;
var
  t: TDatetime;
begin
  if Datetime<0
  then
    t := trunc(Datetime) - frac(Datetime) - UnixDateDelta
  else
    t := Datetime - UnixDateDelta;
  if t>0
  then
    Result := trunc(t*SecsPerDay + 0.5)
  else
    Result := trunc(t*SecsPerDay - 0.5);
end;
Für DateTimeToUnix habe ich noch keine kompakte Lösung.

Ghostwalker 5. Jun 2018 08:57

AW: Konvertierung UnixTimeStamp nacht TDateTime und zurück
 
Naja...DateTimeToUnix tut ja so:

Delphi-Quellcode:
var
  Zeit : int64;
  datum: int64;

begin
  zeit := Trunc((Abs(Frac(value))*cSecPerDay)+0.5); //Zeitanteil in Sekunden
  datum := trunc(int(value)*cSecPerDay); //Anzahl der Tage mit Bezug Delphi-Epoche in Sekunden
  result.fvalue := cDelphiEpocheUT+(datum+zeit);
end;
auch bei Daten vor 31.12.1899.

Nur die UnixTimeStamp nach TDateTime leidet hier unter dem 1899'er problem.

Ich probier grad, ob ich mit der Info von KodeZwerk hinsichtlich DateDelta was rauskrieg.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:53 Uhr.
Seite 1 von 3  1 23      

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