我在格式化日期时间时遇到了麻烦。timedelta对象。
这就是我想做的: 我有一个对象列表,对象类的成员之一是显示事件持续时间的timedelta对象。我想以小时:分钟的格式显示这个持续时间。
我尝试了各种方法来做这件事,但我有困难。我目前的方法是为返回小时和分钟的对象在类中添加方法。我可以通过除以time得到小时数。秒乘以3600,四舍五入。我在得到剩余的秒并将其转换为分钟时遇到了麻烦。
顺便说一下,我使用谷歌AppEngine和Django模板来表示。
我在格式化日期时间时遇到了麻烦。timedelta对象。
这就是我想做的: 我有一个对象列表,对象类的成员之一是显示事件持续时间的timedelta对象。我想以小时:分钟的格式显示这个持续时间。
我尝试了各种方法来做这件事,但我有困难。我目前的方法是为返回小时和分钟的对象在类中添加方法。我可以通过除以time得到小时数。秒乘以3600,四舍五入。我在得到剩余的秒并将其转换为分钟时遇到了麻烦。
顺便说一下,我使用谷歌AppEngine和Django模板来表示。
当前回答
下面是一个通用函数,用于将timedelta对象或常规数字(以秒或分钟等形式)转换为格式化良好的字符串。我采用了mpounsett对一个重复问题的出色回答,使其更加灵活,提高了可读性,并添加了文档。
你会发现这是迄今为止最灵活的答案,因为它允许你:
动态自定义字符串格式,而不是硬编码。 省略特定的时间间隔没有问题(参见下面的例子)。
功能:
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)
演示:
>>> 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
其他回答
我接着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
我知道这是一个老问题,但我使用datetime.utcfromtimestamp()来解决这个问题。它接受秒数并返回一个datetime,该datetime可以像任何其他datetime一样格式化。
duration = datetime.utcfromtimestamp(end - begin)
print duration.strftime('%H:%M')
只要您停留在时间部分的合法范围内,这就应该工作,即它不会返回1234:35,因为小时<= 23。
我的datetime。Timedelta对象的时间大于一天。这是一个更深层次的问题。以上所有讨论都假设时间不超过一天。timedelta实际上是一个由日、秒和微秒组成的元组。上面的讨论应该使用td。秒,因为乔做了,但如果你有天,它不包括在秒值。
我得到2个日期时间和打印天和小时之间的时间跨度。
span = currentdt - previousdt
print '%d,%d\n' % (span.days,span.seconds/3600)
我个人使用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'
当然,它并没有给您所寻找的确切答案(实际上是str(timeA - timeB),但我发现,一旦超过几个小时,显示很快就变得不可读了。Humanize支持更大的值,这些值是人类可读的,而且本地化得很好。
它的灵感来自于Django的贡献。humanize模块,显然,既然你在使用Django,你应该使用它。
在这里,我会认真考虑奥卡姆剃刀方法:
td = str(timedelta).split('.')[0]
这将返回一个没有微秒的字符串
如果要重新生成datetime。Timedelta对象,只需要这样做:
h,m,s = re.split(':', td)
new_delta = datetime.timedelta(hours=int(h),minutes=int(m),seconds=int(s))
2年了,我爱上了这门语言!