web-dev-qa-db-de.com

Timedelta des Python-Formats in Zeichenfolge

Ich bin ein Python-Neuling (2 Wochen) und habe Probleme beim Formatieren eines datetime.timedelta-Objekts.

Folgendes versuche ich zu tun: Ich habe eine Liste von Objekten und eines der Member 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 und habe Schwierigkeiten. Mein aktueller Ansatz besteht darin, der Klasse Methoden für meine Objekte hinzuzufügen, die Stunden und Minuten zurückgeben. Ich kann die Stunden erhalten, indem ich die Zeitsekunde in 3600 dividiere und rundete. Ich habe Probleme, die restlichen Sekunden zu bekommen und diese in Minuten umzuwandeln.

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

Wenn jemand helfen kann oder einen besseren Weg kennt, um dieses Problem zu lösen, wäre ich sehr glücklich.

Vielen Dank,

214
mawcs

Sie können das Timedelta einfach mit str () in einen String konvertieren. Hier ist ein Beispiel:

import datetime
start = datetime.datetime(2009,2,10,14,00)
end   = datetime.datetime(2009,2,10,16,00)
delta = end-start
print(str(delta))
# prints 2:00:00
172
Parand

Wie Sie wissen, können Sie die Gesamtsekunden von einem Timedelta-Objekt abrufen, indem Sie auf das .seconds-Attribut zugreifen.

Python bietet die integrierte Funktion divmod(), die Folgendes ermöglicht:

s = 13420
hours, remainder = divmod(s, 3600)
minutes, seconds = divmod(remainder, 60)
print '{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds))
# result: 03:43:40

oder Sie können in Stunden und Rest umwandeln, indem Sie eine Kombination aus Modulo und Subtraktion verwenden:

# arbitrary number of seconds
s = 13420
# hours
hours = s // 3600 
# remaining seconds
s = s - (hours * 3600)
# minutes
minutes = s // 60
# remaining seconds
seconds = s - (minutes * 60)
# total time
print '{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds))
# result: 03:43:40
147
John Fouhy
>>> str(datetime.timedelta(hours=10.56))
10:33:36

>>> td = datetime.timedelta(hours=10.505) # any timedelta object
>>> ':'.join(str(td).split(':')[:2])
10:30

Wenn Sie das Objekt timedelta an die Funktion str() übergeben, wird derselbe Formatierungscode aufgerufen, wenn Sie einfach print td eingeben. Da Sie die Sekunden nicht wollen, können wir die Zeichenfolge in Doppelteile (3 Teile) aufteilen und nur die ersten beiden Teile zusammensetzen.

53
joeforker
def td_format(td_object):
    seconds = int(td_object.total_seconds())
    periods = [
        ('year',        60*60*24*365),
        ('month',       60*60*24*30),
        ('day',         60*60*24),
        ('hour',        60*60),
        ('minute',      60),
        ('second',      1)
    ]

    strings=[]
    for period_name, period_seconds in periods:
        if seconds > period_seconds:
            period_value , seconds = divmod(seconds, period_seconds)
            has_s = 's' if period_value > 1 else ''
            strings.append("%s %s%s" % (period_value, period_name, has_s))

    return ", ".join(strings)
33

Er hat bereits ein Timedelta-Objekt. Warum also nicht die eingebaute Methode total_seconds () verwenden, um es in Sekunden zu konvertieren, und dann divmod () verwenden, um Stunden und Minuten zu erhalten? 

hours, remainder = divmod(myTimeDelta.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)

# Formatted only for hours and minutes as requested
print '%s:%s' % (hours, minutes)

Dies funktioniert unabhängig davon, ob das Zeitdelta gerade Tage oder Jahre hat.

26
Bill Kidd

Ich persönlich verwende dazu die Bibliothek humanize /:

>>> import datetime
>>> humanize.naturalday(datetime.datetime.now())
'today'
>>> humanize.naturalday(datetime.datetime.now() - datetime.timedelta(days=1))
'yesterday'
>>> humanize.naturalday(datetime.date(2007, 6, 5))
'Jun 05'
>>> humanize.naturaldate(datetime.date(2007, 6, 5))
'Jun 05 2007'
>>> humanize.naturaltime(datetime.datetime.now() - datetime.timedelta(seconds=1))
'a second ago'
>>> humanize.naturaltime(datetime.datetime.now() - datetime.timedelta(seconds=3600))
'an hour ago'

Natürlich gibt es Ihnen nicht genau die Antwort, nach der Sie gesucht haben (was in der Tat str(timeA - timeB) ist, aber ich habe festgestellt, dass die Anzeige nach einigen Stunden schnell unlesbar wird. humanize unterstützt viel größere Werte, die für Menschen lesbar sind, und ist auch gut lokalisiert.

Es ist anscheinend von Djangos contrib.humanize-Modul inspiriert. Da Sie Django verwenden, sollten Sie dies wahrscheinlich verwenden.

18
anarcat

Ich weiß, dass dies eine alte beantwortete Frage ist, aber ich verwende datetime.utcfromtimestamp(). Es dauert die Anzahl von Sekunden und gibt eine datetime zurück, die wie jede andere datetime formatiert werden kann.

duration = datetime.utcfromtimestamp(end - begin)
print duration.strftime('%H:%M')

Solange Sie für die Zeitbereiche in den gesetzlichen Grenzen bleiben, sollte dies funktionieren, d. H. 1234: 35 wird nicht zurückgegeben, da Stunden <= 23 sind.

15
sjngm

Der Fragesteller wünscht sich ein schöneres Format als das typische:

  >>> import datetime
  >>> datetime.timedelta(seconds=41000)
  datetime.timedelta(0, 41000)
  >>> str(datetime.timedelta(seconds=41000))
  '11:23:20'
  >>> str(datetime.timedelta(seconds=4102.33))
  '1:08:22.330000'
  >>> str(datetime.timedelta(seconds=413302.33))
  '4 days, 18:48:22.330000'

Es gibt also zwei Formate: Eines ist, wo die Tage 0 sind und nicht angegeben werden, und eines, wo der Text "n Tage, h: m: s" ist. Die Sekunden haben jedoch Brüche und es gibt keine führenden Nullen in den Ausdrucken, daher sind die Spalten unordentlich.

Hier ist meine Routine, wenn es Ihnen gefällt:

def printNiceTimeDelta(stime, etime):
    delay = datetime.timedelta(seconds=(etime - stime))
    if (delay.days > 0):
        out = str(delay).replace(" days, ", ":")
    else:
        out = "0:" + str(delay)
    outAr = out.split(':')
    outAr = ["%02d" % (int(float(x))) for x in outAr]
    out   = ":".join(outAr)
    return out

dies gibt die Ausgabe als dd: hh: mm: ss Format zurück:

00:00:00:15
00:00:00:19
02:01:31:40
02:01:32:22

Ich habe darüber nachgedacht, Jahre hinzuzufügen, aber dies ist für den Leser eine Übung, da die Ausgabe mit über 1 Jahr sicher ist:

>>> str(datetime.timedelta(seconds=99999999))
'1157 days, 9:46:39'
14
Kevin J. Rice

Meine datetime.timedelta-Objekte waren länger als ein Tag. Hier ist also ein weiteres Problem. Alle obigen Ausführungen gehen von weniger als einem Tag aus. Eine timedelta ist eigentlich ein Tuple von Tagen, Sekunden und Mikrosekunden. Die obige Diskussion sollte td.seconds wie bei Joe verwenden, aber wenn Sie Tage haben, ist dies NICHT im Sekundenwert enthalten. 

Ich habe eine Zeitspanne zwischen zwei Datumsangaben und Drucktagen und -stunden.

span = currentdt - previousdt
print '%d,%d\n' % (span.days,span.seconds/3600)
12
user198910

Hier ist eine allgemeine Funktion zum Konvertieren eines timedelta-Objekts oder einer regulären Zahl (in Form von Sekunden oder Minuten usw.) in eine schön formatierte Zeichenfolge. Ich nahm mpounsetts fantastische Antwort auf eine doppelte Frage, machte sie etwas flexibler, verbesserte die Lesbarkeit und fügte Dokumentation hinzu. 

Sie werden feststellen, dass dies die bisher flexibelste Antwort ist, da Sie:

  1. Passen Sie das Zeichenfolgenformat schnell an, anstatt es fest zu codieren.
  2. Lassen Sie bestimmte Zeitintervalle problemlos aus (siehe Beispiele unten).

Funktion:

from string import Formatter
from datetime import timedelta

def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02}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}s' --> '05d 08h 04m 02s' (default)
        '{W}w {D}d {H}:{M:02}:{S:02}'     --> '4w 5d 8:04:02'
        '{D:2}d {H:2}:{M:02}:{S:02}'      --> ' 5d  8:04:02'
        '{H}h {S}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 = int(tdelta.total_seconds())
    Elif inputtype in ['s', 'seconds']:
        remainder = int(tdelta)
    Elif inputtype in ['m', 'minutes']:
        remainder = int(tdelta)*60
    Elif inputtype in ['h', 'hours']:
        remainder = int(tdelta)*3600
    Elif inputtype in ['d', 'days']:
        remainder = int(tdelta)*86400
    Elif inputtype in ['w', 'weeks']:
        remainder = int(tdelta)*604800

    f = Formatter()
    desired_fields = [field_Tuple[1] for field_Tuple in f.parse(fmt)]
    possible_fields = ('W', 'D', 'H', 'M', 'S')
    constants = {'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
    values = {}
    for field in possible_fields:
        if field in desired_fields and field in constants:
            values[field], remainder = divmod(remainder, constants[field])
    return f.format(fmt, **values)

Demo:

>>> td = timedelta(days=2, hours=3, minutes=5, seconds=8, microseconds=340)

>>> print strfdelta(td)
02d 03h 05m 08s

>>> print strfdelta(td, '{D}d {H}:{M:02}:{S:02}')
2d 3:05:08

>>> print strfdelta(td, '{D:2}d {H:2}:{M:02}:{S:02}')
 2d  3:05:08

>>> print strfdelta(td, '{H}h {S}s')
51h 308s

>>> print strfdelta(12304, inputtype='s')
00d 03h 25m 04s

>>> print strfdelta(620, '{H}:{M:02}', 'm')
10:20

>>> print strfdelta(49, '{D}d {H}h', 'h')
2d 1h
9
MarredCheese

Ich würde den Ansatz von Occam's Razor hier ernsthaft in Betracht ziehen:

td = str(timedelta).split('.')[0]

Dies gibt eine Zeichenfolge ohne Mikrosekunden zurück

Wenn Sie das datetime.timedelta-Objekt neu generieren möchten, führen Sie einfach Folgendes aus:

h,m,s = re.split(':', td)
new_delta = datetime.timedelta(hours=int(h),minutes=int(m),seconds=int(s))

2 Jahre in, ich liebe diese Sprache!

8
Pyrotherm

Nach dem obigen Beispielwert von Joe würde ich den Modulus-Arithmetikoperator verwenden, also:

td = datetime.timedelta(hours=10.56)
td_str = "%d:%d" % (td.seconds/3600, td.seconds%3600/60)

Beachten Sie, dass die Ganzzahleinteilung in Python standardmäßig abgerundet wird. Wenn Sie expliziter sein wollen, verwenden Sie math.floor () oder math.ceil ().

6
UltraNurd

Ich habe dazu die humanfriendly-Python-Bibliothek verwendet, die sehr gut funktioniert.

import humanfriendly
from datetime import timedelta
delta = timedelta(seconds = 321)
humanfriendly.format_timespan(delta)

'5 minutes and 21 seconds'

Verfügbar unter https://pypi.org/project/humanfriendly/

3
Dhiraj Gupta
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
3
Veselin Penev

Ich hatte ein ähnliches Problem mit der Überstundenberechnung bei der Arbeit. Der Wert sollte immer in HH: MM angezeigt werden, auch wenn er größer als ein Tag ist und der Wert negativ werden kann. Ich habe einige der gezeigten Lösungen kombiniert, und vielleicht findet diese Lösung für jemanden nützlich. Mir wurde klar, dass die meisten der gezeigten Lösungen mit der divmod-Methode nicht funktionieren, wenn der zeitliche Deltawert negativ ist:

def td2HHMMstr(td):
  '''Convert timedelta objects to a HH:MM string with (+/-) sign'''
  if td < datetime.timedelta(seconds=0):
    sign='-'
    td = -td
  else:
    sign = ''
  tdhours, rem = divmod(td.total_seconds(), 3600)
  tdminutes, rem = divmod(rem, 60)
  tdstr = '{}{:}:{:02d}'.format(sign, int(tdhours), int(tdminutes))
  return tdstr

zeitliches Delta zu HH: MM-String:

td2HHMMstr(datetime.timedelta(hours=1, minutes=45))
'1:54'

td2HHMMstr(datetime.timedelta(days=2, hours=3, minutes=2))
'51:02'

td2HHMMstr(datetime.timedelta(hours=-3, minutes=-2))
'-3:02'

td2HHMMstr(datetime.timedelta(days=-35, hours=-3, minutes=-2))
'-843:02'
3
nealtz
import datetime
hours = datetime.timedelta(hours=16, minutes=30)
print((datetime.datetime(1,1,1) + hours).strftime('%H:%M'))
2
SleX
from Django.utils.translation import ngettext

def localize_timedelta(delta):
    ret = []
    num_years = int(delta.days / 365)
    if num_years > 0:
        delta -= timedelta(days=num_years * 365)
        ret.append(ngettext('%d year', '%d years', num_years) % num_years)

    if delta.days > 0:
        ret.append(ngettext('%d day', '%d days', delta.days) % delta.days)

    num_hours = int(delta.seconds / 3600)
    if num_hours > 0:
        delta -= timedelta(hours=num_hours)
        ret.append(ngettext('%d hour', '%d hours', num_hours) % num_hours)

    num_minutes = int(delta.seconds / 60)
    if num_minutes > 0:
        ret.append(ngettext('%d minute', '%d minutes', num_minutes) % num_minutes)

    return ' '.join(ret)

Dies wird produzieren:

>>> from datetime import timedelta
>>> localize_timedelta(timedelta(days=3660, minutes=500))
'10 years 10 days 8 hours 20 minutes'
1
Artem Vasilev

Bitte überprüfen Sie diese Funktion - es konvertiert das Timedelta-Objekt in den String 'HH: MM: SS'.

def format_timedelta(td):
    hours, remainder = divmod(td.total_seconds(), 3600)
    minutes, seconds = divmod(remainder, 60)
    hours, minutes, seconds = int(hours), int(minutes), int(seconds)
    if hours < 10:
        hours = '0%s' % int(hours)
    if minutes < 10:
        minutes = '0%s' % minutes
    if seconds < 10:
        seconds = '0%s' % seconds
    return '%s:%s:%s' % (hours, minutes, seconds)
0
MobilePro.pl