xml - para - funciones en delphi
En Delphi hay una funciĆ³n para convertir la fecha y hora de XML a TDateTime (3)
Delphi tiene una unidad XSBuiltIns (desde Delphi 6) que contiene tipos de datos que pueden ayudarlo a convertir algunos tipos de datos XML:
(hay más, como TXSDecimal , tienes la idea)
Todos estos contienen al menos estos dos métodos:
Puedes usarlo así:
with TXSDateTime.Create() do
try
AsDateTime := ClientDataSetParam.AsDateTime; // convert from TDateTime
Attribute.DateTimeValue := NativeToXS; // convert to WideString
finally
Free;
end;
with TXSDateTime.Create() do
try
XSToNative(XmlAttribute.DateTimeValue); // convert from WideString
CurrentField.AsDateTime := AsDateTime; // convert to TDateTime
finally
Free;
end;
Eso te ayudara a llegar.
--jeroen
La fecha y hora XML están en el formato
''-''? yyyy ''-'' mm ''-'' dd ''T'' hh '':'' mm '':'' ss (''.'' s +)? (zzzzzz)?
fueron
• ''-''? aaaa es un número de cuatro o más dígitos opcionalmente con signo negativo que representa el año; si hay más de cuatro dígitos, los ceros a la izquierda están prohibidos, y está prohibido "0000"
• los '''' restantes son separadores entre partes de la porción de fecha;
• el primer mm es un número de dos dígitos que representa el mes;
• dd es un número de dos dígitos que representa el día;
• ''T'' es un separador que indica que la hora del día sigue;
• hh es un número de dos dígitos que representa la hora; ''24'' está permitido si los minutos y segundos representados son cero, y el valor dateTime así representado es el primer instante del día siguiente (la propiedad hora de un objeto dateTime en el · espacio de valor · no puede tener un valor mayor a 23) ;
• '':'' es un separador entre partes de la porción del tiempo del día;
• el segundo mm es un número de dos dígitos que representa el minuto;
• ss es un número de dos dígitos enteros que representa los segundos completos;
• ''.'' s + (si está presente) representa los segundos fraccionarios;
• zzzzzz (si está presente) representa la zona horaria (como se describe a continuación).
aquí hay más ejemplos
Ejemplo simple 2009-08-31T19: 30: 00
Ejemplos más complejos
2002-10-10T12: 00: 00-05: 00 (mediodía del 10 de octubre de 2002, horario de verano central y hora estándar del este de EE. UU.) Es 2002-10-10T17: 00: 00Z , cinco horas después de 2002 -10-10T12: 00: 00Z .
ver www.w3.org/TR/2004/REC-xmlschema-2-20041028/datatypes.html para más información
Esto ya ha sido respondido bien, pero agregaré aquí algunas cosas que terminé haciendo en un caso similar que tuve. De la unidad XSBuiltIns encontré el método
function XMLTimeToDateTime(const XMLDateTime: InvString; AsUTCTime: Boolean = False): TDateTime;
que parecía ser lo que yo quería. Lo que quería era poder analizar todas las diferentes cadenas de tiempo XML definidas aquí: w3schools.com/schema/schema_dtypes_date.asp
Esto incluye cadenas con solo Fecha, solo Hora o Fecha y Hora, y todas estas con las opciones de zona horaria especificada o hora UTC o local para la cadena de origen, y el valor de retorno como hora local. Además, cuando se le da solo un tiempo, quería que siempre estuviera dentro del "día cero", es decir, después de la operación, la parte completa del TDateTime devuelto (emitida a número real) era cero.
Finalmente, quería que la función devuelva DateTime.MinValue en entrada errónea (principalmente cuando se le da una cadena vacía).
No estoy seguro de si estaba usando la función de forma diferente a como está especificada, pero al menos desafortunadamente falló en varios lugares para mí. Terminé haciendo mi propia función alrededor de esta, que cubría todos los casos que encontré y ahora estoy bien en el futuro. Se puede argumentar que quizás hubiera sido mejor escribir todo el análisis yo mismo, ya que no podría haber sido mucho más complejo que la solución de problemas que terminé haciendo, pero al menos por el momento , Voy con lo que tengo y decidí publicarlo aquí también en caso de que alguien más encuentre algo útil.
Principales puntos problemáticos (es posible que ya me olvide de algunos):
- La secuencia vacía da como resultado DateTime correspondiente a una fecha en Year 1, mientras que MinDateTime de Delphi está en Year 100.
- Las cadenas con solo Fecha siempre se consideran UTC independientemente de la presencia o ausencia de ''Z'' o definiciones explícitas de huso horario.
- Las cadenas con solo Time se identifican erróneamente como cadenas de fechas y se analizan incorrectamente.
- Los modificadores de zona horaria se aplican SÓLO si están explícitamente definidos; de lo contrario, se asume que todos son UTC, incluso cuando no haya ''Z''.
- Los segundos fraccionarios no son compatibles, sino que milisegundos siempre se convierten a 0.
- Como las cadenas de tiempo únicas no son compatibles, tuve que agregarles una fecha ficticia y luego asegurarme de que es la fecha actual (para cubrir problemas de horario de verano al convertir a / desde UTC, que a su vez tuvo que realizarse debido a la UTC errónea consideraciones) y luego, al final, restarlo del resultado y, finalmente, en estos casos, garantizar el requisito de día cero para cadenas de tiempo único.
El resultado final es una función de aproximadamente 100 líneas (incluyendo comentarios, etc.), que utiliza una cantidad considerable de funciones auxiliares (que deberían ser bastante autoexplicativas y que no son el tema de este mensaje :)). Deshice los bits del código relevante en un archivo separado y la unidad prueba que usé para probar esto en otro, incluyo ambos a continuación. Siéntase libre de utilizar y comentar según sea necesario. Tenga en cuenta que el formulario y sus usos relacionados, etc. son exactamente lo que Delphi puso en el proyecto de demostración en el que lo incluí, de ninguna manera son necesarios.
unit Main;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, XSBuiltIns, Math, DateUtils;
const
EPSILON = 10e-9;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
{Returns whether the given variable represents negative infinity.}
function IsNegInf(AValue : extended) : boolean;
{Returns whether the given variable represents positive infinity.}
function IsPosInf(AValue : extended) : boolean;
{Checks the less than relation of the given real numbers (R1 < R2), up to
precision EPSILON.}
function RealLessThan(R1, R2 : double) : boolean;
{Checks the greater than or equal to relation of the given real numbers (R1 >= R2),
up to precision EPSILON.}
function RealGreaterThanOrEqualTo(R1, R2 : double) : boolean;
{Checks the less than or equal to relation of the given real numbers (R1 <= R2),
up to precision EPSILON.}
function RealLessThanOrEqualTo(R1, R2 : double) : boolean;
{Return the floor of R, up to precision EPSILON. If Frac(R) < EPSILON, return R.}
function RealFloor(R : extended) : extended;
{Return the floor of R as integer, up to precision EPSILON. If Frac(R) < EPSILON, return R.}
function RealFloorInt(R : extended) : integer;
{Round the value X (properly) to an integer.}
function RoundProper(X : extended) : integer; overload;
function UtcTimeToLocalTime(AUtcTime: TDateTime): TDateTime;
function LocalTimeToUtcTime(ALocalTime: TDateTime): TDateTime;
function CountOccurrences(const SubText: string; const Text: string): Integer;
// Returns a count of the number of occurences of SubText in Text
function XMLTimeStamp2DateTime(TimeStamp : String): TDateTime;
// Parses an XML time stamp string to a TDateTime. All returned times are in
// local time. If time stamp string contains no time stamp definition (either
// explicit time zone info or UTC flag), the time is assumed to be in local time.
// Otherwise the time is parsed as the time zone indicated, and converted to local.
// If no time section is contained in the stamp, the time is assumed to be
// 0:00:00 in the time zone specified (or local time if no specification set).
// If time string is not valid MinDateTime is returned.
var
Form1: TForm1;
implementation
{$R *.dfm}
function XMLTimeStamp2DateTime(TimeStamp : String): TDateTime;
var
HasDateAndTimePart, HasUTCForce, HasExplicitTimeZone, HasDatePart, HasFractionalSeconds: Boolean;
PlusCount, MinusCount, HourOffset, MinuteOffset, FractionIndex, I: Integer;
TimeOffset: TDateTime;
TimeZoneString, TimeZoneDelimiter: string;
Year, Month, Day, MilliSeconds: Word;
YearS, MonthS, DayS, FracSecS: string;
CurrentDate, MSecsFromFractions: TDateTime;
DotSeparatedDecimals: TFormatSettings;
begin
TimeOffset := 0; TimeZoneString := ''''; TimeZoneDelimiter := ''+'';
FractionIndex := Pos(''.'', TimeStamp);
{$REGION ''Get the fractional seconds as milliseconds''}
HasFractionalSeconds := FractionIndex > 0;
FracSecS := ''0.'';
if HasFractionalSeconds then
begin
for I := FractionIndex + 1 to Length(TimeStamp) do
begin
if CharInSet(TimeStamp[I], [''0''..''9'']) then FracSecS := FracSecS + TimeStamp[I]
else Break;
end;
end else FracSecS := FracSecS + ''0'';
DotSeparatedDecimals.Create;
DotSeparatedDecimals.DecimalSeparator := ''.'';
DotSeparatedDecimals.ThousandSeparator := #0;
MilliSeconds := RoundProper(StrToFloatDef(FracSecS, 0, DotSeparatedDecimals) * 1000);
MSecsFromFractions := EncodeTime(0, 0, 0, MilliSeconds);
{$ENDREGION}
MinusCount := CountOccurrences(''-'', TimeStamp);
HasDatePart := (MinusCount > 1) or (TimeStamp = '''');
PlusCount := CountOccurrences(''+'', TimeStamp);
HasExplicitTimeZone := PlusCount > 0;
if not HasExplicitTimeZone then
begin
HasExplicitTimeZone := Odd(MinusCount); // 1 or 3 minuses => explicit time zone
TimeZoneDelimiter := ''-'';
end;
if HasExplicitTimeZone then
begin
TimeZoneString := Copy(TimeStamp, LastDelimiter(TimeZoneDelimiter, TimeStamp) + 1, Length(TimeStamp));
// Now TimeZoneString should be of format xx:xx where x''s are numbers!
if (Length(TimeZoneString) = 5) and (TimeZoneString[3] = '':'') then
begin
HourOffset := StrToIntDef(Copy(TimeZoneString, 1, 2), 0);
MinuteOffset := StrToIntDef(Copy(TimeZoneString, 3, 2), 0);
TimeOffset := EncodeTime(HourOffset, MinuteOffset, 0, 0);
if TimeZoneDelimiter = ''-'' then TimeOffset := -TimeOffset;
end;
end;
CurrentDate := Now;
Year := 0; Month := 0; Day := 0;
DecodeDate(CurrentDate, Year, Month, Day);
if not HasDatePart then
begin
// Since XMLTimeToDateTime doesn''t cope with strings without date part, add
// a dummy one on current date if it doesn''t exist - we can''t use day zero
// since then the daylight saving time calculation in the LocalTimeToUtcTime
// fixup being possibly done later will go wrong, if local time is in DST
// and day zero is not. So we have to use current day here, then remove it
// from the final result once we''re done otherwise.
YearS := IntToStr(Year);
MonthS := IntToStr(Month);
DayS := IntToStr(Day);
while Length(YearS) < 4 do YearS := ''0'' + YearS;
while Length(MonthS) < 2 do MonthS := ''0'' + MonthS;
while Length(DayS) < 2 do DayS := ''0'' + DayS;
TimeStamp := YearS + ''-'' + MonthS + ''-'' + DayS + SoapTimePrefix + TimeStamp;
end;
HasDateAndTimePart := Pos(SoapTimePrefix, TimeStamp) > 0;
HasUTCForce := Pos(SLocalTimeMarker, TimeStamp) > 0;
Result := XMLTimeToDateTime(TimeStamp); // This doesn''t support fractions of a second!
// Now the conversion is done with zero milliseconds, we need to add the fractions
Result := Result + MSecsFromFractions;
// XMLTimeToDateTime assumes source as UTC when:
// - No time part is defined and one of the following holds:
// - Explicit time zone is defined (to other than UTC) - here it works WRONG!
// - Explicit time zone is NOT defined and UTC flag is NOT defined - here it works WRONG!
// - Explicit UTC flag is defined - here it works CORRECT!
// - Time part is defined and one of the following holds:
// - Explicit time zone is NOT defined and UTC flag is NOT defined - here it works WRONG!
// - Explicit UTC flag is defined - here it works CORRECT!
// In the cases where it works wrong, we need to manually offset its result
// by the local-to-UTC difference.
if (not HasExplicitTimeZone) and (not HasUTCForce) then
Result := LocalTimeToUtcTime(Result)
else if HasExplicitTimeZone and (not HasDateAndTimePart) then
Result := Result - TimeOffset; // Minus to remove the effect of the offset
if not HasDatePart then
begin
// We added the current date to make XMLTimeToDateTime work, now we need to
// remove (the date part of) it back from the end result.
Result := Result - EncodeDate(Year, Month, Day);
// Since there originally was no date part, then there should not be one in
// the end result also, meaning that the result''s date should correspond to
// the zero-day.
while RealGreaterThanOrEqualTo(Result, 1) do Result := Result - 1;
while RealLessThan(Result, 0) do Result := Result + 1;
end;
Result := Max(Result, MinDateTime); // In erroneous situations XMLTimeToDateTime returns something less than MinDateTime, which we want as default
end;
{ Returns a count of the number of occurences of SubText in Text }
function CountOccurrences(const SubText: string; const Text: string): Integer;
var
i, j, SubLength: Integer;
First: Char;
begin
Result := 0;
if Length(SubText) <= 0 then Exit;
First := SubText[1];
SubLength := Length(SubText);
for i := 1 to Length(Text) do
begin
if Text[i] = First then
begin
j := 2;
while (j <= SubLength) and (Text[i + j - 1] = SubText[j]) do Inc(j);
if j > SubLength then Inc(result); // Matched all the way
end;
end;
end;
function UtcTimeToLocalTime(AUtcTime: TDateTime): TDateTime;
begin
Result := TTimeZone.Local.ToLocalTime(AUtcTime);
end;
function LocalTimeToUtcTime(ALocalTime: TDateTime): TDateTime;
begin
Result := TTimeZone.Local.ToUniversalTime(ALocalTime);
end;
function RoundProper(X : extended) : integer;
begin
Result := RealFloorInt(0.5 + x);
end;
function RealFloorInt(R : extended) : integer;
begin
Result := Trunc(RealFloor(R));
end;
function RealFloor(R : extended) : extended;
var
FracR : Extended;
begin
Result := R;
FracR := Abs(Frac(R));
if (FracR >= EPSILON) and RealLessThan(FracR, 1) then begin
if Frac(R) > 0 then Result := R - Frac(R)
else Result := R - (1 - Abs(Frac(R)));
end;
end;
function RealLessThan(R1, R2 : double) : boolean;
begin
if IsPosInf(R2) then Result := not IsPosInf(R1)
else if IsNegInf(R2) or IsPosInf(R1) then Result := False
else if IsNegInf(R1) then Result := not IsNegInf(R2)
else // (-Inf, -EPSILON) => Less,
Result := R1 - R2 < -EPSILON; // [-EPSILON, EPSILON] => Equal
end; // (EPSILON, Inf) => Greater
function RealGreaterThanOrEqualTo(R1, R2 : double) : boolean;
begin
if IsPosInf(R1) or IsNegInf(R2) then Result := True
else if IsPosInf(R2) or IsNegInf(R1) then Result := False
else // (-Inf, -EPSILON) => Less,
Result := R1 - R2 > -EPSILON; // [-EPSILON, EPSILON] => Equal
end; // (EPSILON, Inf) => Greater
function RealLessThanOrEqualTo(R1, R2 : double) : boolean;
begin
if IsPosInf(R2) or IsNegInf(R1) then Result := True
else if IsPosInf(R1) or IsNegInf(R2) then Result := False
else // (-Inf, -EPSILON) => Less,
Result := R1 - R2 < EPSILON; // [-EPSILON, EPSILON] => Equal
end; // (EPSILON, Inf) => Greater
function IsPosInf(AValue : extended) : boolean;
begin
Result := IsInfinite(AValue) and (Sign(AValue) = 1);
end;
function IsNegInf(AValue : extended) : boolean;
begin
Result := IsInfinite(AValue) and (Sign(AValue) = -1);
end;
end.
Entonces las pruebas unitarias están aquí:
unit TestMain;
{
Delphi DUnit Test Case
----------------------
This unit contains a skeleton test case class generated by the Test Case Wizard.
Modify the generated code to correctly setup and call the methods from the unit
being tested.
}
interface
uses
TestFramework, System.SysUtils, Vcl.Graphics, XSBuiltIns, Winapi.Windows,
System.Variants, DateUtils, Vcl.Dialogs, Vcl.Controls, Vcl.Forms, Winapi.Messages, Math,
System.Classes, Main;
type
// Test methods for class TForm1
TestTForm1 = class(TTestCase)
strict private
public
procedure SetUp; override;
procedure TearDown; override;
published
procedure TestXMLTimeStamp2DateTime;
end;
implementation
procedure TestTForm1.SetUp;
begin
// Nothing to do here
end;
procedure TestTForm1.TearDown;
begin
// Nothing to do here
end;
procedure TestTForm1.TestXMLTimeStamp2DateTime;
const
TIME_TOLERANCE = 0.0000000115741; // Approximately 1 millisecond, in days
var
Source: string;
ReturnValue, ExpectedValue, Today: TDateTime;
function DateTimeOfToday: TDateTime;
var
Year, Month, Day: Word;
begin
Year := 0; Month := 0; Day := 0;
DecodeDate(Now, Year, Month, Day);
Result := EncodeDate(Year, Month, Day);
end;
begin
Today := DateTimeOfToday; // Counted only once, we ignore the theoretic chance of day changing during the test execution from DST to non-DST or vice versa
{$REGION ''Empty string''}
// Setup method call parameters
Source := '''';
ExpectedValue := MinDateTime;
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for empty string should return MinDateTime, but did not!'');
{$ENDREGION}
{$REGION ''Date only strings''}
{$REGION ''Date string - local''}
// Setup method call parameters
Source := ''2002-09-24'';
ExpectedValue := EncodeDate(2002, 9, 24);
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, ''XMLTimeStamp2DateTime for date string - local should return 24.9.2002, but did not!'');
{$ENDREGION}
{$REGION ''Date string - UTC''}
// Setup method call parameters
Source := ''2002-09-24Z'';
ExpectedValue := EncodeDate(2002, 9, 24);
ExpectedValue := UtcTimeToLocalTime(ExpectedValue);
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for date string - UTC should return 24.9.2002 + local time offset, but did not!'');
{$ENDREGION}
{$REGION ''Date string - negative offset''}
// Setup method call parameters
Source := ''2002-09-24-03:00'';
ExpectedValue := EncodeDate(2002, 9, 24);
ExpectedValue := ExpectedValue + EncodeTime(3, 0, 0, 0); // First convert to UTC by removing the offset
ExpectedValue := UtcTimeToLocalTime(ExpectedValue); // Then convert to local from UTC
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for date string - negative offset should return 24.9.2002 + three hours + local time offset, but did not!'');
{$ENDREGION}
{$REGION ''Date string - positive offset''}
// Setup method call parameters
Source := ''2002-09-24+11:00'';
ExpectedValue := EncodeDate(2002, 9, 24);
ExpectedValue := ExpectedValue - EncodeTime(11, 0, 0, 0); // First convert to UTC by removing the offset
ExpectedValue := UtcTimeToLocalTime(ExpectedValue); // Then convert to local from UTC
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for date string - positive offset should return 24.9.2002 - eleven hours + local time offset, but did not!'');
{$ENDREGION}
{$ENDREGION}
{$REGION ''Time only strings''}
{$REGION ''Time string - local''}
// Setup method call parameters
Source := ''09:30:10'';
ExpectedValue := EncodeTime(9, 30, 10, 0);
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for time string - local should return 09:30:10, but did not!'');
{$ENDREGION}
{$REGION ''Time string - UTC''}
// Setup method call parameters
Source := ''09:30:10Z'';
// Have to add Today for the UtcTimeToLocalTime call to have correct DST
// - then have to remove Today again away to have correct zero-day date
ExpectedValue := Today + EncodeTime(9, 30, 10, 0);
ExpectedValue := UtcTimeToLocalTime(ExpectedValue);
ExpectedValue := ExpectedValue - Today;
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for time string - UTC should return 09:30:10 + local time offset, but did not!'');
{$ENDREGION}
{$REGION ''Time string - negative offset''}
// Setup method call parameters
Source := ''09:30:10-03:00'';
// Have to add Today for the UtcTimeToLocalTime call to have correct DST
// - then have to remove Today again away to have correct zero-day date
ExpectedValue := Today + EncodeTime(9, 30, 10, 0);
ExpectedValue := ExpectedValue + EncodeTime(3, 0, 0, 0); // First convert to UTC by removing the offset
ExpectedValue := UtcTimeToLocalTime(ExpectedValue); // Then convert to local from UTC
ExpectedValue := ExpectedValue - Today;
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for time string - negative offset should return 09:30:10 + three hours + local time offset, but did not!'');
{$ENDREGION}
{$REGION ''Time string - positive offset over date line''}
// Setup method call parameters
Source := ''06:30:10+11:00'';
// Have to add Today for the UtcTimeToLocalTime call to have correct DST
// - then have to remove Today again away to have correct zero-day date
ExpectedValue := Today + EncodeTime(6, 30, 10, 0);
ExpectedValue := ExpectedValue - EncodeTime(11, 0, 0, 0); // First convert to UTC by removing the offset
ExpectedValue := UtcTimeToLocalTime(ExpectedValue); // Then convert to local from UTC
ExpectedValue := ExpectedValue - Today;
if RealGreaterThanOrEqualTo(ExpectedValue, 1) then ExpectedValue := ExpectedValue - 1; // When having time only, date should always be zero!
if RealLessThan(ExpectedValue, 0) then ExpectedValue := ExpectedValue + 1; // When having time only, date should always be zero!
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for time string - positive offset (over day change) should return 06:30:10 - eleven hours + local time offset (modulo 24 hours), but did not!'');
{$ENDREGION}
{$REGION ''Fractional time string with negative offset over date line''}
// Setup method call parameters
Source := ''14:30:10.25-11:00'';
// Have to add Today for the UtcTimeToLocalTime call to have correct DST
// - then have to remove Today again away to have correct zero-day date
ExpectedValue := Today + EncodeTime(14, 30, 10, 250);
ExpectedValue := ExpectedValue + EncodeTime(11, 0, 0, 0); // First convert to UTC by removing the offset
ExpectedValue := UtcTimeToLocalTime(ExpectedValue); // Then convert to local from UTC
ExpectedValue := ExpectedValue - Today;
if RealGreaterThanOrEqualTo(ExpectedValue, 1) then ExpectedValue := ExpectedValue - 1; // When having time only, date should always be zero!
if RealLessThanOrEqualTo(ExpectedValue, 0) then ExpectedValue := ExpectedValue + 1; // When having time only, date should always be zero!
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for fractional time string - negative offset (over day change) should return 14:30:10.25 + eleven hours + local time offset (modulo 24 hours), but did not!'');
{$ENDREGION}
{$ENDREGION}
{$REGION ''Date and time strings}
{$REGION ''Date and time string - local''}
// Setup method call parameters
Source := ''2002-09-24T09:30:10.25'';
ExpectedValue := EncodeDate(2002, 9, 24) + EncodeTime(9, 30, 10, 250);
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for date and time string - local should return 24.9.2002 09:30:10.25, but did not!'');
{$ENDREGION}
{$REGION ''Date and time string - UTC''}
// Setup method call parameters
Source := ''2002-09-24T09:30:10.25Z'';
ExpectedValue := EncodeDate(2002, 9, 24) + EncodeTime(9, 30, 10, 250);
ExpectedValue := UtcTimeToLocalTime(ExpectedValue);
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for date and time string - UTC should return 24.9.2002 09:30:10.25 + local time offset, but did not!'');
{$ENDREGION}
{$REGION ''Date and time string - positive offset over date line''}
// Setup method call parameters
Source := ''2002-09-24T06:30:10.25+11:00'';
ExpectedValue := EncodeDate(2002, 9, 24) + EncodeTime(6, 30, 10, 250);
ExpectedValue := ExpectedValue - EncodeTime(11, 0, 0, 0); // First convert to UTC by removing the offset
ExpectedValue := UtcTimeToLocalTime(ExpectedValue); // Then convert to local from UTC
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for date and time string - positive offset (over day change) should return 24.9.2002 06:30:10.25 - eleven hours + local time offset, but did not!'');
{$ENDREGION}
{$REGION ''Date and time string - negative offset over date line''}
// Setup method call parameters
Source := ''2002-09-24T14:30:10.25-11:00'';
ExpectedValue := EncodeDate(2002, 9, 24) + EncodeTime(14, 30, 10, 250);
ExpectedValue := ExpectedValue + EncodeTime(11, 0, 0, 0); // First convert to UTC by removing the offset
ExpectedValue := UtcTimeToLocalTime(ExpectedValue); // Then convert to local from UTC
// Call the method
ReturnValue := XMLTimeStamp2DateTime(Source);
// Validate method results
CheckEquals(ExpectedValue, ReturnValue, TIME_TOLERANCE, ''XMLTimeStamp2DateTime for date and time string - negative offset (over day change) should return 14:30:10.25 + eleven hours + local time offset, but did not!'');
{$ENDREGION}
{$ENDREGION}
end;
initialization
// Register any test cases with the test runner
RegisterTest(TestTForm1.Suite);
end.
La unidad OmniXML OmniXMLUtils contiene un montón de funciones para hacer XML para fechar y fechar las conversiones XML.
function XMLStrToDateTime(nodeValue: XmlString; var value: TDateTime): boolean; overload;
function XMLStrToDateTime(nodeValue: XmlString): TDateTime; overload;
function XMLStrToDateTimeDef(nodeValue: XmlString; defaultValue: TDateTime): TDateTime;
function XMLStrToDate(nodeValue: XmlString; var value: TDateTime): boolean; overload;
function XMLStrToDate(nodeValue: XmlString): TDateTime; overload;
function XMLStrToDateDef(nodeValue: XmlString; defaultValue: TDateTime): TDateTime;
function XMLStrToTime(nodeValue: XmlString; var value: TDateTime): boolean; overload;
function XMLStrToTime(nodeValue: XmlString): TDateTime; overload;
function XMLStrToTimeDef(nodeValue: XmlString; defaultValue: TDateTime): TDateTime;
function XMLDateTimeToStr(value: TDateTime): XmlString;
function XMLDateTimeToStrEx(value: TDateTime): XmlString;
function XMLDateToStr(value: TDateTime): XmlString;
function XMLTimeToStr(value: TDateTime): XmlString;