格式化timedelta对象

66 投票
7 回答
130796 浏览
提问于 2025-04-17 10:30

我有两个 datetime 对象。我需要计算它们之间的 timedelta,然后以特定的格式显示结果。

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

比如这个 Turnaround_TimeObj 的时间差是 "2 days, 22:13:45"。我想把输出格式化一下,但我不知道怎么做。

print Turnaround_TimeObj.strftime('%H hrs %M mins %S secs')

这个方法不行。

我知道一种方法是把它转换成秒,然后用除法和取余的方法来得到想要的格式。

就像这样:

totalSeconds = Turnaround_TimeObj.seconds
hours, remainder = divmod(totalSeconds, 3600)
minutes, seconds = divmod(remainder, 60)
print '%s:%s:%s' % (hours, minutes, seconds)

但是我在想,能不能用像 strftime 这样的日期时间函数在一行代码里完成这个操作。

其实,把它转换成秒也不行。如果我用下面的方式把时间差 "1 day, 3:42:54" 转换成秒:

totalSeconds = Turnaround_TimeObj.seconds

那么 totalSeconds 的值显示为 13374,而不是 99774。也就是说,它忽略了 "day" 的值。

7 个回答

23

在Python 2.7或更新的版本中,你可以使用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))

这样会得到

27 hrs 42 mins 54 secs

在Python 2.6或更早的版本中,你需要自己计算total_seconds

total_seconds = turnaround.seconds + turnaround.days*24*60*60

(如果你想要更通用的公式,包括微秒,可以查看上面的链接)。

32

这是对Shawn Chin回答的一个小改动,同时也解决了mpouncett提出的一个后续问题。这个改动的主要目的是在小时、分钟和秒前面加上零,这样可以确保这三个部分都是两位数(这和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)

下面是一些示例值的测试:

from datetime import timedelta
for seconds in [0, 1, 59, 60, 61, 3599, 3600, 3601]:
    print strfdelta(timedelta(0, seconds), '%H:%M:%S')

这是输出结果:

00:00:00
00:00:01
00:00:59
00:01:00
00:01:01
00:59:59
01:00:00
01:00:01
97

我在想,能不能用像 strftime 这样的日期时间函数,把它写成一行代码。

根据我的了解,timedelta 里没有直接的方法可以做到这一点。如果你经常需要这样做,可以自己写一个函数,比如:

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)

用法:

>>> 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

如果你想用一种更接近 strftime 的字符串格式,我们可以使用 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)

用法:

>>> 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

这里的 totalSeconds 值显示为 13374,而不是 99774。也就是说,它忽略了“天”的值。

在上面的例子中,你可以用 timedelta.days 来获取“天”的值。

另外,从 Python 2.7 开始,timedelta 有一个 total_seconds() 方法,可以返回这个时间段内的总秒数。

撰写回答