Чтобы понять смысл високосных лет, вы почти вынуждены разбить это на две части: целое число лет и дробная часть.Оба должны иметь дело с високосными годами, но по-разному - интеграл должен иметь дело с датой начала 29 февраля, а дробный должен иметь дело с различным числом дней в году.Вы хотите, чтобы дробная часть увеличивалась в равных количествах до тех пор, пока она не станет равной 1,0 на следующую годовщину, поэтому она должна основываться на количестве дней в году после даты окончания.
Вы хотите, чтобы ваш диапазон дат включал 1900 или 2100?Все становится немного проще, если вы этого не сделаете.
Редактировать: Мне потребовалось много времени, чтобы объяснить это.Основная проблема заключается в том, что календарные годы не являются постоянными, но вы заставляете их быть постоянными, устанавливая их на 1,0.Любое решение, которое вы придумаете, будет иметь аномалии из-за этого, и вам придется выбирать, с какими аномалиями вы можете жить.Джон Мачин был прав.
В чем разница между 2008-02-28 и 2009-02-28?Большинство людей согласятся, что это должно быть ровно 1,0 года.Как насчет разницы между 2008-03-01 и 2009-03-01?Опять же, большинство людей согласится, что это должно быть ровно 1,0 года.Если вы решите представить дату как год плюс часть года в зависимости от дня, невозможно сделать оба этих утверждения правдивыми.Это относится к вашему исходному коду, который предполагал, что день был 1 / 365.2425 года, или даже к любому коду, который предполагает постоянную долю года в день, даже если размер дня составляет годы, которые являются високоснымилет.
Мое утверждение о том, что вам нужно разбить это на целые годы и дробные годы, было попыткой обойти эту проблему.Если вы рассматриваете каждое из предыдущих условий как целостный год, все, что вам нужно сделать, это решить, какую дробь назначить на любое количество оставшихся дней.Проблема с этой схемой заключается в том, что вы все еще не можете понять (date2-date1) + date3, потому что дробь не может быть разрешена обратно в день с какой-либо согласованностью.
Таким образом, я предлагаю ещедругая кодировка, основанная на каждом году, содержащая 366 дней, независимо от того, високосный или нет.Во-первых, аномалии состоят в том, что не может быть даты, которая ровно год (или 2 или 3) с 29 февраля - «Извините, Джонни, у вас нет дня рождения в этом году, 29 февраля нет».не всегда приемлемоВо-вторых, если вы попытаетесь привести такое число к дате, вам придется учитывать не високосные годы, проверить особый случай 29 февраля и преобразовать его, вероятно, в 1 марта.
from datetime import datetime
from datetime import timedelta
from calendar import isleap
size_of_day = 1. / 366.
size_of_second = size_of_day / (24. * 60. * 60.)
def date_as_float(dt):
days_from_jan1 = dt - datetime(dt.year, 1, 1)
if not isleap(dt.year) and days_from_jan1.days >= 31+28:
days_from_jan1 += timedelta(1)
return dt.year + days_from_jan1.days * size_of_day + days_from_jan1.seconds * size_of_second
start_date = datetime(2010,4,28,12,33)
end_date = datetime(2010,5,5,23,14)
difference_in_years = date_as_float(end_time) - date_as_float(start_time)
Я не предполагаю, что это решение, потому что я не думаю, что идеальное решение возможно.Но у него есть некоторые желательные свойства:
- Разница между любыми датами с одним и тем же месяцем и днем и временем будет точным числом лет.
- Добавление разницы к другой дате приведет кпривести к значению, которое можно преобразовать обратно в полезную дату.