Browse Source

GetLocalTimeOffset: DateTime-aware overloads (Windows supported, Unix is a ToDo). Issue #35710

git-svn-id: trunk@47206 -
(cherry picked from commit 0d08b98d47c67169574ff4b2d72d650d67ed5243)
ondrej 4 năm trước cách đây
mục cha
commit
ac08f01ec0

+ 4 - 6
packages/fcl-pdf/src/fppdf.pp

@@ -1285,9 +1285,7 @@ const
 Var
   PDFFormatSettings : TFormatSettings;
 
-//Works correctly ony with Now (problem with DST depended on time)
-//Is used only for CreationDate and it is usualy Now
-function GetLocalTZD(ISO8601: Boolean): string;
+function GetLocalTZD(ADate: TDateTime; ISO8601: Boolean): string;
 var
   i: Integer;
   fmt: string;
@@ -1296,7 +1294,7 @@ begin
     fmt := '%.2d:%.2d'
   else
     fmt := '%.2d''%.2d''';
-  i := GetLocalTimeOffset; //min
+  i := GetLocalTimeOffset(ADate); //min
   if i < 0 then
     Result := '+'
   else if i = 0 then begin
@@ -1310,7 +1308,7 @@ end;
 
 function DateToPdfDate(const ADate: TDateTime): string;
 begin
-  Result:=FormatDateTime('"D:"yyyymmddhhnnss', ADate)+GetLocalTZD(False);
+  Result:=FormatDateTime('"D:"yyyymmddhhnnss', ADate)+GetLocalTZD(ADate, False);
 end;
 
 function FormatPDFInt(const Value: integer; PadLen: integer): string;
@@ -1509,7 +1507,7 @@ procedure TXMPStream.Write(const AStream: TStream);
 
   function DateToISO8601Date(t: TDateTime): string;
   begin
-    Result := FormatDateTime('yyyy-mm-dd"T"hh:nn:ss', t) + GetLocalTZD(True);
+    Result := FormatDateTime('yyyy-mm-dd"T"hh:nn:ss', t) + GetLocalTZD(t, True);
   end;
 
 var

+ 6 - 6
packages/rtl-objpas/src/inc/dateutil.inc

@@ -2281,7 +2281,7 @@ Var
 begin
   T:=aValue;
   if Not aInputisUTC then
-    T:=IncMinute(T,GetLocalTimeOffset);
+    T:=IncMinute(T,GetLocalTimeOffset(AValue));
   Result:=Round(DateTimeDiff(RecodeMillisecond(T,0),UnixEpoch)*SecsPerDay);
 end;
 
@@ -2291,7 +2291,7 @@ Function UnixToDateTime(const AValue: Int64; aReturnUTC : Boolean = true): TDate
 begin
   Result:=IncSecond(UnixEpoch, AValue);
   if Not aReturnUTC then
-    Result:=IncMinute(Result,-GetLocalTimeOffset);
+    Result:=IncMinute(Result,-GetLocalTimeOffset(Result));
 end;
 
 
@@ -2692,7 +2692,7 @@ end;
 function UniversalTimeToLocal(UT: TDateTime): TDateTime;
 
 begin
-  Result:=UniversalTimeToLocal(UT,-GetLocalTimeOffset);
+  Result:=UniversalTimeToLocal(UT,-GetLocalTimeOffset(UT));
 end;
 
 function UniversalTimeToLocal(UT: TDateTime; TZOffset : Integer): TDateTime;
@@ -2709,7 +2709,7 @@ end;
 Function LocalTimeToUniversal(LT: TDateTime): TDateTime;
 
 begin
-  Result:=LocalTimeToUniversal(LT,-GetLocalTimeOffset);
+  Result:=LocalTimeToUniversal(LT,-GetLocalTimeOffset(LT));
 end;
 
 Function LocalTimeToUniversal(LT: TDateTime;TZOffset: Integer): TDateTime;
@@ -2737,7 +2737,7 @@ var
   Offset: Integer;
 begin
   Result := FormatDateTime(FmtUTC, ADate);
-  Offset := GetLocalTimeOffset;
+  Offset := GetLocalTimeOffset(ADate);
   if AInputIsUTC or (Offset=0) then
     Result:=Result+'Z'
   else
@@ -2963,7 +2963,7 @@ begin
   if ReturnUTC then
     Offset:=0
   else
-    OffSet:=-GetLocalTimeOffset;
+    OffSet:=-GetLocalTimeOffset(ADateTime);
   aDateTime:=IncMinute(aDateTime,Offset);
   Result:=True;
 end;

+ 11 - 0
rtl/objpas/sysutils/dati.inc

@@ -1521,4 +1521,15 @@ Function GetLocalTimeOffset : Integer;
 begin
   Result:=0;
 end;
+
+function GetLocalTimeOffset(const DateTime: TDateTime; out Offset: Integer): Boolean;
+begin
+  Result:=False;
+end;
 {$ENDIF}
+
+function GetLocalTimeOffset(const DateTime: TDateTime): Integer;
+begin
+  if not GetLocalTimeOffset(DateTime, Result) then
+    Result:=GetLocalTimeOffset;
+end;

+ 4 - 0
rtl/objpas/sysutils/datih.inc

@@ -198,4 +198,8 @@ Procedure GetLocalTime(var SystemTime: TSystemTime);
 
 procedure ReplaceTime(var dati:TDateTime; NewTime : TDateTime); inline;
 procedure ReplaceDate(var DateTime: TDateTime; const NewDate: TDateTime); inline;
+
 function GetLocalTimeOffset: Integer;
+function GetLocalTimeOffset(const DateTime: TDateTime; out Offset: Integer): Boolean;
+function GetLocalTimeOffset(const DateTime: TDateTime): Integer;
+

+ 6 - 0
rtl/unix/sysutils.pp

@@ -1669,6 +1669,12 @@ begin
  Result := -Tzseconds div 60; 
 end;
 
+function GetLocalTimeOffset(const DateTime: TDateTime; out Offset: Integer): Boolean;
+
+begin
+  Result := False; // ToDo
+end;
+
 {$ifdef android}
 
 procedure InitAndroid;

+ 64 - 0
rtl/win/sysutils.pp

@@ -821,6 +821,70 @@ begin
 end;
 
 
+function GetLocalTimeOffset(const DateTime: TDateTime; out Offset: Integer): Boolean;
+var
+  Year: Integer;
+const
+  DaysPerWeek = 7;
+
+  // MonthOf and YearOf are not available in SysUtils
+  function MonthOf(const AValue: TDateTime): Word;
+  var
+    Y,D : Word;
+  begin
+    DecodeDate(AValue,Y,Result,D);
+  end;
+  function YearOf(const AValue: TDateTime): Word;
+  var
+    D,M : Word;
+  begin
+    DecodeDate(AValue,Result,D,M);
+  end;
+
+  function RelWeekDayToDateTime(const SysTime: TSystemTime): TDateTime;
+  var
+    WeekDay, IncDays: Integer;
+  begin
+    // get first day in month
+    Result := EncodeDate(Year, SysTime.Month, 1);
+    WeekDay := DayOfWeek(Result)-1;
+    // get the correct first weekday in month
+    IncDays := SysTime.wDayOfWeek-WeekDay;
+    if IncDays<0 then
+      Inc(IncDays, DaysPerWeek);
+    // inc weeks
+    Result := Result+IncDays+DaysPerWeek*(SysTime.Day-1);
+    // SysTime.DayOfWeek=5 means the last one - check if we are not in the next month
+    while (MonthOf(Result)>SysTime.Month) do
+      Result := Result-DaysPerWeek;
+    Result := Result+EncodeTime(SysTime.Hour, SysTime.Minute, SysTime.Second, SysTime.Millisecond);
+  end;
+
+var
+  TZInfo: TTimeZoneInformation;
+  DSTStart, DSTEnd: TDateTime;
+
+begin
+  Year := YearOf(DateTime);
+  TZInfo := Default(TTimeZoneInformation);
+  // GetTimeZoneInformationForYear is supported only on Vista and newer
+  if not ((Win32MajorVersion>=6) and GetTimeZoneInformationForYear(Year, nil, TZInfo)) then
+    Exit(False);
+
+  if (TZInfo.StandardDate.Month>0) and (TZInfo.DaylightDate.Month>0) then
+  begin // there is DST
+    DSTStart := RelWeekDayToDateTime(TZInfo.DaylightDate);
+    DSTEnd := RelWeekDayToDateTime(TZInfo.StandardDate);
+    if (DateTime>DSTStart) and (DateTime<DSTEnd) then
+      Offset := TZInfo.Bias+TZInfo.DaylightBias
+    else
+      Offset := TZInfo.Bias+TZInfo.StandardBias;
+  end else // no DST
+    Offset := TZInfo.Bias;
+  Result := True;
+end;
+
+
 function GetTickCount: LongWord;
 begin
   Result := Windows.GetTickCount;

+ 2 - 0
rtl/win/wininc/redef.inc

@@ -624,6 +624,8 @@ function GetThreadPriorityBoost(hThread: THandle; var DisablePriorityBoost: Bool
 function GetThreadSelectorEntry(hThread: THandle; dwSelector: DWORD; var lpSelectorEntry: TLDTEntry): BOOL; external 'kernel32' name 'GetThreadSelectorEntry';
 function GetThreadTimes(hThread: THandle; var lpCreationTime, lpExitTime, lpKernelTime, lpUserTime: TFileTime): BOOL; external 'kernel32' name 'GetThreadTimes';
 function GetTimeZoneInformation(var lpTimeZoneInformation: TTimeZoneInformation): DWORD; external 'kernel32' name 'GetTimeZoneInformation';
+function GetTimeZoneInformationForYear(wYear: USHORT; lpDynamicTimeZoneInformation: PDynamicTimeZoneInformation;
+  var lpTimeZoneInformation: TTimeZoneInformation): BOOL; external 'kernel32' name 'GetTimeZoneInformationForYear';
 //function GetTitleBarInfo(hwnd: HWND; var pti: TTitleBarInfo): BOOL;external 'user32' name 'GetTitleBarInfo';
 function GetTokenInformation(TokenHandle: THandle; TokenInformationClass: TTokenInformationClass; TokenInformation: Pointer; TokenInformationLength: DWORD; var ReturnLength: DWORD): BOOL; external 'advapi32' name 'GetTokenInformation';
 function GetUpdateRect(hWnd: HWND; var lpRect: TRect; bErase: BOOL): BOOL; external 'user32' name 'GetUpdateRect';

+ 16 - 0
rtl/win/wininc/struct.inc

@@ -7511,6 +7511,22 @@ Const
      TTIMEZONEINFORMATION = TIME_ZONE_INFORMATION;
      PTIMEZONEINFORMATION = ^TIME_ZONE_INFORMATION;
 
+     TIME_DYNAMIC_ZONE_INFORMATION = record
+       Bias: Longint;
+       StandardName: array[0..31] of WCHAR;
+       StandardDate: TSystemTime;
+       StandardBias: Longint;
+       DaylightName: array[0..31] of WCHAR;
+       DaylightDate: TSystemTime;
+       DaylightBias: Longint;
+       TimeZoneKeyName: array[0..127] of WCHAR;
+       DynamicDaylightTimeDisabled: ByteBool;
+     end;
+     LPTIME_DYNAMIC_ZONE_INFORMATION = ^TIME_DYNAMIC_ZONE_INFORMATION;
+     _TIME_DYNAMIC_ZONE_INFORMATION = TIME_DYNAMIC_ZONE_INFORMATION;
+     TDYNAMICTIMEZONEINFORMATION = TIME_DYNAMIC_ZONE_INFORMATION;
+     PDYNAMICTIMEZONEINFORMATION = ^TDYNAMICTIMEZONEINFORMATION;
+
      TOGGLEKEYS = record
           cbSize : DWORD;
           dwFlags : DWORD;

+ 6 - 0
rtl/wince/sysutils.pp

@@ -449,6 +449,12 @@ begin
    end;
 end;
 
+function GetLocalTimeOffset(const DateTime: TDateTime; out Offset: Integer): Boolean;
+
+begin
+  Result := False; // not supported
+end;
+
 {****************************************************************************
                               Misc Functions
 ****************************************************************************}