2011-07-11 13 views
17

można przekonwertować do formatu Delphi TDate ISO 8601 łatwo za pomocą tego:Jak przekonwertować ciąg ISO 8601 na Delphi TDate?

DateTimeToString(result, 'yyyy-mm-dd', myDate); 

Jaka jest idiomatyczne sposób na konwersję odwrotną? StringToDateTime() wydaje się nie istnieć.

Oczywiście można zrobić to „twarde” droga przez ręcznie analizowania ciąg i kodowania wynik, ale to wydaje się być złym wyborem.

+0

możliwe duplikat [Konwersja ciąg TDateTime na podstawie dowolnego formatu] (http://stackoverflow.com/questions/3786823/converting-a-string-to-tdatetime-based-on- format-arbitralny) – NGLN

Odpowiedz

15

Po co wynajdować koło?

XML używa ISO 8601 do przechowywania daty i daty.

Delphi miał wbudowaną obsługą że od Delphi 6 w jednostce XSBuiltIns.

This answer explains how dla DateTime, to dla Data tylko przy użyciu klasę TXSDate:

with TXSDate.Create() do 
    try 
    AsDate := Date; // convert from TDateTime 
    DateString := NativeToXS; // convert to WideString 
    finally 
    Free; 
    end; 

with TXSDate.Create() do 
    try 
    XSToNative(DateString); // convert from WideString 
    Date := AsDate; // convert to TDateTime 
    finally 
    Free; 
    end; 
7

Myślę, że to powinno działać ... Dokumentacja mówi, że przeciążona wersja tych metod jest do wykorzystania w wątkach, ale może być przydatna do określenia ustawień formatu, które chcesz użyć w tym czasie.

Function ISO8601ToDateTime(Value: String):TDateTime; 
var 
    FormatSettings: TFormatSettings; 
begin 
    GetLocaleFormatSettings(GetThreadLocale, FormatSettings); 
    FormatSettings.DateSeparator := '-'; 
    FormatSettings.ShortDateFormat := 'yyyy-MM-dd'; 
    Result := StrToDate(Value, FormatSettings); 
end; 

Można oczywiście warianty zapisu z tego z StrToDateDef i TryStrToDate o równorzędnej funkcjonalności

+3

Możesz także zainicjować ustawienia formatów, z domyślnym systemem. Zależnie od tego, czy zamierzasz używać go do czegoś innego poza parsowaniem dat: 'GetLocaleFormatSettings (LOCALE_SYSTEM_DEFAULT, FormatSettings);' wypełnia rekord FormatSettings z domyślnymi ustawieniami systemowymi. –

+0

@Roald, Dzięki ..Właśnie przeprowadziłem kilka testów! Zaktualizuję go za chwilę. –

+2

Zdecydowanie użyj przeciążonych wersji "wątkowych", w przeciwnym razie zmienisz sposób, w jaki aplikacja wyświetla daty, jeśli używasz DateToStr lub FormatDateTime z "c" lub "ddddd" lub cokolwiek innego, co używa ShortDateFormat. –

7

można znaleźć Iso-8601 procedur konwersji w naszym SynCommons unit.

Został głęboko zoptymalizowany pod kątem szybkości, więc jest znacznie szybszy niż funkcje DateTimeToString() i takie, ale oczywiście kod jest trudniejszy do naśladowania. ;)

procedure Iso8601ToDateTimePUTF8CharVar(P: PUTF8Char; L: integer; var result: TDateTime); 
var i: integer; 
    B: cardinal; 
    Y,M,D, H,MI,SS: cardinal; 
// we expect 'YYYYMMDDThhmmss' format but we handle also 'YYYY-MM-DD hh:mm:ss' 
begin 
    result := 0; 
    if P=nil then 
    exit; 
    if L=0 then 
    L := StrLen(P); 
    if L<4 then 
    exit; // we need 'YYYY' at least 
    if P[0]='T' then 
    dec(P,8) else begin 
    B := ConvertHexToBin[ord(P[0])]; // first digit 
    if B>9 then exit else Y := B; // fast check '0'..'9' 
    for i := 1 to 3 do begin 
     B := ConvertHexToBin[ord(P[i])]; // 3 other digits 
     if B>9 then exit else Y := Y*10+B; 
    end; 
    if P[4] in ['-','/'] then begin inc(P); dec(L); end; // allow YYYY-MM-DD 
    D := 1; 
    if L>=6 then begin // YYYYMM 
     M := ord(P[4])*10+ord(P[5])-(48+480); 
     if (M=0) or (M>12) then exit; 
     if P[6] in ['-','/'] then begin inc(P); dec(L); end; // allow YYYY-MM-DD 
     if L>=8 then begin // YYYYMMDD 
     D := ord(P[6])*10+ord(P[7])-(48+480); 
     if (D=0) or (D>MonthDays[true][M]) then exit; // worse is leap year=true 
     end; 
    end else 
     M := 1; 
    if M>2 then // inlined EncodeDate(Y,M,D) 
     dec(M,3) else 
    if M>0 then begin 
     inc(M,9); 
     dec(Y); 
    end; 
    with Div100(Y) do 
     result := (146097*YDiv100) shr 2 + (1461*YMod100) shr 2 + 
      (153*M+2) div 5+D-693900; 
    if (L<15) or not(P[8] in [' ','T']) then 
     exit; 
    end; 
    H := ord(P[9])*10+ord(P[10])-(48+480); 
    if P[11]=':' then inc(P); // allow hh:mm:ss 
    MI := ord(P[11])*10+ord(P[12])-(48+480); 
    if P[13]=':' then inc(P); // allow hh:mm:ss 
    SS := ord(P[13])*10+ord(P[14])-(48+480); 
    if (H<24) and (MI<60) and (SS<60) then // inlined EncodeTime() 
    result := result + (H * (MinsPerHour * SecsPerMin * MSecsPerSec) + 
      MI * (SecsPerMin * MSecsPerSec) + SS * MSecsPerSec)/MSecsPerDay; 
end; 

ten jest w stanie obsłużyć bardzo szybką przemianę z UTF-8 buforze do TDateTime. Dla wszystkich zależności stałych sprawdź kod źródłowy urządzenia.

+0

Typowy. W każdym razie używam synaps, ale nigdy nie zdawałem sobie sprawy, że to jest włączone :-) – Roddy

+4

Ta funkcja nie jest w pełni zgodna z ISO8601. Specyfikacja mówi o użyciu "T" jako separatora między ciągami daty i czasu. Pominięcie go jest dozwolone tylko za obopólną zgodą. Po drugie nie ma wsparcia dla wskazania strefy czasowej na końcu łańcucha, co jest wymagane przez wiele usług internetowych. –

6

Dla większej elastyczności, można rozważyć Marco van de Voort „s scandate routine który obsługuje swój ciąg w dowolnym formacie:

var 
    D: TDateTime; 
begin 
    D := ScanDate('yyyy-mm-dd', '2011-07-11'); 

Zobacz final version (7KB .zip) dodany do FPC.

+2

Angielski ostateczny nie jest równy holenderskiemu "definitief". W tym kontekście holenderska "wersja ostateczna" jest lepiej tłumaczona jako "wersja ostateczna". "Wersja ostateczna" jest bardziej podobna do stwierdzenia "ostateczna" wersja ... Potem znowu, być może miałeś zamiar powiedzieć :-)) –

+0

@Marjan dankje ...;) – NGLN

+0

Zawsze chętnie pomogę innemu krajowi (wo)mężczyźni –

1
USES Soap.XSBuiltIns; 
... 
Function XMLDateTimeToLocalDateTime(const Value: String): TDateTime; 
begin 
    with TXSDateTime.Create do 
    try 
    XSToNative(Value); 
    result := AsDateTime; 
    finally 
    Free; 
    end; 
end; 

Delphi XE3

Powiązane problemy