19

これを使用して、DelphiTDateをISO8601形式に簡単に変換できます。

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

逆変換を行うための慣用的な方法は何ですか?StringToDateTime()存在しないようです。

明らかに、文字列を手動で解析して結果をエンコードすることで「難しい」方法でそれを行うことができますが、それは悪い選択のようです。

4

7 に答える 7

18

なぜ車輪を再発明するのですか?

XML は、日付と日時の保存に ISO 8601 を使用します。

Delphi では、 XSBuiltInsユニットで Delphi 6 以降、組み込みのサポートが提供されています。

この回答では、DateTime の場合、これはTXSDateクラスを使用した Date のみについて説明しています。

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;
于 2011-07-12T03:40:37.643 に答える
9

これでうまくいくと思います...ドキュメントには、これらのメソッドのオーバーロードされたバージョンはスレッドで使用するためのものであると書かれていますが、その時点で使用したいフォーマット設定を指定するのに便利です。

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

もちろん、同等の機能を備えた StrToDateDef および TryStrToDate を使用して、これのバリアントを作成できます。

于 2011-07-11T15:08:16.227 に答える
7

SynCommons ユニットで ISO-8601 変換ルーチンを見つけることができます。

速度が大幅に最適化されているため、DateTimeToString() 関数などよりもはるかに高速ですが、もちろん、コードをたどるのはより困難です。;)

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;

これにより、UTF-8 でエンコードされたバッファからTDateTime. すべての定数の依存関係については、ユニットのソース コードを確認してください。

于 2011-07-11T15:10:03.247 に答える
6

柔軟性を高めるために、任意の形式で文字列を処理するMarco vandeVoortのスキャン日付ルーチンを検討できます。

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

FPCに追加された最終バージョン(7kB .zip)を参照してください。

于 2011-07-11T16:23:48.833 に答える
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

于 2015-09-09T05:41:16.260 に答える