Некоторое время назад на стене рядом с моим столом висело и вдохновляло меня на новые трудовые свершения нетленное творение неизвестного автора. Этот поистине неиссякаемый источник вечной мудрости при каждой встрече с ним позволял мне испить свежей мысли, приоткрывал новые законы чисел и давал возможность прикоснуться к тайнам мироздания. Но вряд ли кто-либо из смертных способен в полной мере постичь великую мудрость, которой наполнен сей источник.
function IncDay(const DateTime: TDateTime; NumberOfDays: Integer): TDateTime;
//Функция предназначена для изменения даты (DateTime) путем добавления количества дней (NumberOfDays).
//Значение NumberOfDays может быть отрицательным.
var
Y, M, D, CountDays: Word;
N: Integer;
Sign, NoBreak: Boolean;
begin
Sign := NumberOfDays >= 0;
DecodeDate(DateTime, Y, M, D);
N := NumberOfDays;
NoBreak := True;
if Sign then //Прибавить
begin
while(NoBreak) do
begin //Количество дней в месяце
CountDays := MonthDays[IsLeapYear(Y), M];
if (N + D) <= CountDays then //Если в пределах данного месяца
begin
Inc(D, N);
NoBreak := False;
end
else
begin
if M < 12 then
Inc(M, 1)
else
begin
M := 1;
Inc(Y, 1);
end;
N := N - (CountDays - D);
D := 0;
end;
end;
end
else //Отнять
begin
N := -N;
while(NoBreak) do
begin
if D > N then //Если в пределах данного месяца
begin
Dec(D, N);
NoBreak := False;
end
else
begin
if M > 1 then
Dec(M, 1)
else
begin
M := 12;
Dec(Y, 1);
end;
//Количество дней в месяце
CountDays := MonthDays[IsLeapYear(Y), M];
N := N - D;
D := CountDays;
end;
end;
end;
Result := EncodeDate(Y, M, D);
//Установить время из старой даты
ReplaceTime(Result, DateTime);
end;И вот недавно, в очередной раз находясь под впечатлением от Источника, я скользил погрустневшим взором по строкам продукта, созданного в далеких землях. Но что это – я не поверил своим глазам – не может быть, чтобы слава неизвестного автора докатилась так далеко. Да, это было правдой, знакомые струи угадывались коде заморской функции. Как ни старался, я не смог устоять перед желанием хоть на миг приобщиться к великому:
function ShaNow: TDateTime; const MsPerDay = 1440 * 60 * 1000; //Day in milliseconds DateTimeBase = 693594; //Days between 01/01/0001 and 12/31/1899 FileTimeBase = 584389; //Days between 01/01/0001 and 01/01/1601 DeltaInDays = DateTimeBase - FileTimeBase; //Days between 01/01/1601 and 12/31/1899 const DeltaInMs = int64(DeltaInDays) * MsPerDay; //Milliseconds between 01/01/1601 and 12/31/1899 DeltaInMsLo = DeltaInMs and $FFFFFFFF; DeltaInMsHi = DeltaInMs shr 32; const OneMs: extended = 1 / MsPerDay; //Millisecond in days const //Magic constant to replace 64-bit integer division by 625 with multiplication Magic625Inverted = $346DC5D63886594B; Magic625InvertedLo = Magic625Inverted and $FFFFFFFF; Magic625InvertedHi = Magic625Inverted shr 32; asm add esp, -20 mov [esp+16], ebx lea ebx, [esp+8] push ebx call GetSystemTimeAsFileTime push esp push ebx call FileTimeToLocalFileTime //Convert TFileTime to milliseconds: divide pint64(esp)^ by 10000, result in edx:eax mov eax, Magic625InvertedLo xor ebx, ebx mul [esp] mov eax, Magic625InvertedLo mov ecx, edx mul [esp+4] add ecx, eax mov eax, Magic625InvertedHi adc ebx, edx mul [esp] add ecx, eax mov eax, Magic625InvertedHi adc ebx, edx mov ecx, 0 adc ecx, ecx mul [esp+4] add eax, ebx adc edx, ecx shrd eax, edx, 11 shr edx, 11 sub eax, DeltaInMsLo sbb edx, DeltaInMsHi mov [esp], eax mov [esp+4], edx fild qword ptr [esp] mov ebx, [esp+16] fld OneMs add esp, 20 fmulp end;
Конечно, мне не удалось добиться даже малой части той лаконичности и самодостаточности кода, которая свойственна творениям великих мастеров. Но я буду пытаться. Вот только дом покрашу в цвет черешни и продолжу.
P.S. Времена выполнения функций Now() и ShaNow() отличаются в 10 раз на E6850.