我在格式化日期时间时遇到了麻烦。timedelta对象。
这就是我想做的: 我有一个对象列表,对象类的成员之一是显示事件持续时间的timedelta对象。我想以小时:分钟的格式显示这个持续时间。
我尝试了各种方法来做这件事,但我有困难。我目前的方法是为返回小时和分钟的对象在类中添加方法。我可以通过除以time得到小时数。秒乘以3600,四舍五入。我在得到剩余的秒并将其转换为分钟时遇到了麻烦。
顺便说一下,我使用谷歌AppEngine和Django模板来表示。
我在格式化日期时间时遇到了麻烦。timedelta对象。
这就是我想做的: 我有一个对象列表,对象类的成员之一是显示事件持续时间的timedelta对象。我想以小时:分钟的格式显示这个持续时间。
我尝试了各种方法来做这件事,但我有困难。我目前的方法是为返回小时和分钟的对象在类中添加方法。我可以通过除以time得到小时数。秒乘以3600,四舍五入。我在得到剩余的秒并将其转换为分钟时遇到了麻烦。
顺便说一下,我使用谷歌AppEngine和Django模板来表示。
当前回答
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'
其他回答
提问者想要一个比典型的更好的格式:
>>> 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”。但是,秒可能有分数,打印输出中没有前导0,所以列很乱。
如果你喜欢,下面是我的日常工作:
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'
按照上面Joe的示例值,我将使用模算术运算符,因此:
td = datetime.timedelta(hours=10.56)
td_str = "%d:%d" % (td.seconds/3600, td.seconds%3600/60)
注意,Python中的整数除法默认是四舍五入;如果想要更显式,可以适当使用math.floor()或math.ceil()。
在这里,我会认真考虑奥卡姆剃刀方法:
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年了,我爱上了这门语言!
如您所知,您可以通过访问.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
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