web-dev-qa-db-fra.com

Python timedelta avec des valeurs négatives

Salut, j'ai besoin d'aide pour comprendre pourquoi cela se produit. J'ai une méthode pour suivre le "temps restant" dans un programme d'événement:

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

Tout va bien lorsque la estimation_duration> self.get_program_duration () mais quand cela va dans l'autre sens, les choses deviennent drôles.

Les résultats sont affichés à l'utilisateur:

Estimated   11 hours    Allocated       10 hours 55 minutes     Remaining       5 minutes

Lorsque le résultat devient négatif, il le fait:

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

Des idées pour obtenir le résultat -5 minutes?

EDIT: Voici le formateur timedelta (Notez qu'il s'agit d'un filtre Django, donc reçoit la valeur timedelta sous forme de str - mais elle est stockée sous forme de 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 
32
Drew Nichols

Si vous utilisez Python 2.7 ou supérieur, vous pouvez utiliser timedelta.total_seconds() pour obtenir une représentation float de la timedelta positive) ou nombre négatif de secondes.

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

Vous devriez pouvoir l'utiliser assez facilement pour calculer un nombre de minutes.

Si vous n'utilisez pas Python 2.7, vous pouvez utiliser la formule équivalente suivante à partir des documents:

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

Edit: Il semble que vous utilisiez probablement la représentation de chaîne par défaut pour timedelta pour afficher le résultat, donc ma réponse originale peut ne pas être aussi utile. Je suggérerais quelque chose comme ceci pour afficher le résultat:

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)

Cela retournerait maintenant une chaîne au lieu d'un timedelta, et pour les timedeltas négatifs, il ajouterait un "-" à un timedelta positif.

42
Andrew Clark

Pourquoi?

Peut-être comme un effet secondaire involontaire de la voie // et % sont définis.

Peut-être parce que cela facilite l'implémentation de la classe datetime. Cinq minutes avant l'Époque, il est 23h55, pas 0: -5.

Ça n'a pas vraiment d'importance. Sachez simplement que c'est ainsi que days, seconds et microseconds sont normalisés. Et qu'il peut facilement être contourné.

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'
14
dan04