Browse Source

* corrected *Between() functions: add epsilon and truncate, rather than
round the results (bug reported on irc)

git-svn-id: trunk@13107 -

Jonas Maebe 16 years ago
parent
commit
8193cd175d
2 changed files with 30 additions and 11 deletions
  1. 11 8
      rtl/objpas/dateutil.inc
  2. 19 3
      tests/webtbs/tw12894.pp

+ 11 - 8
rtl/objpas/dateutil.inc

@@ -423,6 +423,9 @@ implementation
 
 uses sysconst;
 
+const
+  TDateTimeEpsilon = 2.2204460493e-16;
+
 { ---------------------------------------------------------------------
     Auxiliary routines
   ---------------------------------------------------------------------}
@@ -1305,49 +1308,49 @@ end;
 
 Function YearsBetween(const ANow, AThen: TDateTime): Integer;
 begin
-  Result:=Round(Abs(DateTimeDiff(ANow,AThen))/ApproxDaysPerYear);
+  Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)/ApproxDaysPerYear);
 end;
 
 
 Function MonthsBetween(const ANow, AThen: TDateTime): Integer;
 begin
-  Result:=Round(Abs(DateTimeDiff(ANow,AThen))/ApproxDaysPerMonth);
+  Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)/ApproxDaysPerMonth);
 end;
 
 
 Function WeeksBetween(const ANow, AThen: TDateTime): Integer;
 begin
-  Result:=Round(Abs(DateTimeDiff(ANow,AThen))) div 7;
+  Result:=Trunc(Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon) div 7;
 end;
 
 
 Function DaysBetween(const ANow, AThen: TDateTime): Integer;
 begin
-  Result:=Round(Abs(DateTimeDiff(ANow,AThen)));
+  Result:=Trunc(Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon);
 end;
 
 
 Function HoursBetween(const ANow, AThen: TDateTime): Int64;
 begin
-  Result:=Round(Abs(DateTimeDiff(ANow,AThen))*HoursPerDay);
+  Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*HoursPerDay);
 end;
 
 
 Function MinutesBetween(const ANow, AThen: TDateTime): Int64;
 begin
-  Result:=Round(Abs(DateTimeDiff(ANow,AThen))*MinsPerDay);
+  Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*MinsPerDay);
 end;
 
 
 Function SecondsBetween(const ANow, AThen: TDateTime): Int64;
 begin
-  Result:=Round(Abs(DateTimeDiff(ANow,AThen))*SecsPerDay);
+  Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*SecsPerDay);
 end;
 
 
 Function MilliSecondsBetween(const ANow, AThen: TDateTime): Int64;
 begin
-  Result:=Round(Abs(DateTimeDiff(ANow,AThen))*MSecsPerDay);
+  Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*MSecsPerDay);
 end;
 
 

+ 19 - 3
tests/webtbs/tw12894.pp

@@ -65,14 +65,26 @@ begin
    halt(4);
  currentDt := EncodeDateTime(1898, 12, 30, 6, 0, 0, 0);
  convertedDt := EncodeDateTime(1899, 12, 30, 6, 0, 0, 0);
- if (YearsBetween(currentDt,convertedDt)<>1) or
-    (MonthsBetween(currentDt,convertedDt)<>12) or
+ { 0 and 11 rather than 1 and 12, because YearsBetween and MonthsBetween
+   are averaged over 4 years -> include a leap year }
+ if (YearsBetween(currentDt,convertedDt)<>0) or
+    (MonthsBetween(currentDt,convertedDt)<>11) or
     (DaysBetween(currentDt,convertedDt)<>365) or
     (HoursBetween(currentDt,convertedDt)<>365*24) or
     (MinutesBetween(currentDt,convertedDt)<>365*24*60) or
     (SecondsBetween(currentDt,convertedDt)<>365*24*60*60) or
     (MilliSecondsBetween(currentDt,convertedDt)<>365*24*60*60*1000) then
-   halt(5);
+   begin
+     writeln('between ',s1,' and ',s2);
+     writeln(YearsBetween(currentDt,convertedDt));
+     writeln(MonthsBetween(currentDt,convertedDt));
+     writeln(DaysBetween(currentDt,convertedDt));
+     writeln(HoursBetween(currentDt,convertedDt));
+     writeln(MinutesBetween(currentDt,convertedDt));
+     writeln(SecondsBetween(currentDt,convertedDt));
+     writeln(MilliSecondsBetween(currentDt,convertedDt));
+     halt(5);
+   end;
  currentDt := EncodeDateTime(1898, 12, 29, 6, 0, 0, 0);
  convertedDt := EncodeDateTime(1899, 12, 30, 6, 0, 0, 0);
  if (YearsBetween(currentDt,convertedDt)<>1) or
@@ -83,6 +95,10 @@ begin
     (SecondsBetween(currentDt,convertedDt)<>366*24*60*60) or
     (MilliSecondsBetween(currentDt,convertedDt)<>366*24*60*60*1000) then
    halt(6);
+  currentDt := 39939.796069305557;
+  convertedDt := 39939.0;
+  if YearsBetween(currentDt,convertedDt)<>0 then
+    halt(7);
 // convertedDt:=incseconds(currentDt,
 
 end.