Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi VarToDateTime mit englischem Datum (https://www.delphipraxis.net/165759-vartodatetime-mit-englischem-datum.html)

FunThomas 14. Jan 2012 20:20

VarToDateTime mit englischem Datum
 
Hallo,

ich habe nen kleines Problem beim Einlesen eines Datums. Ich versuche ein Datum z.B '29 Dec 2011' auf einem deutschem System in einen TDateTime zu wandeln.
das klappt soweit ganz gut für Datumsangaben mit Monat Jan (ist im engl identisch) allerdings wenn ich folgendes Beispiel nehme schläg es schon fehl

Code:
var
  myDate : TDateTime;

  Datum  : string;
  neues_datumsformat : TFormatSettings;

begin
  GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, orginales_datumsformat);
  orginales_datumsformat.ShortDateFormat := 'dd mmm yyyy';
  orginales_datumsformat.LongDateFormat := 'dd mmm yyyy';
  orginales_datumsformat.DateSeparator := ' ';
  myDate := VarToDateTime('29 Dec 2011');
end;
Gibt es da irgendeine Möglichkeit dieses Datumsformat vernünftig einzulesen ?

Gruß,
Thomas

Sir Rufo 14. Jan 2012 21:11

AW: VarToDateTime mit englischem Datum
 
Du beschreibst doch schon die Ursache.

Du konvertierst immer noch mit den deutschen Monats-Abkürzungen (weil deutsches System).
Hol dir doch die englischen/amerikanischen FormatSettings und nicht die vom System.

implementation 14. Jan 2012 21:35

AW: VarToDateTime mit englischem Datum
 
Zur Not mach's so:
Delphi-Quellcode:
function ConvertDate(const str: string): TDate;
var i: byte; d, m, y: word; mn: string;
const months: array[1..12] of string = ('jan','feb','mar','apr','may',
               'jun','jul','aug','sep','oct','nov','dec');
  procedure Next;
  begin
    Inc(i);
  end;
  function GetNum: word;
  begin
    Result := 0;
    while str[i] in ['0'..'9'] do begin
      Result := Result*10 + Ord(str[i]) - Ord('0');
      Next;
    end;
  end;
  procedure SkipWhite;
  begin
    while str[i] in [#9,#32] do Next;
  end;
  function GetName: string;
  begin
    Result := '';
    while str[i] in ['a'..'z','A'..'Z'] do begin
      if str[i] in ['a'..'z'] then
        Result := Result + str[i]
      else Result := Result + Chr(Ord(str[i])-Ord('A')+Ord('a'));
      Next;
   end;
  end;
begin
  i := 1;
  d := GetNum;
  SkipWhite;
  mn := GetName;
  SkipWhite;
  y := GetNum;
  for i := 1 to 12 do
    if months[i]=mn then
      m := i;
  if not TryEncodeDate(y,m,d,result) then
    raise EConvertError.Create('Invalid date');
end;

himitsu 14. Jan 2012 22:48

AW: VarToDateTime mit englischem Datum
 
Wieso den Umweg über Delphi-Referenz durchsuchenVarToDateTime, oder hast du etwas gegen Delphi-Referenz durchsuchenStrToDateTime?

Du ließt die Systemwerte in orginales_datumsformat ein und veränderst diese Variable.
Gefunden hab ich aber nur die Deklaration für neues_datumsformat. :gruebel:

Außerdem setzt du nirgendwo die geänderten Werte, bzw. weißt sie nirgends zu, so daß sie verwendet werden könnten.

PS: StrToDateTime kann man die FormatSettings auch direkt mitgeben, ohne sie (programm)global ändern zu müssen.


@implementation: Man kann (zumindestens in Delphi funktioniert es ganz gut) auch vorhandene Funktionen nutzen und muß nicht unbedingt alles selber machen. :zwinker:
Man muß nur eben die richtigen Funktionen nutzen, bzw. den verwendeten Funktionen auch dir richtigen Einstellungen geben.

Also noch auf Sir Rufo hören oder zumindestens die FormatSettings selber befüllen.
(LOCALE_SYSTEM_DEFAULT = aktuelle Systemeinstellung, aber alternativ kann man nur was auslesen, welches auch installiert ist, also nicht unbedingt blind drauf verlassen, daß es andere Sprachen überhaupt gibt.)

implementation 14. Jan 2012 23:26

AW: VarToDateTime mit englischem Datum
 
Zitat:

Zitat von himitsu (Beitrag 1146006)
@implementation: Man kann (zumindestens in Delphi funktioniert es ganz gut) auch vorhandene Funktionen nutzen und muß nicht unbedingt alles selber machen. :zwinker:

Kann man? :oops:

Delphi-Quellcode:
while not HinterDieOhrenGeschrieben do Writeln('Ich werde von nun an alles über die RTL machen.');


Ich benutz' normal nichtmal TList, hab 'ne eigene Alternative. So, und jetzt steinigt mich!

FunThomas 15. Jan 2012 10:32

AW: VarToDateTime mit englischem Datum
 
Hi Leute,
sorry dass ich nicht so ein Delphi-Crack bin wie Ihr :)
Ich probiere hier leider rum und kriege das leider nicht hin, der meckert jedesmal dass es kein gültiges Datum ist :(
Wenn ich z.B.
Code:
        GetLocaleFormatSettings(2057, orginales_datumsformat);
        orginales_datumsformat.ShortDateFormat := 'dd mmm yyyy';
        orginales_datumsformat.LongDateFormat := 'dd mmm yyyy';
        orginales_datumsformat.DateSeparator := ' ';
        myDate := StrToDateTime('29 Dec 2011',orginales_datumsformat);
funktioniert das ganze nicht obwohl die orginales_datumsformat.ShortMonthNames[12] = 'Dec' ist.
Falls einer nen Tip hat wieso dann würde ich mich darüber freuen.

kann mir eigentlich jemand sagen wo ich die Konstantennamen für LOCALE_SYSTEM_DEFAULT und die einzelnen Länder finde ? Die Hilfen zeigen mir nur den Typ aber die Konstanten sind leider nirgends aufgeführt. Ich habe jetzt nur bei Microsoft die LCID 2057 für en-UK gefunden, ist aber blöd eine Zahlenkonstante in seinem Progrämmchen zu verwenden.

Wenn ich jetzt über den Umweg
Code:
myDate := VarToDateTime('29 Dec 2011');
gehe passen meine lokalen Settings nicht -> mit welcher Funktion kann ich die auf z.B. en-UK ändern ?

Gruß,
Thomas

Sir Rufo 15. Jan 2012 11:57

AW: VarToDateTime mit englischem Datum
 
  1. Also die Werte bekommt man von Microsoft (die haben ja auch Windows gebaut, also wissen die das auch am besten ;) )
  2. Wenn du dir mal Delphi-Referenz durchsuchenTFormatSettings im Quelltext (oder auch Online-Hilfe) anschaust, stellst du fest, da gibt es auch einen Constructor. Mal schauen, was der so zu bieten hat ... oha, da gibt es ja sogar 3 Varianten Delphi-Referenz durchsuchenTFormatSettings.Create und eine besagt, dass auch dieses möglich ist
    Delphi-Quellcode:
    TFormatSettings.Create( 'en-US' );
Aha, geht ja schon mal ganz einfach.

Jetzt mal zu Delphi-Referenz durchsuchenVarToDateTime und Delphi-Referenz durchsuchenStrToDateTime
Die Online-Hilfe lässt einen hier ein wenig im Regen stehen, so dass man hier auf den Quelltext angewiesen ist.

Delphi-Quellcode:
StrToDateTime
ist eine Pascal-Funktion, die z.B. erhebliche Schwierigkeiten hat, wenn man als Trennzeichen ein Leerzeichen nimmt.
Diese Funktion wird innerhalb von StrToDateTime aufgerufen und entfernt alle Leerzeichen, bis das Trennzeichen gefunden wird ;)
Delphi-Quellcode:
function ScanChar(const S: string; var Pos: Integer; Ch: Char): Boolean;
begin
  Result := False;
  ScanBlanks(S, Pos);
  if (Pos <= Length(S)) and (S[Pos] = Ch) then
  begin
    Inc(Pos);
    Result := True;
  end;
end;
Delphi-Quellcode:
VarToDateTime
ist da etwas anders aufgebaut und ruft - nach einigem Hin- und Hergewurschtel - folgendes auf
Delphi-Quellcode:
  VarDateFromStr: function(const strIn: WideString; LCID: DWORD; dwFlags: Longint;
    out dateOut: TDateTime): HRESULT; stdcall;
Es sieht komisch aus, liegt aber daran, dass hier eine Variable definiert wird, die eine DLL-Funktion aufruft. Die DLL wird per LateBinding eingebunden.

Schlussendlich wird also eine Windows-Funktion für die Konvertierung bemüht.

Interessant ist der Parameter
Delphi-Quellcode:
LCID: DWORD
. Diese Funktion kann also auch je nach LCID entsprechend reagieren ... warum macht die das also nicht?

Der Grund liegt hier, da irgendwann innerhalb von VarToDateTime einmal diese Funktion aufgerufen wird:
Delphi-Quellcode:
function VarToDateAsString(const V: TVarData): TDateTime;
var
  S: WideString;
  D: Double;
  LResult: HResult;
begin
  _VarToWStr(S, V);
  LResult := VarDateFromStr(S, VAR_LOCALE_USER_DEFAULT, 0, Result);
  case LResult of
    VAR_OK:; // in this case the OS function has put the value into result
    VAR_TYPEMISMATCH:
      if not TryStrToDate(S, Result) then
        if TryStrToFloat(S, D) then
          Result := D
        else
          VarResultCheck(VAR_TYPEMISMATCH, V.VType, varDate);
  else
    VarResultCheck(LResult, V.VType, varDate);
  end;
end;
Es gibt auch - soweit ich das überschauen kann - keine überladene Funktion, wo man die gewünschte LCID übergeben kann.

Die Lösung besteht darin, z.B. direkt die Funktion aufzurufen:
Delphi-Quellcode:
function APIStrToDateTime( const S : WideString; LCID : Cardinal ) : TDateTime;
var
  LResult : HResult;
begin
  if VarDateFromStr( S, LCID, 0, Result ) <> VAR_OK
  then
    raise EConvertError.CreateFmt( '"%s" ist kein gültiges Datum', [S] );
end;

procedure TForm1.Button1Click( Sender : TObject );
begin
  ShowMessage( DateToStr( APIStrToDateTime( '15 Dec 2012', 1033 ) ) );
end;

FunThomas 15. Jan 2012 12:11

AW: VarToDateTime mit englischem Datum
 
Besten Dank für die umfangreiche Antwort aber darauf wäre ich bestimmt nicht alleine gekommen :)

Da hätte ich mir eher ne suchen & ersetzen Routine gebaut die das in Zahlen konvertiert und dann das über Standard erledigt *g*

Besten Dank !:thumb:

himitsu 15. Jan 2012 14:01

AW: VarToDateTime mit englischem Datum
 
StrToDateTime wäre eh nicht gegangen.
Das versucht ja Datum und Zeit zu lesen, aber wenn es keine Zeit gibt, dann wäre StrToDate besser.

Aber ich seh auch grade, daß dieses wirklich mit ' ' Probleme hat und es ist auch sooo doof, daß es mit Wörtern nicht klar kommt, da alle Werte nur als Zahlen ausgelesen werden. :shock:

Mir fällt auch auf, daß ich bis jetzt immer zufällig ein Trennzeichen drin hatte und auch nur Zahlen. :opps:

Schon komisch, daß das so noch nicht aufgefallen und schon lange behoben ist, wo doch im englischen (amerikanischen) Datumssystem standardmäßig "dd mmmm yyyy" vorkommt, also Wort+Leerzeichen. :wall:

implementation 15. Jan 2012 16:45

AW: VarToDateTime mit englischem Datum
 
Zitat:

Zitat von himitsu (Beitrag 1146050)
Schon komisch, daß das so noch nicht aufgefallen und schon lange behoben ist, wo doch im englischen (amerikanischen) Datumssystem standardmäßig "dd mmmm yyyy" vorkommt, also Wort+Leerzeichen. :wall:

Manchmal ist selberschreiben eben doch die bessere Option :mrgreen:


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:37 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