Алгоритм конвертации даты в "абсолютный" день и обратно
Моей целью является вычислить количество дней между 0000.00.00 00:00:00
, и до указанной даты, а потом сделать обратное преобразование.
Месяц и день я указал в "режиме индекса", поэтому они "00
"; что же касается года, то соглашения с ним мне не ведомы.
Тривиально конвертировать между порядковым днём в году, и месяцем/днём, поэтому проблема сводится только к году/порядковому дню.
Посчитать количество дней – пустяковая проблема, и решить это было почти не трудно:
isLeap = (yr % 4==0) and (yr % 100!=0) or (yr % 400==0)
result = (yr*365 + yr//4 - yr//100 + yr//400 + int(yr>0)*(not isLeap)) + dy + 1
Но вот преобразовать всё обратно выбило меня из колеи.
Несколько дней головной боли, отладки с тестами, и всё равно не решается.
Например:
Год с индексом 207 561
и порядковый день с индексом 137
— это 75 810 237
дней.
Это число включает в себя корректировку на високосные года; что одновременно и является проблемой для обратного преобразования.
Моих интеллектуальных способностей хватило только чтобы вычислить индекс года от количества дней, а именно:
num = num - 1
num = num - num//146097
num = num - num//-36525
num = num - num//1461
result = num//365
Как я могу вычислить порядковый день в году, зная количество дней?
Я пытался решить это самостоятельно, и у меня даже получилось... да только вот по неведомым мне причинам после 36 600
года мой способ ломается, и каждые 100 лет год выдаётся на один меньше чем нужно.
Вот моё самое близкое решение:
type
HDivModResult=record
year,day:Int64;
end;
function AbsoluteDaysToYearLinearDivMod(num:Int64):HDivModResult;
var
tmp:Int64;
tgl:Boolean;
begin
Result.year:=0;
Result.day:=0;
if num<1 then
Exit;
num:=num-1;
tmp:=num-(num div 146097);
tmp:=tmp-(tmp div -36525);
tmp:=tmp-(tmp div 1461);
Result.year:=tmp div 365;
tgl:=(Result.year mod 4=0)and(Result.year mod 100<>0)or(Result.year mod 400=0);
tmp:=((num+Byte(tgl))-(Result.year div 4-Result.year div 100+Result.year div 400));
Result.day:=tmp mod 365;
if (tgl)and(Result.day=0) then
begin
tmp:=tmp div 365;
Result.day:=365*Byte(tmp<>Result.year);
end;
end;
Что я понимаю не так?