将 timedelta 格式化为字符串
Posted
技术标签:
【中文标题】将 timedelta 格式化为字符串【英文标题】:Format timedelta to string 【发布时间】:2010-10-07 00:33:24 【问题描述】:我在格式化 datetime.timedelta
对象时遇到问题。
这就是我想要做的事情: 我有一个对象列表,对象类的成员之一是显示事件持续时间的 timedelta 对象。我想以小时:分钟的格式显示该持续时间。
我已经尝试了多种方法来做到这一点,但我遇到了困难。我目前的方法是为返回小时和分钟的对象添加方法到类。我可以通过将 timedelta.seconds 除以 3600 并四舍五入来获得小时数。我无法获取剩余的秒数并将其转换为分钟数。
顺便说一句,我正在使用带有 Django 模板的 Google AppEngine 进行演示。
【问题讨论】:
如果 timedelta 有一个等效的 strftime() 方法会很好。 @JS。好吧,如果你使用datetime.utcfromtimestamp()
,你就可以了。请参阅下面的my answer。
@JS。 - 100% 同意。然后,timedelta
的__str__
相当不错,而不是__repr__
(即——对于人类而言!)。例如:datetime.timedelta(minutes=6, seconds=41) * 2618 / 48
给出了datetime.timedelta(seconds=21871, microseconds=208333)
,但str(datetime.timedelta(minutes=6, seconds=41) * 2618 / 48)
给出了'6:04:31.208333'
,这很容易阅读。
@JS。在 python3 中,datetime 模块在文件 /usr/lib/python3.7/datetime.py 中以纯 python 实现。在这个文件的末尾,import from _datetime
用一个编译过的纯 python 实现覆盖。但是,如果您注释掉 import
模块可以工作,您可以直接在所述文件中或通过猴子补丁添加 datetime.timedelta.__format__
方法。
当然commenting out the import
,正如我自己所建议的那样,有影响:性能下降(strptime 慢 2 倍),出现不兼容(时区模块崩溃)。
【参考方案1】:
>>> 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
将timedelta
对象传递给str()
函数调用的格式代码与我们只需键入print td
时使用的格式代码相同。由于您不想要秒数,我们可以用冒号(3 部分)分割字符串,然后仅将前 2 部分放在一起。
【讨论】:
感谢您的回答 joeforker,但我不确定我是否理解您的回复。我通过 datetime - datetime 获得时间增量。我不知道时间。另外,您的示例似乎包含秒数,我将如何删除它? 无论你从哪里得到 timedelta 对象,它的格式都是一样的。 如果超过一天,它将格式化为例如拆分/加入处理后的“4 天,8:00”。str(my_timedelta)
对负数效果不佳
也显示 >24 小时的天数,例如'4 天,18:48:22.330000'。这里推荐的许多方法都没有。【参考方案2】:
按照上面 Joe 的示例值,我将使用模算术运算符,因此:
td = datetime.timedelta(hours=10.56)
td_str = "%d:%d" % (td.seconds/3600, td.seconds%3600/60)
请注意,Python 中的整数除法默认向下舍入;如果您想更明确,请酌情使用 math.floor() 或 math.ceil()。
【讨论】:
timedelta 已经知道如何格式化自己,如“print some_timedelta”。 是的,但它不能接受任意格式的字符串,这是 Michael 所要求的。虽然现在我想起来了,3600 除法模型做出了小时秒假设,这会导致闰秒出现问题。 是的,但他不想要任意格式的字符串,他想要几乎完全一样的默认行为。 不要忘记 // 在 Python 3000 中截断除法 +1,但你为什么不编辑答案以使用//?我还建议使用td.total_seconds()
而不是.seconds
使其工作间隔> 1 天。【参考方案3】:
您可以使用 str() 将 timedelta 转换为字符串。这是一个例子:
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
【讨论】:
更像是调用 str() 方法,以 timedelta 作为参数。 这里不需要 str 调用,它会通过 print 自动完成。 @Zitrax 但如果您要将增量与另一个字符串连接起来,这是必要的。例如print 'some thing ' + str(delta)
当数据类型被定义为'datetime.timedelta'并且你像ConvertDuration=datetime.timedelta(milliseconds=int(254459))
这样使用它时,你只需使用split来消除微秒。从 0:03:43.765000 我可以通过简单地运行 TotalDuration=str(ConvertDuration).split('.', 2)[0]
得到 0:03:43
这可能会将增量打印为字符串,但不会按照 OP 的要求对其进行格式化。【参考方案4】:
感谢大家的帮助。我吸收了你的许多想法并将它们组合在一起,让我知道你的想法。
我在类中添加了两个方法,如下所示:
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 hhmm(self): return ':'.join(str(td).split(':')[:2])如您所知,您可以通过访问.seconds
属性从 timedelta 对象中获取 total_seconds。
Python 提供了内置函数divmod()
,它允许:
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
或者您可以使用模数和减法的组合转换为小时和余数:
# 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
【讨论】:
对于负时间增量,您应该先评估符号,然后再执行abs(s)
。
请注意,您实际上可能希望使用'%d:%02d:%02d'
在输出字符串中包含前导零。
对于 python 2.7 及更高版本使用 .total_seconds() 方法
如果差异可能为负数或超过 24 小时,请勿使用 .seconds
(.seconds
属性忽略 .days
)。请改用.total_seconds()
或其类似物。
对于积极的差异,我不时重新实现这一点。感谢您只需搜索这一次 :)【参考方案6】:
我的datetime.timedelta
对象超过了一天。所以这里还有一个问题。上面的所有讨论都假设不到一天。 timedelta
实际上是天、秒和微秒的元组。上面的讨论应该像 joe 一样使用td.seconds
,但如果你有天数,它不会包含在秒值中。
我得到了 2 个日期时间和打印日期和小时之间的时间跨度。
span = currentdt - previousdt
print '%d,%d\n' % (span.days,span.seconds/3600)
【讨论】:
这是面向未来的解决方案。【参考方案7】: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)
【讨论】:
真的很好,不过我建议将if seconds > period_seconds:
改为if seconds >= period_seconds:
。
这会返回负时间增量的空字符串,不确定这是不是有意的?
我尝试了 5473 天,我得到:“14 年,12 个月,3 天”。为什么不是“15年零3天”呢?此外,根据谷歌,5473 是“14.99452 日历年”和“0.99451999988374 日历年是 11.93422692000003593 个月”,而“0.93422692000003593193 个月是 28.416099957565091216 天。因此,不是正确的28 天”?【参考方案8】:
提问者想要一种比典型格式更好的格式:
>>> 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'
所以,实际上有两种格式,一种是天数为 0 并且被省略,另一种是文本“n 天,h:m:s”。但是,秒可能有分数,并且打印输出中没有前导零,所以列很乱。
这是我的日常,如果你喜欢的话:
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
这会以 dd:hh:mm:ss 格式返回输出:
00:00:00:15
00:00:00:19
02:01:31:40
02:01:32:22
我确实考虑过为此添加年份,但这留给读者作为练习,因为输出在 1 年以上是安全的:
>>> str(datetime.timedelta(seconds=99999999))
'1157 days, 9:46:39'
【讨论】:
【参考方案9】:他已经有一个 timedelta 对象,为什么不使用它的内置方法 total_seconds() 将其转换为秒,然后使用 divmod() 获取小时和分钟?
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)
无论时间增量是偶数天还是数年,这都有效。
【讨论】:
【参考方案10】:t1 = datetime.datetime.strptime(StartTime, "%H:%M:%S %d-%m-%y")
t2 = datetime.datetime.strptime(EndTime, "%H:%M:%S %d-%m-%y")
return str(t2-t1)
所以对于:
StartTime = '15:28:53 21-07-13'
EndTime = '15:32:40 21-07-13'
返回:
'0:03:47'
【讨论】:
【参考方案11】: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
【讨论】:
这是你写的吗?你测试了多少? 我在名为datahaven.net 的项目中使用此代码。它工作得很好。您发现任何错误吗? 如果你能用这样一个代码重的答案提供一些信息总是很好的 :) 就像一个例子,它是如何工作的,可能的优点和缺点。 哦。当然!。为您添加了一个示例。 :-) Super :) 另请注意,timedelta
对象在文档中具有 days
、seconds
和 microseconds
字段。【参考方案12】:
我在工作中的加班计算输出也遇到了类似的问题。该值应始终以 HH:MM 显示,即使它大于 1 天并且该值可能为负数。我结合了一些显示的解决方案,也许其他人发现这个解决方案很有用。我意识到,如果 timedelta 值为负,则大多数使用 divmod 方法显示的解决方案都无法开箱即用:
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
timedelta 到 HH:MM 字符串:
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'
【讨论】:
【参考方案13】:我知道这是一个老问题,但我为此使用了datetime.utcfromtimestamp()
。它需要秒数并返回一个datetime
,可以像任何其他datetime
一样格式化。
duration = datetime.utcfromtimestamp(end - begin)
print duration.strftime('%H:%M')
只要您在应该工作的时间部分保持在合法范围内,即它不会返回 1234:35,因为小时数
【讨论】:
你应该改用print timedelta(seconds=end - begin)
。
@J.F.Sebastian 那么你必须用前导零手动填充小时数。
需要一个 .total_seconds() 调用:>>> datetime.utcfromtimestamp((t2-t1).total_seconds()).strftime("%H:%M:%S") >> '00:00:05'
我更喜欢这个解决方案,它允许您控制格式。请注意,您也可以像这样直接使用 str 格式化程序:"0:%H:0:%M".format(duration)
如果有timedelta
对象,可以直接使用:datetime.utcfromtimestamp(delta.total_seconds())
【参考方案14】:
我会在这里认真考虑奥卡姆剃刀方法:
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 年了,我喜欢这种语言!
【讨论】:
这不包括天数【参考方案15】:请检查此函数 - 它会将 timedelta 对象转换为字符串 '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)
【讨论】:
【参考方案16】: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)
这将产生:
>>> from datetime import timedelta
>>> localize_timedelta(timedelta(days=3660, minutes=500))
'10 years 10 days 8 hours 20 minutes'
【讨论】:
我认为最整洁的一个,就长度和涵盖的内容而言【参考方案17】:我个人为此使用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)
,但我发现一旦您超过几个小时, display 很快变得不可读。humanize
支持人类可读的更大值,并且本地化也很好。
显然,它受到 Django 的 contrib.humanize
模块的启发,所以既然您使用的是 Django,那么您可能应该使用它。
【讨论】:
不错,+1 虽然:humanize.naturaldelta(pd.Timedelta('-10sec')) --> '10 seconds' :S... 嗯,它是 10 秒delta。 :) 你想要 时间,naturaltime
就是你想要使用的。【参考方案18】:
这是一个通用函数,用于将timedelta
对象或常规数字(以秒或分钟等形式)转换为格式良好的字符串。我在一个重复的问题上使用了mpounsett's fantastic answer,使其更加灵活,提高了可读性,并添加了文档。
您会发现这是迄今为止最灵活的答案,因为它允许您:
-
即时自定义字符串格式,而不是硬编码。
忽略某些时间间隔不会出现问题(参见下面的示例)。
功能:
from string import Formatter
from datetime import timedelta
def strfdelta(tdelta, fmt='D:02d H:02h M:02m S:02s', 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:02d H:02h M:02m S:02s' --> '05d 08h 04m 02s' (default)
'Ww Dd H:M:02:S:02' --> '4w 5d 8:04:02'
'D:2d H:2:M:02:S:02' --> ' 5d 8:04:02'
'Hh Ss' --> '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, 'Dd H:M:02:S:02')
2d 3:05:08
>>> print strfdelta(td, 'D:2d H:2:M:02:S:02')
2d 3:05:08
>>> print strfdelta(td, 'Hh Ss')
51h 308s
>>> print strfdelta(12304, inputtype='s')
00d 03h 25m 04s
>>> print strfdelta(620, 'H:M:02', 'm')
10:20
>>> print strfdelta(49, 'Dd Hh', 'h')
2d 1h
【讨论】:
非常好,干净的代码!我想知道如何扩展此代码以处理格式化程序中的最后一个小数余数秒... @kfmfe04 我修改了这个解决方案以包含秒的分数***.com/a/63198084/11998874【参考方案19】:如果您已经有一个 timedelta obj,那么只需将该 obj 转换为字符串。删除字符串的最后 3 个字符并打印。这将截断秒部分并以 Hours:Minutes 格式打印其余部分。
t = str(timedeltaobj)
print t[:-3]
【讨论】:
-3 不行,最好用print t.split('.')[0]
【参考方案20】:
import datetime
hours = datetime.timedelta(hours=16, minutes=30)
print((datetime.datetime(1,1,1) + hours).strftime('%H:%M'))
【讨论】:
在 3.7 中我得到 AttributeError: 'datetime.timedelta' object has no attribute 'strftime' 现在试试hours = datetime.timedelta(hours=25, minutes=30)
【参考方案21】:
我使用了humanfriendly
python 库来做这个,效果很好。
import humanfriendly
from datetime import timedelta
delta = timedelta(seconds = 321)
humanfriendly.format_timespan(delta)
'5 minutes and 21 seconds'
可通过https://pypi.org/project/humanfriendly/获得
【讨论】:
【参考方案22】:针对此问题的直接模板过滤器。内置函数 int() 从不四舍五入。 F-Strings(即 f'')需要 python 3.6。
@app_template_filter()
def diffTime(end, start):
diff = (end - start).total_seconds()
d = int(diff / 86400)
h = int((diff - (d * 86400)) / 3600)
m = int((diff - (d * 86400 + h * 3600)) / 60)
s = int((diff - (d * 86400 + h * 3600 + m *60)))
if d > 0:
fdiff = f'dd hh mm ss'
elif h > 0:
fdiff = f'hh mm ss'
elif m > 0:
fdiff = f'mm ss'
else:
fdiff = f'ss'
return fdiff
【讨论】:
【参考方案23】:一个班轮。由于 timedeltas 不提供 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 的烦恼,这导致我遇到了这个问题,以及我分享的解决方案。
【讨论】:
【参考方案24】:如果你的包中碰巧有IPython
(你应该),它(到目前为止,无论如何)有一个非常好的持续时间格式化程序(以浮点秒为单位)。这在各个地方都有使用,例如 %%time
细胞魔术。我喜欢它在短时间内产生的格式:
>>> 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
【讨论】:
【参考方案25】:这是一个字符串化 timedelta.total_seconds() 的函数。它适用于 python 2 和 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'
)
示例输出:
>>> 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
【讨论】:
【参考方案26】:我有一个函数:
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'
【讨论】:
非常好!最佳答案!。我会稍微修改以包含微秒d['f'] = delta.microseconds
,然后使用print(period(td,"d days h:m:s.f"))
【参考方案27】:
我从MarredCheese's answer继续添加year
、month
、millicesond
和microsecond
除second
外,所有数字都被格式化为整数,即can be customized 秒的小数部分。
@kfmfe04 要求不到一秒钟,所以我发布了这个解决方案
main
中有一些例子。
from string import Formatter
from datetime import timedelta
def strfdelta(tdelta, fmt='D:02d H:02h M:02m S:02.0fs', 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:02d H:02h M:02m S:02.0fs' --> '05d 08h 04m 02s' (default)
'Ww Dd H:M:02:S:02.0f' --> '4w 5d 8:04:02'
'D:2d H:2:M:02:S:02.0f' --> ' 5d 8:04:02'
'Hh S:.0fs' --> '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
【讨论】:
谢谢!但是您的浮点格式对于秒 S:07.4f。【参考方案28】: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'
【讨论】:
【参考方案29】:也许:
>>> import datetime
>>> dt0 = datetime.datetime(1,1,1)
>>> td = datetime.timedelta(minutes=34, hours=12, seconds=56)
>>> (dt0+td).strftime('%X')
'12:34:56'
>>> (dt0+td).strftime('%M:%S')
'34:56'
>>> (dt0+td).strftime('%H:%M')
'12:34'
>>>
【讨论】:
【参考方案30】:我建议以下方法,以便我们可以使用标准格式化功能,pandas.Timestamp.strftime
!
from pandas import Timestamp, Timedelta
(Timedelta("2 hours 30 min") + Timestamp("00:00:00")).strftime("%H:%M")
【讨论】:
以上是关于将 timedelta 格式化为字符串的主要内容,如果未能解决你的问题,请参考以下文章