Python timedelta probleem met negatieve waarden

Hallo ik heb hulp nodig om te begrijpen waarom dit gebeurt. Ik heb een methode om 'resterende tijd' in een evenementprogramma bij te houden:

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

All fine when the estimated_duration > self.get_program_duration() but when this goes the other way things get funny.

Resultaten worden getoond aan de gebruiker:

Estimated   11 hours    Allocated       10 hours 55 minutes     Remaining       5 minutes

Wanneer het resultaat negatief wordt doet het dit:

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

Om het even welke ideeën hoe te om het resultaat te krijgen -5 minuten?

BEWERK: Hier is de timedelta formatter (merk op dat dit een Django filter is, dus ontvangt de timedelta waarde als een str - maar het wordt opgeslagen als een 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 
21
Dit is de manier waarop timedelta werkt voor negatieve waarden. Resultaten zijn altijd genormaliseerd, zodat alleen de waarde dagen negatief is. Wilt u de andere velden negeren als de dagwaarde bijvoorbeeld 5 was?
toegevoegd de auteur Ray Toal, de bron
We weten hoe we twee timedeltas kunnen aftrekken. Wat we niet weten, is welke code u gebruikte om het resultaat weer te geven. Voor beter advies, graag onthullen.
toegevoegd de auteur John Machin, de bron
Als u op een normale manier met negatieve timedelta-waarden wilt werken ("-1 minuut" is slechts "-1 minuut" en niet "-1 dag plus 23u59"), kunt u de relativetimedelta module aanwezig in dateutil .
toegevoegd de auteur florisla, de bron

2 antwoord

Als u Python 2.7 of hoger gebruikt, kunt u timedelta.total_seconds gebruiken() om een ​​ float -representatie van de timedelta te krijgen als een positief of negatief aantal seconden.

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

U zou dit moeten kunnen gebruiken om vrij gemakkelijk een aantal minuten te berekenen.

Als u Python 2.7 niet gebruikt, kunt u de volgende equivalente formule uit de documenten gebruiken:

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

Edit: It looks like you are probably using the default string representation for timedelta to display the result, so my original answer may not be as useful. I would suggest something like this for displaying the result:

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)

Dit zou nu een string teruggeven in plaats van een timedelta, en voor negatieve timedeltas zou het een '-' vervangen door een positieve timedelta.

37
toegevoegd
In dat geval zou je je formatter moeten veranderen in een positieve timedelta en gewoon op een '-' naar de voorkant ervan.
toegevoegd de auteur Andrew Clark, de bron
Bedankt. Geweldig antwoord, maar ik gebruik niet de standaard str-indeling. Ik heb mijn eigen formatter (om seconden te ontrafelen, enzovoort), dus heb ik een timedelta nodig, geen str. Zal de formule uit de documenten proberen om total_seconds te doen.
toegevoegd de auteur Drew Nichols, de bron
Helaas is de formatteercode een Django-filter, dus neemt de timedelta .__ str__ (of unicode ) de waarde - zie vraag voor code.
toegevoegd de auteur Drew Nichols, de bron

Waarom?

Mogelijk is er een onbedoeld neveneffect van de manier waarop // en % zijn gedefinieerd.

Mogelijk omdat het het gemakkelijker maakt om de klasse datetime te implementeren. Vijf minuten voor het tijdperk is 23:55 uur, niet 0: -5.

Het maakt niet echt uit. Weet gewoon dat dit de manier is waarop dagen , seconden en microseconden genormaliseerd worden. En dat het gemakkelijk kan worden verwerkt.

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'
11
toegevoegd
Dit is zo eenvoudig en toch geniaal. Dank je!
toegevoegd de auteur Marcel Wilson, de bron