我在格式化datetime.timedelta对象时遇到问题。

这是我要尝试的操作:
我有一个对象列表,并且该对象的类成员之一是显示事件持续时间的timedelta对象。我想以小时:分钟的格式显示该持续时间。

我尝试了多种方法来执行此操作,但遇到了困难。我当前的方法是为类添加返回小时和分钟的对象的方法。我可以通过将timedelta.seconds除以3600并四舍五入来获得小时数。我在获取剩余秒数并将其转换为分钟时遇到了麻烦。

我正在使用带有Django模板的Google AppEngine进行演示。

评论

如果timedelta具有与strftime()方法等效的方法,那就更好了。

@JS。好吧,如果您使用datetime.utcfromtimestamp(),则可以。请参阅下面的答案。

@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中实现。在此文件的末尾,从_datetime导入将使用已编译的python实现替换纯python实现。但是,如果您对导入进行注释,则该模块将起作用,并且可以直接在该文件中或通过猴子补丁添加datetime.timedelta .__ format__方法。

好问题!

#1 楼

您可以使用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


评论


更像以timedelta作为参数调用str()方法。

– joeforker
09年2月12日在18:23

您在那里不需要str调用,它将通过打印自动完成。

– Zitrax
14年2月14日在7:49

@Zitrax,但是如果要将增量与另一个字符串连接起来,则很有必要。例如打印'some something'+ str(delta)

– Plinio.Santos
2015年2月6日下午13:33

当数据类型定义为“ datetime.timedelta”并且您像ConvertConration = datetime.timedelta(milliseconds = int(254459))这样使用数据类型时,这是必要的,然后您只需使用split即可使微秒失效。从0:03:43.765000,我可以通过简单地运行TotalDuration = str(ConvertDuration).split('。',2)[0]来获得0:03:43

– DarkXDroid
2015年2月8日在11:51



这可能会将增量打印为字符串,但不会按照OP要求将其格式化。

–丹妮德
15年2月18日在22:16

#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
 


评论


对于负时间差,您应该先评估符号,然后再进行绝对值运算。

– mbarkhau
2011年5月4日晚上10:45

请注意,您实际上可能希望使用'%d:%02d:%02d'在输出字符串中使用前导零。

–ShinNoNoir
2014年3月20日在12:35

对于python 2.7及更高版本,请使用.total_seconds()方法

–sk8asd123
2014年4月22日在21:46

如果差异可能为负或超过24小时(.seconds属性忽略.days),则不要使用.seconds。请改用.total_seconds()或其类似物。

– jfs
2015年1月30日20:33



为了实现积极的差异,我会不时重新实现此功能。感谢您这次必须进行搜索:)

–狼
18年4月25日在10:12

#3 楼

>>> 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获得时间增量。我不知道时间。另外,您的示例似乎包含几秒钟,如何删除?

– mawcs
09年2月11日在20:46

不管在哪里获取timedelta对象,它都会设置相同的格式。

– joeforker
09年2月11日在20:48

如果超过一天,它将格式化为例如拆分/合并处理后的“ 4天8:00”。

– joeforker
09年2月11日在20:52

str(my_timedelta)不能很好地处理负数

–卡特斯克尔
2014年5月17日23:14

超过24小时时也会显示天数,例如'4天,18:48:22.330000'。这里建议的许多方法都不是。

– Alexei Martianov
18年5月17日在12:53

#4 楼

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)


评论


真的很好,我建议将“秒> period_seconds:”更改为“秒> = period_seconds:”。

– CBenni
15年6月19日在19:04

这会为空的timedelta返回空字符串,不确定是否要这样做吗?

–德克
17年8月22日在10:34

我尝试了5473天,然后得到:“ 14年12个月3天”。为什么不选择“ 15年零3天”呢?此外,根据Google的说法,5473是“ 14.99452日历年”,“ 0.99451999988374日历年是11.93422692000003593个月”,而“ 0.93422692000003593193个月是28.416099957565091216天。 28天”?

–布鲁诺·安布罗齐奥(Bruno Ambrozio)
12月15日23:50

#5 楼

我个人将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的启发contrib.humanize模块,显然,因此,由于您使用的是Django,因此您可能应该使用它。

评论


不错,+ 1虽然:humanize.naturaldelta(pd.Timedelta('-10sec'))-> '10 seconds':S ...

–ntg
16 Dec 13'在10:49

好吧,这是10秒的变化量。 :)如果您想要时间,自然就是您要使用的时间。

–anarcat
16年12月14日在19:58

#6 楼

他已经有一个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)


无论时间增量是偶数天还是数年,这都有效。

#7 楼

这是一个通用函数,用于将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


评论


非常好,干净的代码!我想知道如何扩展此代码以处理格式化程序中的最后小数秒...

–kfmfe04
2月22日7:06

@ kfmfe04我修改了此解决方案,以包含第二个stackoverflow.com/a/63198084/11998874的一部分

–番茄移位
7月31日19:34

#8 楼

我知道这是一个古老的已回答问题,但是我为此使用了datetime.utcfromtimestamp()。它花费秒数并返回一个datetime,该datetime可以像其他任何q4312079q一样进行格式化。应该可以工作,即小时数<= 23时,它不会返回1234:35。

评论


您应该改用print timedelta(seconds = end-begin)。

– jfs
15年1月30日在20:37

@ J.F.Sebastian然后,您必须用前导零手动填充小时。

– sjngm
15年1月30日在20:45

我对问题的填充一无所知。如果需要,请使用.zfill(8)。

– jfs
15年1月30日在21:34

需要.total_seconds()调用:>>> datetime.utcfromtimestamp((t2-t1).total_seconds())。strftime(“%H:%M:%S”)<<< >>> '00:00: 05'

–香槟色
17年3月3日,0:45



我非常喜欢这种解决方案,它可以让您控制格式。请注意,您也可以像这样直接使用str格式程序:“ {0:%H}:{0:%M}”。format(duration)

–脚趾
17年7月26日在15:26



#9 楼

发问者想要一种比典型格式更好的格式:

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


#10 楼

我会在这里认真考虑Occam的Razor方法:

td = str(timedelta).split('.')[0]


如果要重新生成日期时间,它将返回不带微秒的字符串

。 timedelta对象,只需执行以下操作:

h,m,s = re.split(':', td)
new_delta = datetime.timedelta(hours=int(h),minutes=int(m),seconds=int(s))


2年了,我喜欢这种语言!

评论


这不包括几天

–瓦施拜尔
16-2-20在17:29

#11 楼

我的datetime.timedelta对象超过一天。因此,这是另一个问题。以上所有讨论都假设不到一天。 timedelta实际上是由天,秒和微秒组成的元组。上面的讨论应该像joe一样使用td.seconds,但是如果您有工作日,则它不包括在秒值中。

我得到了2个日期时间与打印日期和时间之间的时间跨度。

span = currentdt - previousdt
print '%d,%d\n' % (span.days,span.seconds/3600)


评论


这是面向未来的解决方案。

–吉宾
2012年8月22日在12:17

#12 楼

我使用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/
获得

#13 楼

按照上面Joe的示例值,我将使用模算术运算符,从而:如果要更明确,请适当使用math.floor()或math.ceil()。

评论


timedelta已经知道如何格式化自己,就像在'print some_timedelta'中一样。

– joeforker
09年2月11日在20:57

是的,但是它不能接受任意格式的字符串,这是Michael要求的。尽管现在我考虑到它,但3600除法器进行了以小时为单位的假设,这在leap秒时会引起问题。

–UltraNurd
09年2月11日在21:01

是的,但是他不想使用任意格式的字符串,他几乎想要默认的行为。

– joeforker
09年2月11日在21:07

不要忘记//在Python 3000中截断

– joeforker
09年2月12日在18:22

+1,但为什么不编辑答案以使用//?我还建议使用td.total_seconds()而不是.seconds使其在间隔> 1天时起作用。

– Antony Hatchkins
14年8月14日在13:03



#14 楼

直接解决此问题的模板过滤器。内置函数int()从不舍入。 F字符串(即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'{d}d {h}h {m}m {s}s'
    elif h > 0:
        fdiff = f'{h}h {m}m {s}s'
    elif m > 0:
        fdiff = f'{m}m {s}s'
    else:
        fdiff = f'{s}s'
    return fdiff


#15 楼

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


评论


你写这个吗?您测试了多少?

–托马斯·阿勒
2013年12月4日12:30

我在名为datahaven.net的项目中使用此代码。它工作正常。有没有看到错误?

– Veselin Penev
2013年12月12日16:07

如果您可以提供一些信息,并且提供如此繁重的代码,那总是很高兴的:)像一个例子,说明它如何工作,可能的优点和缺点。

–托马斯·阿勒
2013年12月12日下午16:13

哦。当然!。为您添加了一个示例。 :-)

– Veselin Penev
2013年12月22日下午16:26

超级:)还要注意,文档中的timedelta对象具有天,秒和微秒字段。

–托马斯·阿勒
14年4月16日在9:23

#16 楼

我在工作中加班计算的输出有类似的问题。该值应始终以HH:MM显示,即使该值大于一天并且该值可能会变为负数。我合并了一些所示的解决方案,也许其他人认为此解决方案很有用。我意识到,如果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'


#17 楼

import datetime
hours = datetime.timedelta(hours=16, minutes=30)
print((datetime.datetime(1,1,1) + hours).strftime('%H:%M'))


评论


在3.7中,我得到AttributeError:'datetime.timedelta'对象没有属性'strftime'

– Qubodup
19 Mar 14 '13:00



现在尝试使用hours = datetime.timedelta(hours = 25,minutes = 30)

– gss
8月27日20:41

#18 楼

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'


评论


我认为,就长度和涵盖范围而言,最好的一个

– Dici
19/12/22在12:54

#19 楼

一支班轮。由于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


这也解决了将timedelta格式化为H:MM:SS而不是HH:MM:SS的麻烦,这导致了我这个问题我分享的解决方案。

#20 楼

请检查此功能-它会将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)


#21 楼

如果您的软件包中恰巧有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


#22 楼

这是一个将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


#23 楼

我有一个函数:
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'


#24 楼

我从MarredCheese的答案继续,并添加了yearmonthmillicesondmicrosecond
second之外,所有数字都被格式化为整数,因此可以自定义秒的分数。
@ kfmfe04要求一秒所以我发布了这个解决方案
main中有一​​些示例。
 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


#25 楼

timedelta到字符串,用于打印运行时间信息。
def strf_runningtime(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'


#26 楼

也许:
>>> 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'
>>>


#27 楼

我建议采用以下方法,以便我们可以利用标准格式功能pandas.Timestamp.strftime
from pandas import Timestamp, Timedelta

(Timedelta("2 hours 30 min") + Timestamp("00:00:00")).strftime("%H:%M")


#28 楼

如果您已经有一个timedelta obj,则只需将该obj转换为字符串即可。删除字符串的最后3个字符并打印。这将截断秒部分,并以小时:分钟的格式打印其余部分。

t = str(timedeltaobj) 

print t[:-3]


评论


-3不起作用,最好使用print t.split('。')[0]

– EvgenyKolyakov
3月5日21:46



#29 楼

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'


#30 楼

感谢大家的帮助。我采纳了您的许多想法并将它们放在一起,让我知道您的想法。

我在类中添加了两个方法,如下所示:

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中,我使用了它(总和是对象,它在字典中):

<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]) {{sum.1.hhmm}}

– joeforker
09年2月12日在13:57

只需使用docs.python.org/release/2.5.2/lib/datetime-timedelta.html上的“两个日期的区别”示例中所示的divmod()即可。

–汤姆
2010年11月17日在16:01