How do I convert an ISO 8601 string to a Delphi TDate?

前端 未结 7 1388
北海茫月
北海茫月 2020-12-06 05:09

I can convert a Delphi TDate to ISO 8601 format easily using this:

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

What\'s the idiomatic

相关标签:
7条回答
  • 2020-12-06 05:23

    Starting with XE6 you can use function System.DateUtils.ISO8601ToDate:

    uses
      System.DateUtils;
    var
      vDat: TDateTime;
    begin
      vDat := ISO8601ToDate('2018-03-26T11:01:35.867Z');
    end.
    
    0 讨论(0)
  • 2020-12-06 05:26
    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

    0 讨论(0)
  • 2020-12-06 05:27

    You can find Iso-8601 conversion routines in our SynCommons unit.

    It has been deeply optimized for speed, so it's much faster than the DateTimeToString() functions and such, but of course, code is more difficult to follow. ;)

    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;
    

    This is able to handle a very fast conversion from an UTF-8 encoded buffer into a TDateTime. For all constants dependencies, check the unit source code.

    0 讨论(0)
  • 2020-12-06 05:33

    I think this should work... the documentation says the overloaded version of these methods is for use in threads, but it can be handy for specifying the format settings you wish to use at the time.

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

    You can of course write variants of this with StrToDateDef and TryStrToDate with equivalent functionality

    0 讨论(0)
  • 2020-12-06 05:34

    why re-invent the wheel?

    XML uses ISO 8601 for date and date-time storage.

    Delphi has had built-in support for that since Delphi 6 in the XSBuiltIns unit.

    This answer explains how for DateTime, this is for Date only using the TXSDate class:

    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;
    
    0 讨论(0)
  • 2020-12-06 05:37

    For more flexibility, you could consider Marco van de Voort's scandate routine which handles your string in any format:

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

    See final version (7kB .zip) as added to FPC.

    0 讨论(0)
提交回复
热议问题