J'ai deux datetime
objets. J'ai besoin de calculer le timedelta
entre eux, puis d'afficher la sortie dans un format spécifique.
Alpha_TimeObj = datetime.datetime(int(AlphaTime.strftime('%Y')), int(AlphaTime.strftime('%m')), int(AlphaTime.strftime('%d')), int(AlphaTime.strftime('%H')), int(AlphaTime.strftime('%M')), int(AlphaTime.strftime('%S')))
Beta_TimeObj = datetime.datetime(int(BetaTime.strftime('%Y')), int(BetaTime.strftime('%m')), int(BetaTime.strftime('%d')), int(BetaTime.strftime('%H')), int(BetaTime.strftime('%M')), int(BetaTime.strftime('%S')))
Turnaround_TimeObj = Beta_TimeObj - Alpha_TimeObj
Un exemple de cette Turnaround_TimeObj
le delta horaire est "2 jours, 22:13:45". Je souhaite formater la sortie mais je ne peux pas le faire.
print Turnaround_TimeObj.strftime('%H hrs %M mins %S secs')
ne fonctionne pas.
Je sais qu'une façon de le faire sera de le convertir en secondes puis de divmoder pour obtenir le formatage requis. un péché:
totalSeconds = Turnaround_TimeObj.seconds
hours, remainder = divmod(totalSeconds, 3600)
minutes, seconds = divmod(remainder, 60)
print '%s:%s:%s' % (hours, minutes, seconds)
Mais je me demandais si je pouvais le faire sur une seule ligne en utilisant n'importe quelle fonction date-heure comme strftime
.
Edit: La conversion en secondes ne fonctionne pas non plus. Si je convertis le delta de temps "1 jour, 3:42:54" en secondes en utilisant
totalSeconds = Turnaround_TimeObj.seconds
totalSeconds
valeur est affichée comme 13374 au lieu de 99774. c'est-à-dire qu'elle ignore la valeur "jour".
mais je me demandais si je pouvais le faire sur une seule ligne en utilisant une fonction date-heure comme strftime.
Pour autant que je sache, il n'y a pas de méthode intégrée à timedelta
qui le fasse. Si vous le faites souvent, vous pouvez créer votre propre fonction, par ex.
def strfdelta(tdelta, fmt):
d = {"days": tdelta.days}
d["hours"], rem = divmod(tdelta.seconds, 3600)
d["minutes"], d["seconds"] = divmod(rem, 60)
return fmt.format(**d)
Usage:
>>> print strfdelta(delta_obj, "{days} days {hours}:{minutes}:{seconds}")
1 days 20:18:12
>>> print strfdelta(delta_obj, "{hours} hours and {minutes} to go")
20 hours and 18 to go
Si vous souhaitez utiliser un format de chaîne plus proche de celui utilisé par strftime
, nous pouvons utiliser string.Template
.
from string import Template
class DeltaTemplate(Template):
delimiter = "%"
def strfdelta(tdelta, fmt):
d = {"D": tdelta.days}
d["H"], rem = divmod(tdelta.seconds, 3600)
d["M"], d["S"] = divmod(rem, 60)
t = DeltaTemplate(fmt)
return t.substitute(**d)
Usage:
>>> print strfdelta(delta_obj, "%D days %H:%M:%S")
1 days 20:18:12
>>> print strfdelta(delta_obj, "%H hours and %M to go")
20 hours and 18 to go
la valeur totalSeconds est indiquée comme 13374 au lieu de 99774. ie. son ignorer la valeur "jour".
Notez dans l'exemple ci-dessus que vous pouvez utiliser timedelta.days
pour obtenir la valeur "jour".
Alternativement, à partir de Python 2.7, timedelta a une méthode total_seconds () qui retourne le nombre total de secondes contenues dans la durée.
En Python2.7 ou plus récent, vous pouvez utiliser la méthode total_seconds :
import datetime as dt
turnaround = dt.timedelta(days = 1, hours = 3, minutes = 42, seconds = 54)
total_seconds = int(turnaround.total_seconds())
hours, remainder = divmod(total_seconds,60*60)
minutes, seconds = divmod(remainder,60)
print('{} hrs {} mins {} secs'.format(hours,minutes,seconds))
les rendements
27 hrs 42 mins 54 secs
En Python2.6 ou version antérieure, vous pouvez calculer le total_seconds
toi même:
total_seconds = turnaround.seconds + turnaround.days*24*60*60
(pour la formule plus générale, y compris les microsecondes, voir le lien ci-dessus).
La réponse de Shawn Chin est bonne, mais un problème avec cela est que si vous sautez un élément particulier dans votre format (comme dans son deuxième exemple qui n'a que des heures et des minutes .. pas des jours ou des secondes) alors ce temps disparaît de votre résultat . Vous pouvez le modifier pour résoudre ce problème et obtenir des résultats plus précis en ne traitant que les mots clés qui apparaissent réellement dans la chaîne de format.
class DeltaTemplate(Template):
delimiter = '%'
def strfdelta(tdelta, fmt):
d = {}
l = {'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
rem = int(tdelta.total_seconds())
for k in ( 'D', 'H', 'M', 'S' ):
if "%{}".format(k) in fmt:
d[k], rem = divmod(rem, l[k])
t = DeltaTemplate(fmt)
return t.substitute(**d)
Usage:
>>> print strfdelta(delta_obj, "%D days %H:%M:%S")
1 days 20:18:12
>>> print strfdelta(delta_obj, "%H hours and %M to go")
44 hours and 18 to go
Cependant, le formatage est inflexible, car vous ne pouvez pas appliquer de chaînes de conversion et vous retrouver avec des choses laides comme ceci:
>>> delta_obj = timedelta(minutes=5, seconds=2)
>>> print strfdelta(delta_obj, "%H:%M:%S")
0:5:2
Cependant, vous pouvez adopter la même approche et l'appliquer à string.Formatter au lieu de string.Template et obtenir quelque chose de bien meilleur.
from string import Formatter
def strfdelta(tdelta, fmt):
f = Formatter()
d = {}
l = {'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
k = map( lambda x: x[1], list(f.parse(fmt)))
rem = int(tdelta.total_seconds())
for i in ('D', 'H', 'M', 'S'):
if i in k and i in l.keys():
d[i], rem = divmod(rem, l[i])
return f.format(fmt, **d)
Usage:
>>> delta_obj = timedelta(days=1, hours=20, minutes=18, seconds=12)
>>> print strfdelta(delta_obj, "{D} days {H}:{M}:{S}")
1 days 20:18:12
>>> print strfdelta(delta_obj, "{H} hours and {M} to go")
44 hours and 18 to go
>>> delta_obj = timedelta(minutes=5, seconds=2)
>>> print strfdelta(delta_obj, "{H:02}h{M:02}m{S:02}s")
00h05m02s
>>> print strfdelta(delta_obj, "{H:02}:{M:02}:{S:02}")
00:05:02
Une légère variante sur Shawn Chin 's answer - qui répond également à un issue soulevé par mpouncett - remplit le heures, minutes et secondes avec des zéros au début pour garantir que les 3 éléments utilisent 2 places (plus cohérent avec les spécifications de ces champs dans strftime ):
from string import Template
class DeltaTemplate(Template):
delimiter = "%"
def strfdelta(tdelta, fmt):
d = {"D": tdelta.days}
hours, rem = divmod(tdelta.seconds, 3600)
minutes, seconds = divmod(rem, 60)
d["H"] = '{:02d}'.format(hours)
d["M"] = '{:02d}'.format(minutes)
d["S"] = '{:02d}'.format(seconds)
t = DeltaTemplate(fmt)
return t.substitute(**d)
Voici un test pour quelques exemples de valeurs:
from datetime import timedelta
for seconds in [0, 1, 59, 60, 61, 3599, 3600, 3601]:
print strfdelta(timedelta(0, seconds), '%H:%M:%S')
Et voici la sortie:
00:00:00
00:00:01
00:00:59
00:01:00
00:01:01
00:59:59
01:00:00
01:00:01
Vous pouvez utiliser le module dateutil qui a l'objet relativedelta le plus convivial.
import dateutil
import datetime
alpha = datetime.datetime(2012, 1, 16, 6, 0)
beta = datetime.datetime(2012, 1, 18, 10, 42, 57, 230301)
delta = dateutil.relativedelta(beta, alpha)
cela vous donne un delta d'objet qui ressemble
>>> delta
relativedelta(days=+2, hours=+4, minutes=+42, seconds=+57, microseconds=+230301)
Vous pouvez alors faire
print('turnaround %i hrs %i mins %i secs' % (delta.days * 24 + delta.hours, delta.minutes, delta.seconds)
)
def to_time(seconds):
delta = datetime.timedelta(seconds=seconds)
return str(delta.days) + 'd ' + (datetime.datetime.utcfromtimestamp(0) + delta).strftime('%H:%M')
Les réponses ci-dessus ne semblent pas gérer les valeurs de timedelta négatives (telles que produites par exemple par pytz pour les fuseaux horaires "gauche" de UTC ). Comme selon la documentation , les objets timedelta sont normalisés et un timedelta négatif est représenté par un attribut d'instance day
négatif. De la documentation:
Notez que la normalisation des valeurs négatives peut être surprenante au premier abord.
et cela
Les représentations de chaînes d'objets timedelta sont normalisées de la même manière que leur représentation interne. Cela conduit à des résultats quelque peu inhabituels pour les timedeltas négatifs.
Par exemple:
>>> td = timedelta(seconds=-30)
>>> str(td)
'-1 day, 23:59:30'
>>> repr(td)
'datetime.timedelta(-1, 86370)'
Dans cet exemple, timedelta, à la fois réponse acceptée par Shawn Chin et réponse de gumption return '23:59:30'
et réponse de mpounsett'-1:59:30'
.
Je pense que pour imprimer des timedeltas négatifs et positifs d'une manière plus lisible, nous devons gérer explicitement le signe et la valeur absolue d'un objet de fuseau horaire:
def strfdelta(td, fmt):
# Get the timedelta’s sign and absolute number of seconds.
sign = "-" if td.days < 0 else "+"
secs = abs(td).total_seconds()
# Break the seconds into more readable quantities.
days, rem = divmod(secs, 86400) # seconds per day: 24 * 60 * 60
hours, rem = divmod(rem, 3600) # seconds per hour: 60 * 60
mins, secs = divmod(rem, 60)
# Format (as per above answers) and return the result string.
t = DeltaTemplate(fmt)
return t.substitute(
s=sign,
D="{:d}".format(int(days)),
H="{:02d}".format(int(hours)),
M="{:02d}".format(int(mins)),
S="{:02d}".format(int(secs)),
)
Cette fonction renvoie une représentation sous forme de chaîne plus lisible:
>>> strfdelta(td, "%s%H:%M:%S") # Note that %s refers to the timedelta’s sign.
'-00:00:30'
>>> strfdelta(timedelta(days=-1), "%s%D %H:%M:%S")
'-1 00:00:00'
>>> strfdelta(timedelta(days=-1, minutes=5), "%s%D %H:%M:%S")
'-0 23:55:00'
>>> strfdelta(timedelta(days=-1, minutes=-5), "%s%D %H:%M:%S")
'-1 00:05:00'
… Ou dans le contexte plus pratique des fuseaux horaires:
>>> import pytz
>>> import datetime
>>> td = pytz.timezone("Canada/Newfoundland").utcoffset(datetime.datetime.now())
>>> td
datetime.timedelta(-1, 77400)
>>> strfdelta(td, fmt="%s%H:%M")
'-02:30'
>>> td = pytz.timezone("Australia/Eucla").utcoffset(datetime.datetime.now())
>>> td
datetime.timedelta(0, 31500)
>>> strfdelta(td, fmt="%s%H:%M")
'+08:45'