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 WriteInteger(const AName: String; AValue: Integer): Boolean; override;
|
||||||
function WriteString(const AName: String; const AValue: String): 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;
|
property Output: IPersistTestOutput read FOutput write FOutput;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -191,7 +196,7 @@ var
|
|||||||
testFiler: TX2UtPersistTestFiler;
|
testFiler: TX2UtPersistTestFiler;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
testFiler := TX2UtPersistTestFiler.Create(AIsReader);;
|
testFiler := TX2UtPersistTestFiler.Create(AIsReader);
|
||||||
testFiler.Output := Self.Output;
|
testFiler.Output := Self.Output;
|
||||||
|
|
||||||
Result := testFiler;
|
Result := testFiler;
|
||||||
@ -266,6 +271,24 @@ begin
|
|||||||
end;
|
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 }
|
{ TPersistTestOutput }
|
||||||
constructor TPersistTestOutput.Create();
|
constructor TPersistTestOutput.Create();
|
||||||
begin
|
begin
|
||||||
|
@ -10,12 +10,16 @@ type
|
|||||||
published
|
published
|
||||||
procedure TestIsValidXMLChar;
|
procedure TestIsValidXMLChar;
|
||||||
procedure TestGetValidXMLText;
|
procedure TestGetValidXMLText;
|
||||||
|
procedure TestXMLToDateTime;
|
||||||
|
procedure TestXMLToDate;
|
||||||
|
procedure TestDateTimeToXML;
|
||||||
|
procedure TestDateToXML;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
XMLDataBindingUtils;
|
XMLDataBindingUtils, DateUtils, SysUtils;
|
||||||
|
|
||||||
|
|
||||||
{ TXMLDataBindingUtilsTest }
|
{ TXMLDataBindingUtilsTest }
|
||||||
@ -33,6 +37,64 @@ begin
|
|||||||
end;
|
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
|
initialization
|
||||||
RegisterTest(TXMLDataBindingUtilsTest.Suite);
|
RegisterTest(TXMLDataBindingUtilsTest.Suite);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ type
|
|||||||
TXMLDateTimeFormat = (xdtDateTime, xdtDate, xdtTime);
|
TXMLDateTimeFormat = (xdtDateTime, xdtDate, xdtTime);
|
||||||
TXMLTimeFragment = (xtfMilliseconds, xtfTimezone);
|
TXMLTimeFragment = (xtfMilliseconds, xtfTimezone);
|
||||||
TXMLTimeFragments = set of TXMLTimeFragment;
|
TXMLTimeFragments = set of TXMLTimeFragment;
|
||||||
|
TDateConvert = (dcToUtc, dcToLocal);
|
||||||
|
|
||||||
IXSDValidate = interface
|
IXSDValidate = interface
|
||||||
['{3BFDC851-7459-403B-87B3-A52E9E85BC8C}']
|
['{3BFDC851-7459-403B-87B3-A52E9E85BC8C}']
|
||||||
@ -197,12 +197,79 @@ begin
|
|||||||
end;
|
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;
|
function DateTimeToXML(ADate: TDateTime; AFormat: TXMLDateTimeFormat; ATimeFragments: TXMLTimeFragments): string;
|
||||||
var
|
var
|
||||||
formatSettings: TFormatSettings;
|
formatSettings: TFormatSettings;
|
||||||
timeZone: TTimeZoneInformation;
|
utcDate: TDateTime;
|
||||||
timeOffset: Integer;
|
offsetMinutes: Integer;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
formatSettings := GetDefaultFormatSettings;
|
formatSettings := GetDefaultFormatSettings;
|
||||||
@ -213,21 +280,16 @@ begin
|
|||||||
if xtfMilliseconds in ATimeFragments then
|
if xtfMilliseconds in ATimeFragments then
|
||||||
Result := Result + FormatDateTime(XMLMsecsFormat, ADate);
|
Result := Result + FormatDateTime(XMLMsecsFormat, ADate);
|
||||||
|
|
||||||
if xtfTimezone in ATimeFragments then
|
if (xtfTimezone in ATimeFragments) then
|
||||||
begin
|
begin
|
||||||
FillChar(timeZone, SizeOf(TTimeZoneInformation), #0);
|
utcDate := ConvertDate(ADate, dcToUtc);
|
||||||
if GetTimeZoneInformation(timeZone) <> TIME_ZONE_ID_INVALID then
|
offsetMinutes := MinutesBetween(ADate, utcDate);
|
||||||
begin
|
|
||||||
timeOffset := -timeZone.Bias;
|
|
||||||
|
|
||||||
if timeOffset = 0 then
|
if offsetMinutes = 0 then
|
||||||
Result := Result + XMLTimezoneZulu
|
Result := Result + XMLTimezoneZulu
|
||||||
else
|
else
|
||||||
Result := Result + Format(XMLTimezoneFormat,
|
Result := Result + Format(XMLTimezoneFormat,
|
||||||
[XMLTimezoneSigns[timeOffset > 0],
|
[XMLTimezoneSigns[offsetMinutes > 0], offsetMinutes div 60, offsetMinutes mod 60]);
|
||||||
Abs(timeZone.Bias div 60),
|
|
||||||
Abs(timeZone.Bias mod 60)]);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -252,8 +314,6 @@ var
|
|||||||
msec: Integer;
|
msec: Integer;
|
||||||
hasTimezone: Boolean;
|
hasTimezone: Boolean;
|
||||||
xmlOffset: Integer;
|
xmlOffset: Integer;
|
||||||
timeZone: TTimeZoneInformation;
|
|
||||||
localOffset: Integer;
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
@ -326,7 +386,6 @@ begin
|
|||||||
if Length(time) > 0 then
|
if Length(time) > 0 then
|
||||||
begin
|
begin
|
||||||
hasTimezone := False;
|
hasTimezone := False;
|
||||||
xmlOffset := 0;
|
|
||||||
|
|
||||||
if time[1] = XMLTimezoneZulu then
|
if time[1] = XMLTimezoneZulu then
|
||||||
begin
|
begin
|
||||||
@ -343,18 +402,13 @@ begin
|
|||||||
|
|
||||||
if time[1] = XMLTimezoneSigns[False] then
|
if time[1] = XMLTimezoneSigns[False] then
|
||||||
xmlOffset := -xmlOffset;
|
xmlOffset := -xmlOffset;
|
||||||
|
|
||||||
|
Result := IncMinute(Result, - xmlOffset);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if hasTimezone then
|
if hasTimezone then
|
||||||
begin
|
Result := ConvertDate(Result, dcToLocal);
|
||||||
FillChar(timeZone, SizeOf(TTimeZoneInformation), #0);
|
|
||||||
if GetTimeZoneInformation(timeZone) <> TIME_ZONE_ID_INVALID then
|
|
||||||
begin
|
|
||||||
localOffset := -timeZone.Bias;
|
|
||||||
Result := IncMinute(Result, localOffset - xmlOffset);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
Loading…
Reference in New Issue
Block a user