Fixed: Daylight Saving Time dependant on the target date instead of the current settings
This commit is contained in:
parent
29c1cab091
commit
e9f864d150
@ -72,6 +72,11 @@ type
|
||||
function WriteInteger(const AName: String; AValue: Integer): Boolean; override;
|
||||
function WriteString(const AName: String; const AValue: String): Boolean; override;
|
||||
|
||||
procedure GetKeys(const ADest: TStrings); override;
|
||||
procedure GetSections(const ADest: TStrings); override;
|
||||
procedure DeleteKey(const AName: string); override;
|
||||
procedure DeleteSection(const AName: string); override;
|
||||
|
||||
property Output: IPersistTestOutput read FOutput write FOutput;
|
||||
end;
|
||||
|
||||
@ -191,7 +196,7 @@ var
|
||||
testFiler: TX2UtPersistTestFiler;
|
||||
|
||||
begin
|
||||
testFiler := TX2UtPersistTestFiler.Create(AIsReader);;
|
||||
testFiler := TX2UtPersistTestFiler.Create(AIsReader);
|
||||
testFiler.Output := Self.Output;
|
||||
|
||||
Result := testFiler;
|
||||
@ -266,6 +271,24 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TX2UtPersistTestFiler.GetKeys(const ADest: TStrings);
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure TX2UtPersistTestFiler.GetSections(const ADest: TStrings);
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure TX2UtPersistTestFiler.DeleteKey(const AName: string);
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure TX2UtPersistTestFiler.DeleteSection(const AName: string);
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ TPersistTestOutput }
|
||||
constructor TPersistTestOutput.Create();
|
||||
begin
|
||||
|
@ -10,12 +10,16 @@ type
|
||||
published
|
||||
procedure TestIsValidXMLChar;
|
||||
procedure TestGetValidXMLText;
|
||||
procedure TestXMLToDateTime;
|
||||
procedure TestXMLToDate;
|
||||
procedure TestDateTimeToXML;
|
||||
procedure TestDateToXML;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
XMLDataBindingUtils;
|
||||
XMLDataBindingUtils, DateUtils, SysUtils;
|
||||
|
||||
|
||||
{ TXMLDataBindingUtilsTest }
|
||||
@ -33,6 +37,64 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TXMLDataBindingUtilsTest.TestXMLToDateTime;
|
||||
var
|
||||
dateInWintertime, dateInSummerTime : TDateTime;
|
||||
begin
|
||||
// Local Time
|
||||
dateInWintertime := EncodeDateTime(2016, 2, 2, 00, 59, 59, 0);
|
||||
dateInSummerTime := EncodeDateTime(2016, 4, 9, 00, 59, 59, 0);
|
||||
|
||||
// Wintertijd
|
||||
CheckEquals(dateInWintertime, XMLToDateTime('2016-02-01T23:59:59Z', xdtDateTime));
|
||||
CheckEquals(IncMilliSecond(dateInWintertime, 678), XMLToDateTime('2016-02-01T23:59:59.678Z', xdtDateTime));
|
||||
CheckEquals(dateInWintertime, XMLToDateTime('2016-02-02T00:59:59+01:00', xdtDateTime));
|
||||
CheckEquals(IncMilliSecond(dateInWintertime, 678), XMLToDateTime('2016-02-02T00:59:59.678+01:00', xdtDateTime));
|
||||
|
||||
// Zomertijd
|
||||
CheckEquals(dateInSummerTime, XMLToDateTime('2016-04-08T22:59:59Z', xdtDateTime));
|
||||
CheckEquals(IncMilliSecond(dateInSummerTime, 678), XMLToDateTime('2016-04-08T22:59:59.678Z', xdtDateTime));
|
||||
CheckEquals(dateInSummerTime, XMLToDateTime('2016-04-09T00:59:59+02:00', xdtDateTime));
|
||||
CheckEquals(IncMilliSecond(dateInSummerTime, 678), XMLToDateTime('2016-04-09T00:59:59.678+02:00', xdtDateTime));
|
||||
end;
|
||||
|
||||
|
||||
procedure TXMLDataBindingUtilsTest.TestXMLToDate;
|
||||
begin
|
||||
CheckEquals(EncodeDate(2016, 2, 2), XMLToDateTime('2016-02-02', xdtDate));
|
||||
CheckEquals(EncodeDate(2016, 4, 9), XMLToDateTime('2016-04-09', xdtDate));
|
||||
end;
|
||||
|
||||
|
||||
procedure TXMLDataBindingUtilsTest.TestDateTimeToXML;
|
||||
var
|
||||
dateInWintertime, dateInSummerTime : TDateTime;
|
||||
begin
|
||||
dateInWintertime := EncodeDateTime(2016, 2, 1, 14, 59, 59, 0);
|
||||
dateInSummerTime := EncodeDateTime(2016, 4, 8, 14, 59, 59, 0);
|
||||
|
||||
// Wintertijd
|
||||
CheckEquals('2016-02-01T13:59:59+01:00', DateTimeToXML(XMLToDateTime('2016-02-01T12:59:59Z', xdtDateTime), xdtDateTime, [xtfTimezone]));
|
||||
CheckEquals('2016-02-01T13:59:59.678+01:00', DateTimeToXML(IncMilliSecond(XMLToDateTime('2016-02-01T12:59:59Z', xdtDateTime), 678), xdtDateTime, [xtfTimezone, xtfMilliseconds]));
|
||||
CheckEquals('2016-02-01T14:59:59+01:00', DateTimeToXML(dateInWintertime, xdtDateTime, [xtfTimezone]));
|
||||
CheckEquals('2016-02-01T14:59:59.678+01:00', DateTimeToXML(IncMilliSecond(dateInWintertime, 678), xdtDateTime, [xtfTimezone, xtfMilliseconds]));
|
||||
|
||||
// Zomertijd
|
||||
CheckEquals('2016-04-08T14:59:59+02:00', DateTimeToXML(XMLToDateTime('2016-04-08T12:59:59Z', xdtDateTime), xdtDateTime, [xtfTimezone]));
|
||||
CheckEquals('2016-04-08T14:59:59.678+02:00', DateTimeToXML(IncMilliSecond(XMLToDateTime('2016-04-08T12:59:59Z', xdtDateTime), 678), xdtDateTime, [xtfTimezone, xtfMilliseconds]));
|
||||
CheckEquals('2016-04-08T14:59:59+02:00', DateTimeToXML(dateInSummerTime, xdtDateTime, [xtfTimezone]));
|
||||
CheckEquals('2016-04-08T14:59:59.678+02:00', DateTimeToXML(IncMilliSecond(dateInSummerTime, 678), xdtDateTime, [xtfTimezone, xtfMilliseconds]));
|
||||
end;
|
||||
|
||||
|
||||
procedure TXMLDataBindingUtilsTest.TestDateToXML;
|
||||
begin
|
||||
CheckEquals('2016-02-02', DateTimeToXML(EncodeDate(2016, 2, 2), xdtDate));
|
||||
CheckEquals('2016-04-09', DateTimeToXML(EncodeDate(2016, 4, 9), xdtDate));
|
||||
end;
|
||||
|
||||
|
||||
|
||||
initialization
|
||||
RegisterTest(TXMLDataBindingUtilsTest.Suite);
|
||||
|
||||
|
@ -18,7 +18,7 @@ type
|
||||
TXMLDateTimeFormat = (xdtDateTime, xdtDate, xdtTime);
|
||||
TXMLTimeFragment = (xtfMilliseconds, xtfTimezone);
|
||||
TXMLTimeFragments = set of TXMLTimeFragment;
|
||||
|
||||
TDateConvert = (dcToUtc, dcToLocal);
|
||||
|
||||
IXSDValidate = interface
|
||||
['{3BFDC851-7459-403B-87B3-A52E9E85BC8C}']
|
||||
@ -197,12 +197,79 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
function InDSTSpan(ADate: TDateTime; ATimeZoneInfo: TTimeZoneInformation): boolean;
|
||||
var
|
||||
lowerDayLight: TDateTime;
|
||||
upperDayLight: TDateTime;
|
||||
day: TDate;
|
||||
days: Integer;
|
||||
|
||||
function GetDay(AYear, AMonth, ADay, ADayOfWeek: Integer): TDate;
|
||||
var
|
||||
I, Counter : Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
Counter := 0;
|
||||
|
||||
days := DaysInAMonth(AYear, AMonth);
|
||||
for I := 1 to days do
|
||||
begin
|
||||
Result := EncodeDate(AYear, AMonth, I);
|
||||
// Delphi DayOfWeek 1 = Sunday
|
||||
// TimeZoneInfo.wDayOfWeek 0 = Sunday
|
||||
if DayOfWeek(Result) -1 = ADayOfWeek then
|
||||
begin
|
||||
inc(Counter);
|
||||
if (counter = ADay) or ((Counter < Aday) and (I >= days - 6)) then
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
with ATimeZoneInfo.DaylightDate do
|
||||
begin
|
||||
day := GetDay(wYear + YearOf(ADate), wMonth, wDay, wDayOfWeek);
|
||||
lowerDayLight := day + EncodeTime(wHour, wMinute, wSecond, wMilliseconds);
|
||||
end;
|
||||
|
||||
with ATimeZoneInfo.StandardDate do
|
||||
begin
|
||||
day := GetDay(wYear + YearOf(ADate), wMonth, wDay, wDayOfWeek);
|
||||
upperDayLight := day + EncodeTime(wHour, wMinute, wSecond, wMilliseconds);
|
||||
end;
|
||||
|
||||
Result := (ADate >= lowerDayLight) and (ADate <= upperDayLight);
|
||||
end;
|
||||
|
||||
|
||||
function ConvertDate(ADate: TDateTime; ADateconvert: TDateConvert): TDateTime;
|
||||
var
|
||||
timeZone: TTimeZoneInformation;
|
||||
timeZoneID: Cardinal;
|
||||
localOffset: Integer;
|
||||
|
||||
begin
|
||||
FillChar(timeZone, SizeOf(TTimeZoneInformation), #0);
|
||||
timeZoneID := GetTimeZoneInformation(timeZone);
|
||||
|
||||
if timeZoneID in [TIME_ZONE_ID_STANDARD, TIME_ZONE_ID_DAYLIGHT] then
|
||||
localOffset := -timeZone.Bias - IfThen(InDSTSpan(ADate, timeZone), timeZone.DaylightBias, timeZone.StandardBias)
|
||||
else
|
||||
localOffset := 0;
|
||||
|
||||
if ADateconvert = dcToUtc then
|
||||
localOffset := localOffset * -1;
|
||||
|
||||
Result := IncMinute(ADate, localOffset);
|
||||
end;
|
||||
|
||||
|
||||
function DateTimeToXML(ADate: TDateTime; AFormat: TXMLDateTimeFormat; ATimeFragments: TXMLTimeFragments): string;
|
||||
var
|
||||
formatSettings: TFormatSettings;
|
||||
timeZone: TTimeZoneInformation;
|
||||
timeOffset: Integer;
|
||||
utcDate: TDateTime;
|
||||
offsetMinutes: Integer;
|
||||
|
||||
begin
|
||||
formatSettings := GetDefaultFormatSettings;
|
||||
@ -213,21 +280,16 @@ begin
|
||||
if xtfMilliseconds in ATimeFragments then
|
||||
Result := Result + FormatDateTime(XMLMsecsFormat, ADate);
|
||||
|
||||
if xtfTimezone in ATimeFragments then
|
||||
if (xtfTimezone in ATimeFragments) then
|
||||
begin
|
||||
FillChar(timeZone, SizeOf(TTimeZoneInformation), #0);
|
||||
if GetTimeZoneInformation(timeZone) <> TIME_ZONE_ID_INVALID then
|
||||
begin
|
||||
timeOffset := -timeZone.Bias;
|
||||
utcDate := ConvertDate(ADate, dcToUtc);
|
||||
offsetMinutes := MinutesBetween(ADate, utcDate);
|
||||
|
||||
if timeOffset = 0 then
|
||||
if offsetMinutes = 0 then
|
||||
Result := Result + XMLTimezoneZulu
|
||||
else
|
||||
Result := Result + Format(XMLTimezoneFormat,
|
||||
[XMLTimezoneSigns[timeOffset > 0],
|
||||
Abs(timeZone.Bias div 60),
|
||||
Abs(timeZone.Bias mod 60)]);
|
||||
end;
|
||||
[XMLTimezoneSigns[offsetMinutes > 0], offsetMinutes div 60, offsetMinutes mod 60]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@ -252,8 +314,6 @@ var
|
||||
msec: Integer;
|
||||
hasTimezone: Boolean;
|
||||
xmlOffset: Integer;
|
||||
timeZone: TTimeZoneInformation;
|
||||
localOffset: Integer;
|
||||
|
||||
begin
|
||||
Result := 0;
|
||||
@ -326,7 +386,6 @@ begin
|
||||
if Length(time) > 0 then
|
||||
begin
|
||||
hasTimezone := False;
|
||||
xmlOffset := 0;
|
||||
|
||||
if time[1] = XMLTimezoneZulu then
|
||||
begin
|
||||
@ -343,18 +402,13 @@ begin
|
||||
|
||||
if time[1] = XMLTimezoneSigns[False] then
|
||||
xmlOffset := -xmlOffset;
|
||||
|
||||
Result := IncMinute(Result, - xmlOffset);
|
||||
end;
|
||||
end;
|
||||
|
||||
if hasTimezone then
|
||||
begin
|
||||
FillChar(timeZone, SizeOf(TTimeZoneInformation), #0);
|
||||
if GetTimeZoneInformation(timeZone) <> TIME_ZONE_ID_INVALID then
|
||||
begin
|
||||
localOffset := -timeZone.Bias;
|
||||
Result := IncMinute(Result, localOffset - xmlOffset);
|
||||
end;
|
||||
end;
|
||||
Result := ConvertDate(Result, dcToLocal);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user