2011-07-11 27 views
17

puedo convertir un Delphi TDate al formato ISO 8601 fácilmente usando esto:¿Cómo convierto una cadena ISO 8601 en una Delphi TDate?

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

Cuál es la forma idiomática para hacer la conversión inversa? StringToDateTime() no parece existir.

Obviamente, puedo hacerlo de forma "difícil" analizando manualmente la cadena y codificando el resultado, pero esa parece una mala elección.

+0

posible duplicado de [la conversión de una cadena a TDateTime basado en un formato arbitrario] (http://stackoverflow.com/questions/3786823/converting-a-string-to-tdatetime-based-on- un formato arbitrario) – NGLN

Respuesta

15

¿por qué reinventar la rueda?

XML utiliza ISO 8601 para el almacenamiento de fecha y hora.

Delphi ha tenido soporte integrado para eso desde Delphi 6 en la unidad XSBuiltIns.

This answer explains how de DateTime, esto es para la fecha sólo se utiliza la clase 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; 
7

Creo que esto debería funcionar ... la documentación dice que la versión sobrecargada de estos métodos es para usar en subprocesos, pero puede ser útil para especificar la configuración de formato que desea utilizar en ese momento.

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

Por supuesto, puede variantes de escritura de este con StrToDateDef y TryStrToDate con funcionalidad equivalente

+3

Es posible que desee inicializar los ajustes de formato también, con el sistema predeterminado. Dependiendo de si va a usarlo para otra cosa, excepto las fechas de análisis: 'GetLocaleFormatSettings (LOCALE_SYSTEM_DEFAULT, FormatSettings);' llena el registro FormatSettings con los valores predeterminados del sistema. –

+0

@Roald, gracias ..¡Estaba haciendo solo un par de pruebas! Lo actualizaré en un momento –

+2

Use definitivamente las versiones sobrecargadas "thread-safe", de lo contrario cambiará la forma en que su aplicación muestra las fechas si usa DateToStr, o FormatDateTime con 'c' o 'ddddd' o cualquier otra cosa que use ShortDateFormat. –

7

puede encontrar Iso-8601 rutinas de conversión en nuestra SynCommons unit.

Ha sido profundamente optimizado para la velocidad, por lo que es mucho más rápido que las funciones DateTimeToString() y tal, pero, por supuesto, el código es más difícil de seguir. ;)

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; 

Esto es capaz de manejar una conversión muy rápida de un tampón codificado UTF-8 en un TDateTime. Para todas las dependencias de constantes, verifique el código fuente de la unidad.

+0

Típico. Estoy usando Synapse de todos modos, pero nunca me di cuenta de que esto estaba incluido :-) – Roddy

+4

Sin embargo, esta función no es totalmente compatible con ISO8601. La especificación dice que use "T" como separador entre las cadenas de fecha y hora. Omitirlo solo está permitido por mutuo acuerdo. En segundo lugar, no hay soporte para la indicación de zona horaria al final de la cadena, que es requerida por muchos servicios web. –

6

Para mayor flexibilidad, usted podría considerar Marco van de Voort 's scandate routine que se ocupa de la cadena en cualquier formato:

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

Ver final version (7kB .zip) como añadido a FPC.

+2

el inglés definitivo no es igual al "definitief" holandés. En este contexto, el "versículo definitivo" holandés se traduce mejor como la "versión final". Una "versión definitiva" es más parecida a decir la versión "definitiva" ... Por otra parte, tal vez quisiste decir eso :-)) –

+0

@Marjan dankje ...;) – NGLN

+0

Siempre dispuesto a ayudar a un país (wo)hombres –

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

Cuestiones relacionadas