如何将ISO 8601字符串转换为Delphi TDate?

Rod*_*ddy 18 delphi iso8601

我可以使用以下方法轻松地将Delphi TDate转换为ISO 8601格式:

DateTimeToString(result, 'yyyy-mm-dd', myDate);
Run Code Online (Sandbox Code Playgroud)

进行逆转换的惯用方法是什么?StringToDateTime()似乎不存在.

显然,我可以通过手动解析字符串并对结果进行编码来实现"硬"方式,但这似乎是一个糟糕的选择.

Jer*_*ers 16

为什么重新发明轮子?

XML使用ISO 8601进行日期和日期时间存储.

自从XSBuiltIns单元中的Delphi 6以来,Delphi就已经内置了对它的支持.

这个答案解释了如何使用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;
Run Code Online (Sandbox Code Playgroud)

  • 使用 XSBuiltins;XMLTimeToDateTime(str, True); - 也会起作用。 (2认同)

Rod*_*ddy 16

从XE8开始,使用ISO8601ToDate(和DateToISO8601)来自dateutils.pas.

http://docwiki.embarcadero.com/Libraries/XE8/en/System.DateUtils.ISO8601ToDate


Jam*_*ass 7

我认为这应该有用......文档说这些方法的重载版本是用于线程的,但是它可以方便地指定你当时想要使用的格式设置.

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

您当然可以使用StrToDateDef和TryStrToDate编写具有相同功能的变体

  • 您可能还希望使用系统默认值初始化格式设置.取决于您是否要将其用于除解析日期之外的其他内容:`GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT,FormatSettings);`使用系统默认值填充FormatSettings记录. (3认同)
  • 绝对使用"线程安全"重载版本,否则如果使用DateToStr,或者使用带有'c'或'ddddd'的FormatDateTime或使用ShortDateFormat的任何其他内容,您将更改应用程序显示日期的方式. (2认同)

Arn*_*hez 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;
Run Code Online (Sandbox Code Playgroud)

这能够处理从UTF-8编码缓冲区到a的非常快速的转换TDateTime.对于所有常量依赖项,请检查单元源代码.

  • 但是,此功能并非完全符合ISO8601标准.规范说使用"T"作为日期和时间字符串之间的分隔符.只有双方同意才能省略它.其次,在字符串末尾不支持时区指示,这是许多Web服务所要求的. (4认同)

NGL*_*GLN 6

为了获得更大的灵活性,您可以考虑Marco van de Voortscandate例程,该例程以任何格式处理您的字符串:

var
  D: TDateTime;
begin
  D := ScanDate('yyyy-mm-dd', '2011-07-11');
Run Code Online (Sandbox Code Playgroud)

查看添加到FPC的最终版本(7kB .zip).

  • 英语权威不等于荷兰语的"定义".在这种情况下,荷兰语"definitieve versie"被更好地翻译为"最终版本"."最终版本"更类似于说"终极"版本......然后,也许你想说:-)) (2认同)