爲了閏年感覺,你幾乎被迫分拆成兩個部分這樣的:一個整數年,和小數部分。兩者都需要處理閏年,但以不同的方式 - 處理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