437 Stimmen

Zeitdelta in String formatieren

Ich habe Probleme bei der Formatierung einer datetime.timedelta Objekt.

Hier ist, was ich t Ich habe eine Liste von Objekten und eines der Mitglieder der Klasse des Objekts ist ein Timedelta-Objekt, das die Dauer eines Ereignisses anzeigt. Ich möchte diese Dauer im Format Stunden:Minuten anzeigen.

Ich habe verschiedene Methoden ausprobiert, um dies zu erreichen, aber ich habe Schwierigkeiten. Mein derzeitiger Ansatz besteht darin, der Klasse für meine Objekte Methoden hinzuzufügen, die Stunden und Minuten zurückgeben. Die Stunden erhalte ich, indem ich die timedelta.seconds durch 3600 teile und das Ergebnis runde. Ich habe Schwierigkeiten, die restlichen Sekunden zu ermitteln und in Minuten umzurechnen.

Übrigens, ich verwende Google AppEngine mit Django Templates für die Präsentation.

4voto

Veselin Penev Punkte 79
def seconds_to_time_left_string(total_seconds):
    s = int(total_seconds)
    years = s // 31104000
    if years > 1:
        return '%d years' % years
    s = s - (years * 31104000)
    months = s // 2592000
    if years == 1:
        r = 'one year'
        if months > 0:
            r += ' and %d months' % months
        return r
    if months > 1:
        return '%d months' % months
    s = s - (months * 2592000)
    days = s // 86400
    if months == 1:
        r = 'one month'
        if days > 0:
            r += ' and %d days' % days
        return r
    if days > 1:
        return '%d days' % days
    s = s - (days * 86400)
    hours = s // 3600
    if days == 1:
        r = 'one day'
        if hours > 0:
            r += ' and %d hours' % hours
        return r 
    s = s - (hours * 3600)
    minutes = s // 60
    seconds = s - (minutes * 60)
    if hours >= 6:
        return '%d hours' % hours
    if hours >= 1:
        r = '%d hours' % hours
        if hours == 1:
            r = 'one hour'
        if minutes > 0:
            r += ' and %d minutes' % minutes
        return r
    if minutes == 1:
        r = 'one minute'
        if seconds > 0:
            r += ' and %d seconds' % seconds
        return r
    if minutes == 0:
        return '%d seconds' % seconds
    if seconds == 0:
        return '%d minutes' % minutes
    return '%d minutes and %d seconds' % (minutes, seconds)

for i in range(10):
    print pow(8, i), seconds_to_time_left_string(pow(8, i))

Output:
1 1 seconds
8 8 seconds
64 one minute and 4 seconds
512 8 minutes and 32 seconds
4096 one hour and 8 minutes
32768 9 hours
262144 3 days
2097152 24 days
16777216 6 months
134217728 4 years

4voto

tomatoeshift Punkte 385

Ich fuhr fort mit MarredCheese's Antwort und fügte hinzu year , month , millicesond y microsecond

alle Zahlen werden als Ganzzahl formatiert, außer für second und damit den Bruchteil einer Sekunde kann angepasst werden .

@kfmfe04 fragte nach Sekundenbruchteilen, also habe ich diese Lösung gepostet

In der main gibt es einige Beispiele.

from string import Formatter
from datetime import timedelta

def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02.0f}s', inputtype='timedelta'):
    """Convert a datetime.timedelta object or a regular number to a custom-
    formatted string, just like the stftime() method does for datetime.datetime
    objects.

    The fmt argument allows custom formatting to be specified.  Fields can 
    include seconds, minutes, hours, days, and weeks.  Each field is optional.

    Some examples:
        '{D:02}d {H:02}h {M:02}m {S:02.0f}s' --> '05d 08h 04m 02s' (default)
        '{W}w {D}d {H}:{M:02}:{S:02.0f}'     --> '4w 5d 8:04:02'
        '{D:2}d {H:2}:{M:02}:{S:02.0f}'      --> ' 5d  8:04:02'
        '{H}h {S:.0f}s'                       --> '72h 800s'

    The inputtype argument allows tdelta to be a regular number instead of the  
    default, which is a datetime.timedelta object.  Valid inputtype strings: 
        's', 'seconds', 
        'm', 'minutes', 
        'h', 'hours', 
        'd', 'days', 
        'w', 'weeks'
    """

    # Convert tdelta to integer seconds.
    if inputtype == 'timedelta':
        remainder = tdelta.total_seconds()
    elif inputtype in ['s', 'seconds']:
        remainder = float(tdelta)
    elif inputtype in ['m', 'minutes']:
        remainder = float(tdelta)*60
    elif inputtype in ['h', 'hours']:
        remainder = float(tdelta)*3600
    elif inputtype in ['d', 'days']:
        remainder = float(tdelta)*86400
    elif inputtype in ['w', 'weeks']:
        remainder = float(tdelta)*604800

    f = Formatter()
    desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)]
    possible_fields = ('Y','m','W', 'D', 'H', 'M', 'S', 'mS', 'µS')
    constants = {'Y':86400*365.24,'m': 86400*30.44 ,'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1, 'mS': 1/pow(10,3) , 'µS':1/pow(10,6)}
    values = {}
    for field in possible_fields:
        if field in desired_fields and field in constants:
            Quotient, remainder = divmod(remainder, constants[field])
            values[field] = int(Quotient) if field != 'S' else Quotient + remainder
    return f.format(fmt, **values)

if __name__ == "__main__":
    td = timedelta(days=717, hours=3, minutes=5, seconds=8, microseconds=3549)
    print(strfdelta(td,'{Y} years {m} months {W} weeks {D} days {H:02}:{M:02}:{S:02}'))  
    print(strfdelta(td,'{m} months {W} weeks {D} days {H:02}:{M:02}:{S:02.4f}'))  
    td = timedelta( seconds=8, microseconds=8549)
    print(strfdelta(td,'{S} seconds {mS} milliseconds {µS} microseconds'))  
    print(strfdelta(td,'{S:.0f} seconds {mS} milliseconds {µS} microseconds'))  
    print(strfdelta(pow(10,7),inputtype='s'))

Ausgabe:

1 years 11 months 2 weeks 3 days 01:09:56.00354900211096
23 months 2 weeks 3 days 00:12:20.0035
8.008549 seconds 8 milliseconds 549 microseconds
8 seconds 8 milliseconds 549 microseconds
115d 17h 46m 40s

3voto

Pierre D Punkte 18350

Wenn Sie zufällig eine IPython in Ihren Paketen (das sollten Sie), hat es (bis jetzt jedenfalls) einen sehr schönen Formatierer für Dauern (in Float-Sekunden). Das wird an verschiedenen Stellen verwendet, zum Beispiel von der %%time Zellmagie. Ich mag das Format, das es für kurze Zeiträume erzeugt:

>>> from IPython.core.magics.execution import _format_time
>>> 
>>> for v in range(-9, 10, 2):
...     dt = 1.25 * 10**v
...     print(_format_time(dt))

1.25 ns
125 ns
12.5 µs
1.25 ms
125 ms
12.5 s
20min 50s
1d 10h 43min 20s
144d 16h 13min 20s
14467d 14h 13min 20s

2voto

Hier ist eine Funktion zur Stringifizierung von timedelta.total_seconds(). Sie funktioniert in Python 2 und 3.

def strf_interval(seconds):
    days, remainder = divmod(seconds, 86400)
    hours, remainder = divmod(remainder, 3600)
    minutes, seconds = divmod(remainder, 60)
    return '{} {} {} {}'.format(
            "" if int(days) == 0 else str(int(days)) + ' days',
            "" if int(hours) == 0 else str(int(hours)) + ' hours',
            "" if int(minutes) == 0 else str(int(minutes))  + ' mins',
            "" if int(seconds) == 0 else str(int(seconds))  + ' secs'
        )

Beispielhafte Ausgabe:

>>> print(strf_interval(1))
   1 secs
>>> print(strf_interval(100))
  1 mins 40 secs
>>> print(strf_interval(1000))
  16 mins 40 secs
>>> print(strf_interval(10000))
 2 hours 46 mins 40 secs
>>> print(strf_interval(100000))
1 days 3 hours 46 mins 40 secs

2voto

raidsan Punkte 761

Timedelta in einen String umgewandelt, der zum Drucken von Laufzeitinformationen verwendet wird.

def strfdelta_round(tdelta, round_period='second'):
  """timedelta to string,  use for measure running time
  attend period from days downto smaller period, round to minimum period
  omit zero value period  
  """
  period_names = ('day', 'hour', 'minute', 'second', 'millisecond')
  if round_period not in period_names:
    raise Exception(f'round_period "{round_period}" invalid, should be one of {",".join(period_names)}')
  period_seconds = (86400, 3600, 60, 1, 1/pow(10,3))
  period_desc = ('days', 'hours', 'mins', 'secs', 'msecs')
  round_i = period_names.index(round_period)

  s = ''
  remainder = tdelta.total_seconds()
  for i in range(len(period_names)):
    q, remainder = divmod(remainder, period_seconds[i])
    if int(q)>0:
      if not len(s)==0:
        s += ' '
      s += f'{q:.0f} {period_desc[i]}'
    if i==round_i:
      break
    if i==round_i+1:
      s += f'{remainder} {period_desc[round_i]}'
      break

  return s

z.B. auto omit zero leading period:

>>> td = timedelta(days=0, hours=2, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'second')
'2 hours 5 mins 8 secs'

oder den mittleren Nullpunkt weglassen:

>>> td = timedelta(days=2, hours=0, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'millisecond')
'2 days 5 mins 8 secs 3 msecs'

oder auf Minuten aufrunden, unter Minuten auslassen:

>>> td = timedelta(days=1, hours=2, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'minute')
'1 days 2 hours 5 mins'

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X