diff --git a/Lib/Core/IdCompilerDefines.inc b/Lib/Core/IdCompilerDefines.inc index f9bc13038..2c10c4e46 100644 --- a/Lib/Core/IdCompilerDefines.inc +++ b/Lib/Core/IdCompilerDefines.inc @@ -1234,6 +1234,7 @@ {$DEFINE HAS_PVOID} {$DEFINE HAS_ULONG64} {$DEFINE HAS_TEncoding_GetEncoding_ByEncodingName} + {$DEFINE HAS_DateUtils_TTimeZone} {$IFDEF DCC} // Exception.RaiseOuterException() is now available on all platforms {$DEFINE HAS_Exception_RaiseOuterException} diff --git a/Lib/FCL/IdCompilerDefines.inc b/Lib/FCL/IdCompilerDefines.inc index f9bc13038..2c10c4e46 100644 --- a/Lib/FCL/IdCompilerDefines.inc +++ b/Lib/FCL/IdCompilerDefines.inc @@ -1234,6 +1234,7 @@ {$DEFINE HAS_PVOID} {$DEFINE HAS_ULONG64} {$DEFINE HAS_TEncoding_GetEncoding_ByEncodingName} + {$DEFINE HAS_DateUtils_TTimeZone} {$IFDEF DCC} // Exception.RaiseOuterException() is now available on all platforms {$DEFINE HAS_Exception_RaiseOuterException} diff --git a/Lib/Protocols/IdCompilerDefines.inc b/Lib/Protocols/IdCompilerDefines.inc index f9bc13038..2c10c4e46 100644 --- a/Lib/Protocols/IdCompilerDefines.inc +++ b/Lib/Protocols/IdCompilerDefines.inc @@ -1234,6 +1234,7 @@ {$DEFINE HAS_PVOID} {$DEFINE HAS_ULONG64} {$DEFINE HAS_TEncoding_GetEncoding_ByEncodingName} + {$DEFINE HAS_DateUtils_TTimeZone} {$IFDEF DCC} // Exception.RaiseOuterException() is now available on all platforms {$DEFINE HAS_Exception_RaiseOuterException} diff --git a/Lib/Protocols/IdFSP.pas b/Lib/Protocols/IdFSP.pas index e7c7162d0..71a78c413 100644 --- a/Lib/Protocols/IdFSP.pas +++ b/Lib/Protocols/IdFSP.pas @@ -473,7 +473,7 @@ procedure ParseStatInfo(const AData : TIdBytes; VL : TIdFSPStatInfo; var VI : UI CopyBytesToHostUInt32(AData, VI, LC); VL.FModifiedDateGMT := UnixDateTimeToDelphiDateTime(LC); - VL.FModifiedDate := VL.FModifiedDateGMT + OffSetFromUTC; + VL.FModifiedDate := UTCTimeToLocalTime(VL.FModifiedDateGMT); Inc(VI, 4); CopyBytesToHostUInt32(AData, VI, LC); diff --git a/Lib/Protocols/IdFTP.pas b/Lib/Protocols/IdFTP.pas index fb4fa71b6..c3d90279b 100644 --- a/Lib/Protocols/IdFTP.pas +++ b/Lib/Protocols/IdFTP.pas @@ -4024,7 +4024,7 @@ procedure TIdFTP.SetModTime(const AFileName: String; const ALocalTime: TDateTime //syntax 3 - MDTM [local timestamp] Filename else if FTZInfo.FGMTOffsetAvailable then begin //send it relative to the server's time-zone - LCmd := 'MDTM '+ FTPDateTimeToMDTMD(ALocalTime - OffSetFromUTC + FTZInfo.FGMTOffset, False, False) + ' ' + AFileName; {do not localize} + LCmd := 'MDTM '+ FTPDateTimeToMDTMD(LocalTimeToUTCTime(ALocalTime) + FTZInfo.FGMTOffset, False, False) + ' ' + AFileName; {do not localize} end else begin @@ -4067,7 +4067,7 @@ procedure TIdFTP.SetModTimeGMT(const AFileName : String; const AGMTTime: TDateTi //Syntax 2 - MDTM yyyymmddhhmmss[+-minutes from Universal Time] Filename //use old method for old versions of Serv-U and BPFTP Server else if (IndexOfFeatLine('MDTM YYYYMMDDHHMMSS[+-TZ] filename') > 0) or IsOldServU or IsBPFTP then begin {do not localize} - LCmd := 'MDTM '+ FTPDateTimeToMDTMD(AGMTTime + OffSetFromUTC, False, True) + ' ' + AFileName; {do not localize} + LCmd := 'MDTM '+ FTPDateTimeToMDTMD(UTCTimeToLocalTime(AGMTTime), False, True) + ' ' + AFileName; {do not localize} end //syntax 3 - MDTM [local timestamp] Filename @@ -4077,7 +4077,7 @@ procedure TIdFTP.SetModTimeGMT(const AFileName : String; const AGMTTime: TDateTi end else begin - LCmd := 'MDTM '+ FTPDateTimeToMDTMD(AGMTTime + OffSetFromUTC, False, False) + ' ' + AFileName; {do not localize} + LCmd := 'MDTM '+ FTPDateTimeToMDTMD(UTCTimeToLocalTime(AGMTTime), False, False) + ' ' + AFileName; {do not localize} end; // When using MDTM, Titan FTP 5 returns 200 and vsFTPd returns 213 diff --git a/Lib/Protocols/IdFTPCommon.pas b/Lib/Protocols/IdFTPCommon.pas index 66b6c1989..6c62150b3 100644 --- a/Lib/Protocols/IdFTPCommon.pas +++ b/Lib/Protocols/IdFTPCommon.pas @@ -663,6 +663,7 @@ implementation Posix.SysTime, Posix.Time, {$ENDIF} + {$IFDEF HAS_DateUtils_TTimeZone}DateUtils,{$ENDIF} IdException; {WS_FTP Pro XAUT Support} @@ -1219,7 +1220,7 @@ function EPLFDateToLocalDateTime(const AData: String): TDateTime; LSecs : Int64; begin LSecs := IndyStrToInt(AData); - Result := Extended( ((LSecs)/ (24 * 60 * 60) ) + Int(BASE_DATE)) - IdGlobalProtocols.TimeZoneBias; + Result := UTCTimeToLocalTime( Extended( ((LSecs)/ (24 * 60 * 60) ) + Int(BASE_DATE)) ); end; function EPLFDateToGMTDateTime(const AData: String): TDateTime; @@ -1242,7 +1243,7 @@ function GMTDateTimeToEPLFDate(const ADateTime : TDateTime) : String; function LocalDateTimeToEPLFDate(const ADateTime : TDateTime) : String; {$IFDEF USE_INLINE} inline; {$ENDIF} begin - Result := FloatToStr( Extended(ADateTime + IdGlobalProtocols.TimeZoneBias - Int(EPLF_BASE_DATE)) * 24 * 60 * 60); + Result := FloatToStr( Extended( LocalTimeToUTCTime(ADateTime) - Int(EPLF_BASE_DATE)) * 24 * 60 * 60); end; {Date routines} @@ -1343,11 +1344,27 @@ function MDTMOffset(const AOffs : String) : TDateTime; end; function MinutesFromGMT : Integer; +{$IFDEF HAS_GetLocalTimeOffset} {$IFDEF USE_INLINE} inline; {$ENDIF} +{$ELSE} + {$IFDEF HAS_DateUtils_TTimeZone} + {$IFDEF USE_INLINE} inline; {$ENDIF} + {$ELSE} var LD : TDateTime; LHour, LMin, LSec, LMSec : Word; + {$ENDIF} +{$ENDIF} begin + {$IFDEF HAS_GetLocalTimeOffset} + // RLebeau: Note that on Linux/Unix, this information may be inaccurate around + // the DST time changes (for optimization). In that case, the unix.ReReadLocalTime() + // function must be used to re-initialize the timezone information... + Result := {-1 *} GetLocalTimeOffset(); + {$ELSE} + {$IFDEF HAS_DateUtils_TTimeZone} + Result := {-1 *} TTimeZone.Local.UtcOffset.TotalMinutes; + {$ELSE} LD := OffsetFromUTC; DecodeTime(LD, LHour, LMin, LSec, LMSec); if LD < 0.0 then begin @@ -1355,6 +1372,8 @@ function MinutesFromGMT : Integer; end else begin Result := LHour * 60 + LMin; end; + {$ENDIF} + {$ENDIF} end; function FTPDateTimeToMDTMD(const ATimeStamp : TDateTime; const AIncludeMSecs : Boolean=True; const AIncludeGMTOffset : Boolean=True): String; @@ -1415,7 +1434,7 @@ function FTPMDTMToGMTDateTime(const ATimeStamp : String):TDateTime; Result := EncodeDate(LYear, LMonth, LDay); Result := Result + EncodeTime(LHour, LMin, LSec, LMSec); if LOffset = '' then begin - Result := Result - OffsetFromUTC; + Result := LocalTimeToUTCTime(Result); end else begin Result := Result - MDTMOffset(LOffset); end; diff --git a/Lib/Protocols/IdFTPListOutput.pas b/Lib/Protocols/IdFTPListOutput.pas index e62c582d3..53f891b45 100644 --- a/Lib/Protocols/IdFTPListOutput.pas +++ b/Lib/Protocols/IdFTPListOutput.pas @@ -596,7 +596,7 @@ function TIdFTPListOutput.GetItems(AIndex: Integer): TIdFTPListOutputItem; function TIdFTPListOutput.GetLocalModTime(AItem: TIdFTPListOutputItem): TDateTime; begin if AItem.ModifiedDateGMT <> 0 then begin - Result := AItem.ModifiedDateGMT - TimeZoneBias; + Result := UTCTimeToLocalTime(AItem.ModifiedDateGMT); end else begin Result := AItem.ModifiedDate; end; diff --git a/Lib/Protocols/IdFTPListParseDistinctTCPIP.pas b/Lib/Protocols/IdFTPListParseDistinctTCPIP.pas index 5dc4d648b..2e78e05ee 100644 --- a/Lib/Protocols/IdFTPListParseDistinctTCPIP.pas +++ b/Lib/Protocols/IdFTPListParseDistinctTCPIP.pas @@ -193,7 +193,7 @@ class function TIdFTPLPDistinctTCPIP.ParseLine(const AItem: TIdFTPListItem; // 12/29/2002 01:42p 23 CreateTest.txt // I suspect that this server returns the timestamp as GMT LI.ModifiedDateGMT := LI.ModifiedDate; - LI.ModifiedDate := LI.ModifiedDate - TimeZoneBias; + LI.ModifiedDate := UTCTimeToLocalTime(LI.ModifiedDateGMT); // file name LBuf := StripSpaces(LBuf, 1); LI.FileName := LBuf; diff --git a/Lib/Protocols/IdFTPServer.pas b/Lib/Protocols/IdFTPServer.pas index f6f128ad8..e8f0e1c80 100644 --- a/Lib/Protocols/IdFTPServer.pas +++ b/Lib/Protocols/IdFTPServer.pas @@ -5312,7 +5312,7 @@ procedure TIdFTPServer.DoOnGetFileDate(ASender: TIdFTPServerContext; LFileSystem := FTPFileSystem; if Assigned(LFileSystem) then begin LFileSystem.GetFileDate(ASender, AFileName, VFileDate); - VFileDate := VFileDate - OffsetFromUTC; + VFileDate := LocalTimeToUTCTime(VFileDate); end else if Assigned(FOnGetFileDate) then begin FOnGetFileDate(ASender, AFileName, VFileDate); end; @@ -5477,7 +5477,7 @@ procedure TIdFTPServer.CommandSiteUTIME(ASender: TIdCommand); if IsValidTimeStamp(ALSender.Params[0]) then begin LFileName := ALSender.UnparsedParams; //This is local Time - LgMTime := FTPMLSToGMTDateTime(Fetch(LFileName)) - OffsetFromUTC; + LgMTime := UTCTimeToLocalTime(FTPMLSToGMTDateTime(Fetch(LFileName))); LFileName := DoProcessPath(AContext, LFileName); if Assigned(FOnSiteUTIME) then begin @@ -6200,14 +6200,16 @@ procedure TIdFTPServer.CommandCPSV(ASender: TIdCommand); procedure TIdFTPServer.CommandSiteZONE(ASender: TIdCommand); var LMin : Integer; + LFmt: string; begin LMin := MinutesFromGMT; //plus must always be displayed for positive numbers if LMin < 0 then begin - ASender.Reply.SetReply(210, IndyFormat('UTC%d', [MinutesFromGMT])); {do not localize} + LFmt := 'UTC%d'; {do not localize} end else begin - ASender.Reply.SetReply(210, IndyFormat('UTC+%d', [MinutesFromGMT])); {do not localize} + LFmt := 'UTC+%d'; {do not localize} end; + ASender.Reply.SetReply(210, IndyFormat(LFmt, [LMin])); end; procedure TIdFTPServer.CommandCheckSum(ASender: TIdCommand); diff --git a/Lib/Protocols/IdGlobalProtocols.pas b/Lib/Protocols/IdGlobalProtocols.pas index c7e29101f..a5cb2c50e 100644 --- a/Lib/Protocols/IdGlobalProtocols.pas +++ b/Lib/Protocols/IdGlobalProtocols.pas @@ -523,7 +523,7 @@ EIdExtensionAlreadyExists = class(EIdException); function StrToDay(const ADay: string): Byte; function StrToMonth(const AMonth: string): Byte; function StrToWord(const Value: String): Word; - function TimeZoneBias: TDateTime; + function TimeZoneBias: TDateTime; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IdGlobal.LocalTimeToUTCTime() or IdGlobal.UTCTimeToLocalTime()'{$ENDIF};{$ENDIF} //these are for FSP but may also help with MySQL function UnixDateTimeToDelphiDateTime(UnixDateTime: UInt32): TDateTime; function DateTimeToUnix(ADateTime: TDateTime): UInt32; @@ -593,14 +593,8 @@ implementation {$ENDIF} {$ENDIF} IdIPAddress, - {$IFDEF HAS_GetLocalTimeOffset} - DateUtils, - {$ENDIF} {$IFDEF UNIX} {$IFDEF USE_VCL_POSIX} - {$IFNDEF HAS_GetLocalTimeOffset} - DateUtils, - {$ENDIF} Posix.SysStat, Posix.SysTime, Posix.Time, Posix.Unistd, {$ELSE} {$IFDEF KYLIXCOMPAT} @@ -608,13 +602,13 @@ implementation {$ELSE} {$IFDEF USE_BASEUNIX} BaseUnix, Unix, - {$IFNDEF HAS_GetLocalTimeOffset} - DateUtils, - {$ENDIF} {$ENDIF} {$ENDIF} {$ENDIF} {$ENDIF} + {$IFDEF HAS_UNIT_DateUtils} + DateUtils, + {$ENDIF} {$IFDEF WINDOWS} Messages, Registry, @@ -1352,7 +1346,7 @@ function FTPMLSToLocalDateTime(const ATimeStamp : String):TDateTime; if ATimeStamp <> '' then begin Result := FTPMLSToGMTDateTime(ATimeStamp); // Apply local offset - Result := {$IFDEF HAS_UniversalTimeToLocal}UniversalTimeToLocal(Result){$ELSE}Result + OffsetFromUTC{$ENDIF}; + Result := UTCTimeToLocalTime(Result); end; end; @@ -1378,13 +1372,7 @@ function FTPGMTDateTimeToMLS(const ATimeStamp : TDateTime; const AIncludeMSecs : function FTPLocalDateTimeToMLS(const ATimeStamp : TDateTime; const AIncludeMSecs : Boolean=True): String; {$IFDEF USE_INLINE} inline; {$ENDIF} begin - Result := FTPGMTDateTimeToMLS( - {$IFDEF HAS_LocalTimeToUniversal} - LocalTimeToUniversal(ATimeStamp) - {$ELSE} - ATimeStamp - OffsetFromUTC - {$ENDIF} - , AIncludeMSecs); + Result := FTPGMTDateTimeToMLS(LocalTimeToUTCTime(ATimeStamp), AIncludeMSecs); end; @@ -1981,36 +1969,12 @@ function RightStr(const AStr: String; const Len: Integer): String; end; end; +{$I IdDeprecatedImplBugOff.inc} function TimeZoneBias: TDateTime; -{$IFNDEF FPC} - {$IFDEF UNIX} -var - T: Time_T; - TV: TimeVal; - UT: {$IFDEF USE_VCL_POSIX}tm{$ELSE}TUnixTime{$ENDIF}; - {$ELSE} - {$IFDEF USE_INLINE} inline; {$ENDIF} - {$ENDIF} -{$ELSE} +{$I IdDeprecatedImplBugOn.inc} {$IFDEF USE_INLINE} inline; {$ENDIF} -{$ENDIF} begin -{$IFNDEF FPC} - {$IFDEF UNIX} - // TODO: use -OffsetFromUTC here. It has this same Unix logic in it - {from http://edn.embarcadero.com/article/27890 } - gettimeofday(TV, nil); - T := TV.tv_sec; - localtime_r({$IFNDEF USE_VCL_POSIX}@{$ENDIF}T, UT); -// __tm_gmtoff is the bias in seconds from the UTC to the current time. -// so I multiply by -1 to compensate for this. - Result := (UT.{$IFNDEF USE_VCL_POSIX}__tm_gmtoff{$ELSE}tm_gmtoff{$ENDIF} / 60 / 60 / 24); - {$ELSE} - Result := -OffsetFromUTC; - {$ENDIF} -{$ELSE} Result := -OffsetFromUTC; -{$ENDIF} end; function IndyStrToBool(const AString : String) : Boolean; @@ -2810,8 +2774,7 @@ function GMTToLocalDateTime(S: string): TDateTime; if RawStrInternetToDateTime(S, Result) then begin DateTimeOffset := GmtOffsetStrToDateTime(S); {-Apply GMT and local offsets} - Result := Result - DateTimeOffset; - Result := {$IFDEF HAS_UniversalTimeToLocal}UniversalTimeToLocal(Result){$ELSE}Result + OffsetFromUTC{$ENDIF}; + Result := UTCTimeToLocalTime(Result - DateTimeOffset); end; end; @@ -3066,7 +3029,7 @@ function CookieStrToLocalDateTime(S: string): TDateTime; end; Result := EncodeDate(LYear, LMonth, LDayOfMonth) + EncodeTime(LHour, LMinute, LSecond, 0); - Result := {$IFDEF HAS_UniversalTimeToLocal}UniversalTimeToLocal(Result){$ELSE}Result + OffsetFromUTC{$ENDIF}; + Result := UTCTimeToLocalTime(Result); except Result := 0.0; end; diff --git a/Lib/Protocols/IdHTTPWebBrokerBridge.pas b/Lib/Protocols/IdHTTPWebBrokerBridge.pas index df14e7077..c7b5ca0e4 100644 --- a/Lib/Protocols/IdHTTPWebBrokerBridge.pas +++ b/Lib/Protocols/IdHTTPWebBrokerBridge.pas @@ -628,7 +628,7 @@ function TIdHTTPAppResponse.GetDateVariable(Index: Integer): TDateTime; begin Result := ADateTime; if Result <> -1 then - Result := Result - OffsetFromUTC; + Result := LocalTimeToUTCTime(Result); end; begin //TODO: resource string these @@ -647,7 +647,7 @@ procedure TIdHTTPAppResponse.SetDateVariable(Index: Integer; const Value: TDateT begin Result := ADateTime; if Result <> -1 then - Result := Result + OffsetFromUTC; + Result := UTCTimeToLocalTime(Result); end; begin //TODO: resource string these diff --git a/Lib/Protocols/IdNNTPServer.pas b/Lib/Protocols/IdNNTPServer.pas index 47a4e5bd6..d1f0ca978 100644 --- a/Lib/Protocols/IdNNTPServer.pas +++ b/Lib/Protocols/IdNNTPServer.pas @@ -463,7 +463,7 @@ class function TIdNNTPServer.NNTPTimeToTime(const ATimeStamp : String): TDateTim if TextIsSame(LTimeStr, 'GMT') then {do not localize} begin // Apply local offset - Result := Result + OffsetFromUTC; + Result := UTCTimeToLocalTime(Result); end; end else begin Result := 0.0; @@ -652,7 +652,7 @@ procedure TIdNNTPServer.CommandBody(ASender: TIdCommand); procedure TIdNNTPServer.CommandDate(ASender: TIdCommand); begin if not SecLayerRequired(ASender) then begin - ASender.Reply.SetReply(111, FormatDateTime('yyyymmddhhnnss', Now + TimeZoneBias)); {do not localize} + ASender.Reply.SetReply(111, FormatDateTime('yyyymmddhhnnss', LocalTimeToUTCTime(Now))); {do not localize} end; end; @@ -1551,7 +1551,7 @@ procedure TIdNNTPServer.CommandNewGroups(ASender: TIdCommand); LDate := LDate + NNTPTimeToTime(ASender.Params[1]); if ASender.Params.Count > 2 then begin if TextIsSame(ASender.Params[2], 'GMT') then begin {Do not translate} - LDate := LDate + OffSetFromUTC; + LDate := UTCTimeToLocalTime(LDate); if ASender.Params.Count > 3 then begin LDist := ASender.Params[3]; end; @@ -1587,7 +1587,7 @@ procedure TIdNNTPServer.CommandNewNews(ASender: TIdCommand); LDate := LDate + NNTPTimeToTime(ASender.Params[2]); if ASender.Params.Count > 3 then begin if TextIsSame(ASender.Params[3], 'GMT') then begin {Do not translate} - LDate := LDate + OffsetFromUTC; + LDate := UTCTimeToLocalTime(LDate); if ASender.Params.Count > 4 then begin LDist := ASender.Params[4]; end; diff --git a/Lib/Protocols/IdSNTP.pas b/Lib/Protocols/IdSNTP.pas index 0f55144d8..e32f1cabb 100644 --- a/Lib/Protocols/IdSNTP.pas +++ b/Lib/Protocols/IdSNTP.pas @@ -149,7 +149,7 @@ procedure TIdSNTP.DateTimeToNTP(ADateTime: TDateTime; var Second, Fraction: UInt var Value1, Value2: Double; begin - Value1 := (ADateTime + TimeZoneBias - 2) * 86400; + Value1 := (LocalTimeToUTCTime(ADateTime) - 2) * 86400; Value2 := Value1; if Value2 > NTPMaxInt then @@ -191,7 +191,7 @@ function TIdSNTP.NTPToDateTime(Second, Fraction: UInt32): TDateTime; // Value2 := Trunc(Value2 * 1000) / 1000; Value2 := Trunc(Value2 / NTPMaxInt * 1000) / 1000; - Result := ((Value1 + Value2) / 86400) - TimeZoneBias + 2; + Result := UTCTimeToLocalTime((Value1 + Value2) / 86400) + 2; end ; { TIdSNTP } @@ -232,6 +232,7 @@ function TIdSNTP.GetDateTime: TDateTime; var LNTPDataGram: TNTPGram; LBuffer : TIdBytes; + LBytesRecvd: Integer; begin // DS default result is an empty TDateTime value Result := 0.0; @@ -245,10 +246,10 @@ function TIdSNTP.GetDateTime: TDateTime; CopyTIdUInt32(GStack.HostToNetwork(LNTPDataGram.Xmit2), LBuffer, 44); SendBuffer(LBuffer); - ReceiveBuffer(LBuffer); + LBytesRecvd := ReceiveBuffer(LBuffer); // DS response may contain optional NTP authentication scheme info not in NTPGram - if Length(LBuffer) >= SizeOf(TNTPGram) then + if LBytesRecvd >= SizeOf(TNTPGram) then begin FDestinationTimeStamp := Now; diff --git a/Lib/Protocols/IdSSLOpenSSL.pas b/Lib/Protocols/IdSSLOpenSSL.pas index 69f2c688e..ed556c291 100644 --- a/Lib/Protocols/IdSSLOpenSSL.pas +++ b/Lib/Protocols/IdSSLOpenSSL.pas @@ -2131,12 +2131,6 @@ function AddHrs(const DT: TDateTime; const Hrs: Extended): TDateTime; Result := DT + Hrs / 24.0; end; -function GetLocalTime(const DT: TDateTime): TDateTime; -{$IFDEF USE_INLINE} inline; {$ENDIF} -begin - Result := DT - TimeZoneBias { / (24 * 60) } ; -end; - {$IFDEF OPENSSL_SET_MEMORY_FUNCS} function IdMalloc(num: UInt32): Pointer cdecl; @@ -2287,12 +2281,11 @@ function UTCTime2DateTime(UCTTime: PASN1_UTCTIME): TDateTime; tz_m: Integer; begin Result := 0; - if UTC_Time_Decode(UCTTime, year, month, day, hour, min, sec, tz_h, - tz_m) > 0 then begin + if UTC_Time_Decode(UCTTime, year, month, day, hour, min, sec, tz_h, tz_m) > 0 then begin Result := EncodeDate(year, month, day) + EncodeTime(hour, min, sec, 0); AddMins(Result, tz_m); AddHrs(Result, tz_h); - Result := GetLocalTime(Result); + Result := UTCTimeToLocalTime(Result); end; end; diff --git a/Lib/Protocols/IdSSLOpenSSLUtils.pas b/Lib/Protocols/IdSSLOpenSSLUtils.pas index 314a590ed..3ef8f2891 100644 --- a/Lib/Protocols/IdSSLOpenSSLUtils.pas +++ b/Lib/Protocols/IdSSLOpenSSLUtils.pas @@ -40,7 +40,7 @@ procedure LockVerifyCB_Leave; // function AddMins(const DT: TDateTime; const Mins: Extended): TDateTime; function AddHrs(const DT: TDateTime; const Hrs: Extended): TDateTime; -function GetLocalTime(const DT: TDateTime): TDateTime; +function GetLocalTime(const DT: TDateTime): TDateTime; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IdGlobal.UTCTimeToLocalTime()'{$ENDIF};{$ENDIF} function IndySSL_load_client_CA_file(const AFileName: String) : PSTACK_OF_X509_NAME; function IndySSL_CTX_use_PrivateKey_file(ctx: PSSL_CTX; const AFileName: String; @@ -673,10 +673,12 @@ function AddHrs(const DT: TDateTime; const Hrs: Extended): TDateTime; Result := DT + Hrs / 24.0; end; +{$I IdDeprecatedImplBugOff.inc} function GetLocalTime(const DT: TDateTime): TDateTime; +{$I IdDeprecatedImplBugOn.inc} {$IFDEF USE_INLINE} inline; {$ENDIF} begin - Result := DT - TimeZoneBias { / (24 * 60) } ; + Result := UTCTimeToLocalTime(DT); end; {$IFDEF OPENSSL_SET_MEMORY_FUNCS} diff --git a/Lib/Protocols/IdTime.pas b/Lib/Protocols/IdTime.pas index 721701ea5..a8bf726e6 100644 --- a/Lib/Protocols/IdTime.pas +++ b/Lib/Protocols/IdTime.pas @@ -176,8 +176,7 @@ function TIdCustomTime.GetDateTime: TDateTime; if BufCard <> 0 then begin {The formula is The Time cardinal we receive divided by (24 * 60*60 for days + RoundTrip divided by one-thousand since this is based on seconds - the Time Zone difference} - Result := ( ((BufCard + (FRoundTripDelay div 1000))/ (24 * 60 * 60) ) + Int(fBaseDate)) - -TimeZoneBias; + Result := UTCTimeToLocalTime( ((BufCard + (FRoundTripDelay div 1000))/ (24 * 60 * 60) ) + Int(fBaseDate) ); end else begin { Somehow, I really doubt we are ever going to really get a time such as diff --git a/Lib/Protocols/IdTimeServer.pas b/Lib/Protocols/IdTimeServer.pas index 2acdfd62c..501b96f99 100644 --- a/Lib/Protocols/IdTimeServer.pas +++ b/Lib/Protocols/IdTimeServer.pas @@ -135,7 +135,7 @@ procedure TIdCustomTimeServer.InitComponent; function TIdCustomTimeServer.DoExecute(AContext: TIdContext): Boolean; begin Result := true; - AContext.Connection.IOHandler.Write(UInt32(Trunc(Extended(Now + TimeZoneBias - Int(FBaseDate)) * 24 * 60 * 60))); + AContext.Connection.IOHandler.Write(UInt32(Trunc(Extended(LocalTimeToUTCTime(Now) - Int(FBaseDate)) * 24 * 60 * 60))); AContext.Connection.Disconnect; end; diff --git a/Lib/Protocols/IdTimeUDP.pas b/Lib/Protocols/IdTimeUDP.pas index 209e9c90a..305ba52cf 100644 --- a/Lib/Protocols/IdTimeUDP.pas +++ b/Lib/Protocols/IdTimeUDP.pas @@ -127,8 +127,7 @@ function TIdCustomTimeUDP.GetDateTime: TDateTime; if BufCard <> 0 then begin {The formula is The Time cardinal we receive divided by (24 * 60*60 for days + RoundTrip divided by one-thousand since this is based on seconds - the Time Zone difference} - Result := ( ((BufCard + (FRoundTripDelay div 1000))/ (24 * 60 * 60) ) + Int(fBaseDate)) - - TimeZoneBias; + Result := UTCTimeToLocalTime( ((BufCard + (FRoundTripDelay div 1000))/ (24 * 60 * 60) ) + Int(fBaseDate) ); end else begin { Somehow, I really doubt we are ever going to really get a time such as 12/30/1899 12:00 am so use that as a failure test} diff --git a/Lib/Protocols/IdTimeUDPServer.pas b/Lib/Protocols/IdTimeUDPServer.pas index 71868d14d..f58774d26 100644 --- a/Lib/Protocols/IdTimeUDPServer.pas +++ b/Lib/Protocols/IdTimeUDPServer.pas @@ -97,7 +97,7 @@ procedure TIdCustomTimeUDPServer.DoUDPRead(AThread: TIdUDPListenerThread; LTime : UInt32; begin inherited DoUDPRead(AThread, AData, ABinding); - LTime := Trunc(Extended(Now + TimeZoneBias - Int(FBaseDate)) * 24 * 60 * 60); + LTime := Trunc(Extended(LocalTimeToUTCTime(Now) - Int(FBaseDate)) * 24 * 60 * 60); LTime := GStack.HostToNetwork(LTime); ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, ToBytes(LTime), ABinding.IPVersion); end; diff --git a/Lib/SuperCore/IdCompilerDefines.inc b/Lib/SuperCore/IdCompilerDefines.inc index f9bc13038..2c10c4e46 100644 --- a/Lib/SuperCore/IdCompilerDefines.inc +++ b/Lib/SuperCore/IdCompilerDefines.inc @@ -1234,6 +1234,7 @@ {$DEFINE HAS_PVOID} {$DEFINE HAS_ULONG64} {$DEFINE HAS_TEncoding_GetEncoding_ByEncodingName} + {$DEFINE HAS_DateUtils_TTimeZone} {$IFDEF DCC} // Exception.RaiseOuterException() is now available on all platforms {$DEFINE HAS_Exception_RaiseOuterException} diff --git a/Lib/System/IdCompilerDefines.inc b/Lib/System/IdCompilerDefines.inc index f9bc13038..2c10c4e46 100644 --- a/Lib/System/IdCompilerDefines.inc +++ b/Lib/System/IdCompilerDefines.inc @@ -1234,6 +1234,7 @@ {$DEFINE HAS_PVOID} {$DEFINE HAS_ULONG64} {$DEFINE HAS_TEncoding_GetEncoding_ByEncodingName} + {$DEFINE HAS_DateUtils_TTimeZone} {$IFDEF DCC} // Exception.RaiseOuterException() is now available on all platforms {$DEFINE HAS_Exception_RaiseOuterException} diff --git a/Lib/System/IdGlobal.pas b/Lib/System/IdGlobal.pas index f4d4ae883..2692003f5 100644 --- a/Lib/System/IdGlobal.pas +++ b/Lib/System/IdGlobal.pas @@ -1865,6 +1865,9 @@ function MemoryPos(const ASubStr: string; MemBuff: PChar; MemorySize: Integer): function OffsetFromUTC: TDateTime; function UTCOffsetToStr(const AOffset: TDateTime; const AUseGMTStr: Boolean = False): string; +function LocalTimeToUTCTime(const Value: TDateTime): TDateTime; +function UTCTimeToLocalTime(const Value: TDateTime): TDateTime; + function PosIdx(const ASubStr, AStr: string; AStartPos: UInt32 = 0): UInt32; //For "ignoreCase" use AnsiUpperCase function PosInSmallIntArray(const ASearchInt: Int16; const AArray: array of Int16): Integer; function PosInStrArray(const SearchStr: string; const Contents: array of string; const CaseSensitive: Boolean = True): Integer; @@ -7754,37 +7757,19 @@ function DateTimeGMTToImapStr(const GMTValue: TDateTime) : String; function LocalDateTimeToHttpStr(const Value: TDateTime) : String; {$IFDEF USE_INLINE}inline;{$ENDIF} begin - Result := DateTimeGMTToHttpStr( - {$IFDEF HAS_LocalTimeToUniversal} - LocalTimeToUniversal(Value) - {$ELSE} - Value - OffsetFromUTC - {$ENDIF} - ); + Result := DateTimeGMTToHttpStr(LocalTimeToUTCTime(Value)); end; function LocalDateTimeToCookieStr(const Value: TDateTime; const AUseNetscapeFmt: Boolean = True) : String; {$IFDEF USE_INLINE}inline;{$ENDIF} begin - Result := DateTimeGMTToCookieStr( - {$IFDEF HAS_LocalTimeToUniversal} - LocalTimeToUniversal(Value) - {$ELSE} - Value - OffsetFromUTC - {$ENDIF} - , AUseNetscapeFmt); + Result := DateTimeGMTToCookieStr(LocalTimeToUTCTime(Value), AUseNetscapeFmt); end; function LocalDateTimeToImapStr(const Value: TDateTime) : String; {$IFDEF USE_INLINE}inline;{$ENDIF} begin - Result := DateTimeGMTToImapStr( - {$IFDEF HAS_LocalTimeToUniversal} - LocalTimeToUniversal(Value) - {$ELSE} - Value - OffsetFromUTC - {$ENDIF} - ); + Result := DateTimeGMTToImapStr(LocalTimeToUTCTime(Value)); end; {$I IdDeprecatedImplBugOff.inc} @@ -7852,7 +7837,16 @@ function OffsetFromUTC: TDateTime; {$IFDEF DOTNET} Result := System.Timezone.CurrentTimezone.GetUTCOffset(DateTime.FromOADate(Now)).TotalDays; {$ELSE} - {$IFDEF WINDOWS} + {$IFDEF HAS_GetLocalTimeOffset} + // RLebeau: Note that on Linux/Unix, this information may be inaccurate around + // the DST time changes (for optimization). In that case, the unix.ReReadLocalTime() + // function must be used to re-initialize the timezone information... + Result := GetLocalTimeOffset() / 60 / 24; + {$ELSE} + {$IFDEF HAS_DateUtils_TTimeZone} + Result := TTimeZone.Local.UtcOffset.TotalMinutes / 60 / 24; + {$ELSE} + {$IFDEF WINDOWS} case GetTimeZoneInformation({$IFDEF WINCE}@{$ENDIF}tmez) of TIME_ZONE_ID_INVALID : raise EIdFailedToRetreiveTimeZoneInfo.Create(RSFailedTimeZoneInfo); @@ -7884,37 +7878,32 @@ function OffsetFromUTC: TDateTime; if iBias > 0 then begin Result := 0.0 - Result; end; - {$ELSE} - {$IFDEF HAS_GetLocalTimeOffset} - // RLebeau: Note that on Linux/Unix, this information may be inaccurate around - // the DST time changes (for optimization). In that case, the unix.ReReadLocalTime() - // function must be used to re-initialize the timezone information... - Result := -1 * (GetLocalTimeOffset() / 60 / 24); - {$ELSE} - {$IFDEF UNIX} + {$ELSE} + {$IFDEF UNIX} // TODO: raise EIdFailedToRetreiveTimeZoneInfo if gettimeofday() fails... - {$IFDEF KYLIXCOMPAT_OR_VCL_POSIX} + {$IFDEF KYLIXCOMPAT_OR_VCL_POSIX} {from http://edn.embarcadero.com/article/27890 but without multiplying the Result by -1} gettimeofday(TV, nil); T := TV.tv_sec; localtime_r({$IFDEF KYLIXCOMPAT}@{$ENDIF}T, UT); Result := UT.{$IFDEF KYLIXCOMPAT}__tm_gmtoff{$ELSE}tm_gmtoff{$ENDIF} / 60 / 60 / 24; - {$ELSE} - {$IFDEF USE_BASEUNIX} + {$ELSE} + {$IFDEF USE_BASEUNIX} fpGetTimeOfDay (@TimeVal, @TimeZone); Result := -1 * (timezone.tz_minuteswest / 60 / 24); - {$ELSE} + {$ELSE} {$message error gettimeofday is not called on this platform!} Result := GOffsetFromUTC; + {$ENDIF} {$ENDIF} - {$ENDIF} - {$ELSE} + {$ELSE} {$message error no platform API called to get UTC offset!} Result := GOffsetFromUTC; + {$ENDIF} {$ENDIF} {$ENDIF} {$ENDIF} @@ -7956,6 +7945,32 @@ function UTCOffsetToStr(const AOffset: TDateTime; const AUseGMTStr: Boolean = Fa end; end; +function LocalTimeToUTCTime(const Value: TDateTime): TDateTime; +begin + {$IFDEF HAS_LocalTimeToUniversal} + Result := LocalTimeToUniversal(Value); + {$ELSE} + {$IFDEF HAS_DateUtils_TTimeZone} + Result := TTimeZone.Local.ToUniversalTime(Value); + {$ELSE} + Result := Value - OffsetFromUTC; + {$ENDIF} + {$ENDIF} +end; + +function UTCTimeToLocalTime(const Value: TDateTime): TDateTime; +begin + {$IFDEF HAS_UniversalTimeToLocal} + Result := UniversalTimeToLocal(Value); + {$ELSE} + {$IFDEF HAS_DateUtils_TTimeZone} + Result := TTimeZone.Local.ToLocalTime(Value); + {$ELSE} + Result := Value + OffsetFromUTC; + {$ENDIF} + {$ENDIF} +end; + function IndyIncludeTrailingPathDelimiter(const S: string): string; {$IFDEF USE_INLINE}inline;{$ENDIF} begin