我可以使用以下方法轻松地将 Delphi TDate 转换为 ISO 8601 格式:
DateTimeToString(result, 'yyyy-mm-dd', myDate);
进行逆转换的惯用方法是什么?StringToDateTime()
似乎不存在。
显然,我可以通过手动解析字符串并对结果进行编码来以“硬”的方式做到这一点,但这似乎是一个糟糕的选择。
为什么要重新发明轮子?
XML 使用 ISO 8601 进行日期和日期时间存储。
自 Delphi 6 以来,Delphi 在XSBuiltIns单元中内置了对它的支持。
这个答案解释了DateTime 的情况,这仅适用于使用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;
从 XE8 开始,使用ISO8601ToDate
(和DateToISO8601
)从dateutils.pas
.
http://docwiki.embarcadero.com/Libraries/XE8/en/System.DateUtils.ISO8601ToDate
我认为这应该可行......文档说这些方法的重载版本用于线程,但它可以方便地指定您当时希望使用的格式设置。
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 编写它的变体
您可以在我们的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
. 对于所有常量依赖项,请检查单元源代码。
为了获得更大的灵活性,您可以考虑Marco van de Voort的scandate 例程,它以任何格式处理您的字符串:
var
D: TDateTime;
begin
D := ScanDate('yyyy-mm-dd', '2011-07-11');
请参阅添加到 FPC 的最终版本(7kB .zip)。
USES Soap.XSBuiltIns;
...
Function XMLDateTimeToLocalDateTime(const Value: String): TDateTime;
begin
with TXSDateTime.Create do
try
XSToNative(Value);
result := AsDateTime;
finally
Free;
end;
end;
德尔福 XE3
从 XE6 开始,您可以使用函数System.DateUtils.ISO8601ToDate
:
uses
System.DateUtils;
var
vDat: TDateTime;
begin
vDat := ISO8601ToDate('2018-03-26T11:01:35.867Z');
end.