浏览代码

Amiga: Implementation of Amiga2Date and Date2Amiga for older Amiga Versions

git-svn-id: trunk@44704 -
marcus 5 年之前
父节点
当前提交
acf58acf41
共有 1 个文件被更改,包括 123 次插入4 次删除
  1. 123 4
      rtl/amiga/m68k/legacyutil.inc

+ 123 - 4
rtl/amiga/m68k/legacyutil.inc

@@ -22,14 +22,133 @@
   functional enough for the RTL code.
   functional enough for the RTL code.
 }
 }
 
 
+const
+  // Start day of every month (without leap)
+  StartOfMonth: array[0..11] of LongInt = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
+  SecsPerMin = 60;
+  SecsPerHour = 60 * SecsPerMin;
+  SecsPerDay = 24 * SecsPerHour;
+  SecsPerYear = 365 * SecsPerDay;// without leap
+  AmigaStartYear = 1978; // Amiga starts @1978;
+  DaysPerYear = 365;
+  DaysPerLeapYear = DaysPerYear + 1;
+  Daysof4Years = DaysPerLeapYear + 3 * DaysPerYear;
+  Daysof100Years = 24 * DaysPerLeapYear + 76 * DaysPerYear;
+  Daysof400Years = 97 * DaysPerLeapYear + 303 * DaysPerYear;
+
+
 procedure Amiga2Date(seconds: Cardinal;
 procedure Amiga2Date(seconds: Cardinal;
                      result : PClockData); public name '_fpc_amiga_amiga2date';
                      result : PClockData); public name '_fpc_amiga_amiga2date';
-begin
-{$warning Amiga2Date unimplemented!}
+var
+  IsLeap: boolean;
+  d, y, i: LongWord;
+begin// how many days are passed
+  d := seconds div SecsPerDay;
+
+  // the easier time part
+  Result^.wday := d mod 7;
+  Result^.sec := seconds mod 60;
+  seconds := seconds div 60;
+  Result^.min := seconds mod 60;
+  seconds := seconds div 60;
+  Result^.hour := seconds mod 24;
+
+  // the leap year correction part
+  IsLeap := True;
+  //
+  // before 2100 easier case (function mostly used for now(), so its usually in this range)
+  if d < 92 * DaysPerYear + 30 * DaysPerLeapYear then  // 1978 - 2100 = 92 non leap, 30 leap years
+  begin
+    d := d + DaysPerLeapYear + DaysPerYear; // we want to start from 1976 (a leap year) so we add 2 more years to the nubmer we have
+    y := 4 *(d div Daysof4Years) + 1976; // how many 4 year spans (1 leap + 3 non leap) are there?
+    d := d mod Daysof4Years; //( get the day in the 4 year span)
+    // the first yoear of such a 4 year span, is always a leap year, all other not (thats the reason we want to start at 1976)
+    if d > DaysPerLeapYear then
+    begin
+      IsLeap := False;
+      d := d - 1;
+      y := y + d div DaysPerYear;
+      d := d mod DaysPerYear;
+    end;
+  end
+  else
+  begin
+    // more complicated way for dates > 2100 (not tested until now!)
+    // we do the same as before but not 4 years together but 400 (because of the special years which are not leap even divided by 4)
+    // and we start at 2000
+    d := d - 17 * DaysPerYear + 5 * DaysPerLeapYear;
+    y := 400 * (d div Daysof400Years) + 2000;
+    d := d mod Daysof400Years;
+    // first is always NOT leap year.. other we have to test
+    if d >= DaysPerLeapYear then
+    begin
+      // we do the same again, and test for 100 year spans
+      d := d - 1; // not a leap year one day down
+      IsLeap := False;
+      y := y + 100 * (d div Daysof100Years);
+      d := d mod Daysof100Years;
+      if d >= DaysPerYear then
+      begin
+        d := d + 1; // a leap year, one day up
+        IsLeap := True;
+        // and the same as we did before 4 years span
+        y := y + 4 * (d div Daysof4Years);
+        d := d mod Daysof4Years;
+        if d >= DaysPerLeapYear then
+        begin
+          d := d - 1;
+          IsLeap := False;
+          y := y + d div DaysPerYear;
+          d := d mod DaysPerYear;
+        end;
+      end;
+    end;
+  end;
+  // the current year is a leap year and we are after Februar
+  if IsLeap and (d >= StartOfMonth[2]) then
+    d := d + 1;
+  // get the actual month
+  for i := 1 to High(StartOfMonth) do
+  begin
+    if StartOfMonth[i] > d then
+    begin
+      Result^.Month := i;
+      d := d - (StartOfMonth[i - 1] + 1);
+      break;
+    end;
+  end;
+  Result^.year := y;
+  Result^.mday := d;
 end;
 end;
 
 
 function Date2Amiga(date: PClockData): Cardinal; public name '_fpc_amiga_date2amiga';
 function Date2Amiga(date: PClockData): Cardinal; public name '_fpc_amiga_date2amiga';
+var
+  Y: LongInt;
+  Leaps, LeapsBefore1978, Res: LongWord;
 begin
 begin
-{$warning Date2Amiga unimplemented!}
-  Date2Amiga:=0;
+  // the easy time part
+  Res := date^.hour * SecsPerHour + date^.min * SecsPerMin + date^.sec;
+  Res := Res + ((date^.mday - 1) + StartOfMonth[date^.month - 1]) * SecsPerDay;
+  Res := Res + (date^.year - AmigaStartYear) * SecsPerYear;
+
+  // leap year correction ;)
+
+  // current year
+  y := date^.year;
+  // from IsLeapYear dos.pp
+  if (y mod 400 = 0) or ((y mod 4 = 0) and (y mod 100 <> 0)) then
+  begin
+    // add a day if its after feb in a leap year
+    if date^.month > 2 then
+      Res := Res + SecsPerDay;
+  end;
+
+  // previous years
+  y := date^.year - 1;
+  Leaps := (y div 4) - (y div 100) + (y div 400);
+  // exclude the ones before 1978
+  LeapsBefore1978 := (AmigaStartYear div 4) - (AmigaStartYear div 100) + (AmigaStartYear div 400);
+
+  Date2Amiga := Res + (leaps - leapsBefore1978) * SecsPerDay;
 end;
 end;
+