Browse Source

unix: fix timezone info for timers after the last transition

git-svn-id: trunk@49005 -
ondrej 4 years ago
parent
commit
2a61397d37
2 changed files with 79 additions and 3 deletions
  1. 32 1
      rtl/unix/timezone.inc
  2. 47 2
      tests/test/units/unix/ttimezone1.pp

+ 32 - 1
rtl/unix/timezone.inc

@@ -64,8 +64,22 @@ var
     else
       Exit(0);
   end;
+var
+  timerLoUTC, timerHiUTC: int64;
 begin
-  if (num_transitions=0) or (timer<transitions[0]) then
+  if (num_transitions>0) and not timerIsUTC then
+   begin
+     timerLoUTC:=timer-types[type_idxs[0]].offset;
+     timerHiUTC:=timer-types[type_idxs[num_transitions-1]].offset;
+   end
+  else
+   begin
+     timerLoUTC:=timer;
+     timerHiUTC:=timer;
+   end;
+
+  if (num_transitions=0) or (timerLoUTC<transitions[0]) then
+   { timer is before the first transition }
    begin
      i:=0;
      while (i<num_types) and (types[i].isdst) do
@@ -77,6 +91,15 @@ begin
      trans_end:=high(trans_end);
    end
   else
+  if (num_transitions>0) and (timerHiUTC>=transitions[num_transitions-1]) then
+   { timer is after the last transition }
+   begin
+     i:=type_idxs[num_transitions-1];
+     trans_start:=transitions[num_transitions-1];
+     trans_end:=high(trans_end);
+   end
+  else
+   { timer inbetween }
    begin
       // Use binary search.
       L := 1;
@@ -410,6 +433,13 @@ var
 
     readdata:=true;
   end;
+  procedure ClearCurrentTZinfo;
+  var
+    i:integer;
+  begin
+    for i:=low(CurrentTZinfo) to high(CurrentTZinfo) do
+      CurrentTZinfo[i] := Default(TTZInfo);
+  end;
 begin
   if fn='' then
    fn:='localtime';
@@ -422,6 +452,7 @@ begin
   tzhead:=default(ttzhead);
   LockTZInfo;
   ReadTimezoneFile:=(readheader() and readdata());
+  ClearCurrentTZinfo;
   UnlockTZInfo;
   fpclose(f);
 end;

+ 47 - 2
tests/test/units/unix/ttimezone1.pp

@@ -31,9 +31,10 @@ begin
 end;
 
 begin
-  if not ReadTimezoneFile('Europe/Vienna') then // check against Europe/Vienna file
+  // check against Europe/Vienna file
+  if not ReadTimezoneFile('Europe/Vienna') then
   begin
-    writeln('timezone file not found');
+    writeln('Europe/Vienna timezone file not found');
     halt(10);
   end;
 
@@ -52,5 +53,49 @@ begin
   if GetOffset(2019, 10, 27, 0, 59, 0, True)<>2 then Halt(17);
   if GetOffset(2019, 10, 27, 1, 0, 0, True)<>1 then Halt(18);
 
+
+  // check against Europe/Moscow file
+  if not ReadTimezoneFile('Europe/Moscow') then
+  begin
+    writeln('Europe/Moscow timezone file not found');
+    halt(20);
+  end;
+
+  {
+    https://en.wikipedia.org/wiki/Time_in_Russia
+
+    Daylight saving time was re-introduced in the USSR in 1981, beginning on 1 April and ending on 1 October each year,
+    until mid-1984, when the USSR began following European daylight saving time rules, moving clocks forward one hour
+    at 02:00 local standard time on the last Sunday in March, and back one hour at 03:00 local daylight time on the last
+    Sunday in September until 1995, after which the change back occurred on the last Sunday in October.
+
+    On 27 March 2011, clocks were advanced as usual, but they did not go back on 30 October 2011, effectively making
+    Moscow Time UTC+04:00 permanently. On 26 October 2014, following another change in the law, the clocks in most
+    of the country were moved back one hour, but summer Daylight Time was not reintroduced; Moscow Time returned
+    to UTC+03:00 permanently.
+  }
+
+  if GetOffset(1994, 03, 26, 0, 0, 0, True)<>3 then Halt(21);
+  if GetOffset(1994, 03, 27, 0, 0, 0, True)<>4 then Halt(22);
+  if GetOffset(1994, 09, 24, 0, 0, 0, True)<>4 then Halt(23);
+  if GetOffset(1994, 09, 25, 0, 0, 0, True)<>3 then Halt(24);
+
+  if GetOffset(1996, 03, 30, 0, 0, 0, True)<>3 then Halt(25);
+  if GetOffset(1996, 03, 31, 0, 0, 0, True)<>4 then Halt(26);
+  if GetOffset(1996, 10, 26, 0, 0, 0, True)<>4 then Halt(27);
+  if GetOffset(1996, 10, 27, 0, 0, 0, True)<>3 then Halt(28);
+
+  if GetOffset(2011, 03, 26, 0, 0, 0, True)<>3 then Halt(29);
+  if GetOffset(2011, 03, 27, 0, 0, 0, True)<>4 then Halt(30);
+  if GetOffset(2011, 09, 01, 0, 0, 0, True)<>4 then Halt(31);
+  if GetOffset(2011, 11, 01, 0, 0, 0, True)<>4 then Halt(32);
+
+  if GetOffset(2012, 06, 01, 0, 0, 0, True)<>4 then Halt(33);
+
+  if GetOffset(2014, 10, 25, 0, 0, 0, True)<>4 then Halt(34);
+  if GetOffset(2014, 10, 26, 0, 0, 0, True)<>3 then Halt(35);
+
+  if GetOffset(2021, 03, 31, 0, 0, 0, True)<>3 then Halt(36);
+
   writeln('ok');
 end.