2011-12-06 172 views
19

嗨,我需要一些幫助,以瞭解爲什麼發生這種情況。 我有一個事件程序來跟蹤「剩餘時間」的方法:Python的timedelta問題與負值

def get_program_time_budget(self): 
    return self.estimated_duration-self.get_program_duration() 

一切都很好,當ESTIMATED_DURATION> self.get_program_duration(),但是當這個走另一條路事情變得有趣。

結果顯示給用戶:

Estimated 11 hours Allocated  10 hours 55 minutes  Remaining  5 minutes 

當結果爲負時它不這樣:

Estimated 11 hours Allocated  11 hours 5 minutes Remaining  -1 day 23 hours 55 minutes 

任何想法如何得到的結果-5分鐘?

編輯: 這裏是timedelta格式(注意,這是一個Django的過濾器,所以接收timedelta值作爲海峽 - 但它被存儲爲一個timedelta):

def format_duration(value): 
    try: 
    delim = ':' 
    toks = value.split(',') 
    hour = minute = '' 
    d_string = value.count('day') and toks[0] or '' 
    h, m, s = d_string and toks[-1].strip().split(delim) or value.split(delim) 
    try: 
     hour = int(h) 
    except: 
     pass 
    try: 
     minute = int(m) 
    except: 
     pass 
    h_string = "%s%s%s" % (hour and hour or '', (hour and ' hour' or ''),(hour and hour > 1 and 's' or '') ) 
    m_string = "%s%s%s" % (minute and minute or '', (minute and ' minute' or ''),(minute and minute > 1 and 's' or '')) 
    return "%s %s %s" % (d_string, h_string, m_string) 
    except Exception, e: 
    logging.error("Error in format_duration -> %s. Duration value=%s" % (e, value)) 
    return ''v 
+1

這是'timedelta'對負值的工作方式。結果總是標準化的,因此只有「天」值是負值。如果天數的值是-5,你想否定其他領域? –

+3

我們知道如何減去兩個timedeltas。我們不知道的是您用來顯示結果的代碼。爲了獲得更好的建議,請透露。 –

+1

如果你想以一種理智的方式處理負的timedelta值(「-1分鐘」只是「-1分鐘」,而不是**「-1天加23h59」),你可以使用'relativetimedelta'模塊存在於[dateutil](http://labix.org/python-dateutil)中。 – florisla

回答

35

如果您正在使用Python 2.7或更高版本,您可以使用timedelta.total_seconds()獲取timedelta的float表示形式爲正數或負數秒。

>>> datetime.timedelta(-1, 86100).total_seconds() 
-300.0 

您應該可以很容易地使用它來計算分鐘數。

如果你不使用Python 2.7,你可以用下面的等價公式從文檔:

(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6)/10.0**6 

編輯:看起來你很可能使用的是默認字符串表示timedelta顯示結果,所以我原來的答案可能沒有那麼有用。我建議是這樣的顯示結果:

def get_program_time_budget(self): 
    td = self.estimated_duration-self.get_program_duration() 
    if td.days < 0: 
     return '-' + str(datetime.timedelta() - td) 
    return str(td) 

現在,這將返回一個字符串,而不是一個timedelta,併爲負timedeltas它會在前面加上「 - 」爲正timedelta。

+0

謝謝。很好的答案,但我不使用默認的str格式。我有我自己的格式化程序(去除秒等),所以需要一個timedelta,而不是一個str。將嘗試從文檔的公式做total_seconds。 –

+0

在這種情況下,您應該更改格式化程序以將其轉換爲正值timedelta,並將其轉換爲前面的' - '。 –

+0

不幸的是,格式化程序代碼是一個Django過濾器,因此需要timedelta .__ str__(或__unicode__)作爲值 - 請參閱代碼問題。 –

11

爲什麼?

可能作爲//%定義的方式的意外副作用。

可能是因爲它更容易實現datetime類。在紀元前5分鐘是23:55,而不是0:-5。

這並不重要。只要知道days,secondsmicroseconds是如何被標準化的。而且它可以很容易地解決。

def format_timedelta(td): 
    if td < timedelta(0): 
     return '-' + format_timedelta(-td) 
    else: 
     # Change this to format positive timedeltas the way you want 
     return str(td) 

>>> format_timedelta(timedelta(minutes=-5)) 
'-0:05:00' 
+2

這太簡單了,但天才。謝謝! –