Comment convertir une chaîne ISO 8601 en Delphidate?

<!-Je peux convertir un Delphidate au format ISO 8601 facilement en utilisant ceci:

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

Quelle est la façon idiomatique de faire la conversion inverse? StringToDateTime() ne semble pas exister.

évidemment je peux le faire à la manière "dure" en analysant manuellement la chaîne et en encodant le résultat, mais cela semble un mauvais choix.

17
demandé sur Rob Kennedy 2011-07-11 18:39:40

7 réponses

pourquoi réinventer la roue?

le XML utilise la norme ISO 8601 pour le stockage de la date et de l'heure.

Delphi a intégré un support pour cela depuis Delphi 6 dans le XSBuiltIns unité.

Cette réponse explique comment pour DateTime, ceci est pour Date seulement en utilisant le TXSDate catégorie:

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;
16
répondu Jeroen Wiert Pluimers 2017-05-23 12:25:24

à partir de XE8, utilisez ISO8601ToDate (et DateToISO8601)dateutils.pas.

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

12
répondu Roddy 2015-09-22 20:59:16

vous pouvez trouver des routines de conversion Iso-8601 dans notre SynCommons unit.

il a été profondément optimisé pour la vitesse, donc il est beaucoup plus rapide que les fonctions DateTimeToString() et autres, mais bien sûr, le code est plus difficile à suivre. ;)

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;

ceci est capable de gérer une conversion très rapide d'un tampon encodé UTF-8 vers un TDateTime. Pour toutes les dépendances de constantes, vérifiez le code source de l'unité.

7
répondu Arnaud Bouchez 2011-07-11 15:10:03

je pense que cela devrait fonctionner... la documentation dit la version surchargée de ces méthodes est pour une utilisation dans les threads, mais elle peut être utile pour spécifier les paramètres de format que vous souhaitez utiliser à l'époque.

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

Vous pouvez bien sûr écrire des variantes de cela avec Strtodateef et TryStrToDate avec la fonctionnalité équivalente

7
répondu James Barrass 2011-10-20 11:28:49

pour plus de flexibilité, vous pouvez considérer Marco van de Voort scandate routine qui s'occupe de votre chaîne dans n'importe quel format:

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

Voir version finale (7KB .zip) ajouté à la FPC.

6
répondu NGLN 2017-05-23 12:32:27
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

1
répondu Akella225 2015-09-09 05:41:16

à partir de XE6 vous pouvez utiliser la fonction System.DateUtils.ISO8601ToDate:

uses
  System.DateUtils;
var
  vDat: TDateTime;
begin
  vDat := ISO8601ToDate('2018-03-26T11:01:35.867Z');
end.
0
répondu Marlon Nardi 2018-03-27 00:52:15