我在格式化日期时间时遇到了麻烦。timedelta对象。
这就是我想做的: 我有一个对象列表,对象类的成员之一是显示事件持续时间的timedelta对象。我想以小时:分钟的格式显示这个持续时间。
我尝试了各种方法来做这件事,但我有困难。我目前的方法是为返回小时和分钟的对象在类中添加方法。我可以通过除以time得到小时数。秒乘以3600,四舍五入。我在得到剩余的秒并将其转换为分钟时遇到了麻烦。
顺便说一下,我使用谷歌AppEngine和Django模板来表示。
我在格式化日期时间时遇到了麻烦。timedelta对象。
这就是我想做的: 我有一个对象列表,对象类的成员之一是显示事件持续时间的timedelta对象。我想以小时:分钟的格式显示这个持续时间。
我尝试了各种方法来做这件事,但我有困难。我目前的方法是为返回小时和分钟的对象在类中添加方法。我可以通过除以time得到小时数。秒乘以3600,四舍五入。我在得到剩余的秒并将其转换为分钟时遇到了麻烦。
顺便说一下,我使用谷歌AppEngine和Django模板来表示。
当前回答
一个班轮。由于timedelta不提供datetime的strftime,所以将timedelta带回datetime,并使用stftime。
这不仅可以实现OP要求的格式Hours:Minutes,现在您可以利用datetime的strftime的全部格式化功能,如果您的需求更改为另一种表示形式。
import datetime
td = datetime.timedelta(hours=2, minutes=10, seconds=5)
print(td)
print(datetime.datetime.strftime(datetime.datetime.strptime(str(td), "%H:%M:%S"), "%H:%M"))
Output:
2:10:05
02:10
这也解决了时间增量被格式化为H:MM:SS而不是HH:MM:SS的字符串的烦恼,这导致了我的这个问题,以及我分享的解决方案。
其他回答
我接着MarredCheese的回答,加上了年、月、毫秒和微秒
除秒外,所有数字都被格式化为整数,因此秒的分数可以自定义。
@kfmfe04要求几分之一秒,所以我发布了这个解决方案
大体上有一些例子。
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'))
输出:
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
Timedelta到字符串,用于打印运行时间信息。
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
例如,自动省略零前导周期:
>>> td = timedelta(days=0, hours=2, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'second')
'2 hours 5 mins 8 secs'
或者省略中间的零周期:
>>> td = timedelta(days=2, hours=0, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'millisecond')
'2 days 5 mins 8 secs 3 msecs'
或舍入至分钟,省略以下分钟:
>>> td = timedelta(days=1, hours=2, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'minute')
'1 days 2 hours 5 mins'
我有同样的问题,我使用熊猫Timedeltas,不想带来额外的依赖关系(另一个答案提到人类友好),所以我写了这个小函数只打印出相关信息:
def format_timedelta(td: pd.Timedelta) -> str:
if pd.isnull(td):
return str(td)
else:
c = td.components._asdict()
return ", ".join(f"{n} {unit}" for unit, n in c.items() if n)
例如,pd。Timedelta(hours=3, seconds=12)将打印为3小时12秒。
谢谢大家的帮助。我把你的很多想法放在一起,让我知道你的想法。
我像这样在类中添加了两个方法:
def hours(self):
retval = ""
if self.totalTime:
hoursfloat = self.totalTime.seconds / 3600
retval = round(hoursfloat)
return retval
def minutes(self):
retval = ""
if self.totalTime:
minutesfloat = self.totalTime.seconds / 60
hoursAsMinutes = self.hours() * 60
retval = round(minutesfloat - hoursAsMinutes)
return retval
在我的django中,我使用了这个(sum是对象,它在一个字典中):
<td>{{ sum.0 }}</td>
<td>{{ sum.1.hours|stringformat:"d" }}:{{ sum.1.minutes|stringformat:"#02.0d" }}</td>
我有一个函数:
def period(delta, pattern):
d = {'d': delta.days}
d['h'], rem = divmod(delta.seconds, 3600)
d['m'], d['s'] = divmod(rem, 60)
return pattern.format(**d)
例子:
>>> td = timedelta(seconds=123456789)
>>> period(td, "{d} days {h}:{m}:{s}")
'1428 days 21:33:9'
>>> period(td, "{h} hours, {m} minutes and {s} seconds, {d} days")
'21 hours, 33 minutes and 9 seconds, 1428 days'