为了闰年感觉,你几乎被迫分拆成两个部分这样的:一个整数年,和小数部分。两者都需要处理闰年,但以不同的方式 - 处理2月29日开始日期的整体需求,而分数必须处理一年中不同的天数。您希望小数部分以相等的数量递增,直到在下一周年日期等于1.0,所以它应该基于年后的日期数在结束日期之后。
你想让你的日期范围包括1900或2100吗?如果你不这样做,事情会变得容易一些。
编辑:我花了很长时间来解释这一点。基本的问题是日历年不是一个固定的大小,但是通过将它们设置为1.0来强制它们保持不变。任何你想出来的解决方案都会因为这个而产生异常,你将不得不选择你可以忍受的异常。约翰Machin是对的。
2008-02-28和2009-02-28有什么区别?大多数人会同意它应该完全是1.0年。 2008-03-01和2009-03-01之间的区别怎么样?再次,大多数人会同意它应该完全是1.0年。如果您选择将日期表示为一年,再根据当天表示一年的一小部分,则不可能使这两个表述都成立。对于假设每天为1/365.2425的原始代码,或者对于假定每天的一年不变的部分的代码,即使一天中的大小占据了跳跃年年份。
我断言你需要把这个分解成整数年和分数年是为了解决这个问题。如果您将以前的每个条件都视为整数年份,则您只需决定将剩下的天数分配给哪个分数即可。这个方案的问题在于,你仍然无法理解(date2-date1)+ date3,因为这个分数不能以任何一致性解决回到一天。
因此,我正在提议另一种编码,每年的基础上包含366天,不管它是闰年还是非闰年。这个异常首先是因为从2月29日开始,不会有一年(或2或3)的日期 - “对不起,约翰尼,今年没有生日,没有2月29日的生日”,isn总是可以接受的。其次,如果您试图将这样的数字强制退回到某个日期,则必须考虑非闰年,并检查2月29日的特例,并将其转换为3月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)
我并不是说这是解决方案,因为我不认为一个完美的解决方案是可能的。但它有一些令人满意的属性:
- 任何日期与相同的月份,日期和时间之间的差异将是一个确切的年数。
- 将差异添加到其他日期将导致可以转换回有用日期的值。
在何种意义上,你是希望它可以是“更有效”?更快?较少的代码? – 2010-12-14 07:58:28
要明确;使用浮点常量而不是整型常量。您的最后一行需要使用'difference_in_years =(difference.days + difference.seconds/86400.0)/ 365.2425'来给出Python 2.X运行时的预期答案。 – 2010-12-14 08:09:53
@John Machin好点,没有想到这一点。 – c00kiemonster 2010-12-14 08:21:20