Python格式的timedeltastring
我是一个Python的新手(2周),我有格式化datetime.timedelta
对象的麻烦。
以下是我正在做的事情:我有一个对象列表,而对象类的其中一个成员是timedelta对象,它显示事件的持续时间。 我想以小时:分钟的格式显示那段时间。
我已经尝试了多种方法来做到这一点,我有困难。 我目前的做法是给我的对象添加方法,返回小时和分钟。 我可以通过将timedelta.seconds除以3600并四舍五入来得到小时数。 我得到剩余的秒数,并将其转换为分钟的麻烦。
顺便说一句,我使用Google AppEngine
和Django Templates
进行演示。
如果有人能够帮助或者知道更好的解决方法,我会很高兴的。
谢谢,
你可以用str()把timedelta转换成一个string。 这是一个例子:
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
如您所知,您可以通过访问.seconds
属性来获取timedelta对象的.seconds
。
您可以通过使用模和减的组合将其转换为小时和余数:
# 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 '%s:%s:%s' % (hours, minutes, seconds) # result: 3:43:40
不过,python提供了内build函数divmod(),它允许我们简化这个代码:
s = 13420 hours, remainder = divmod(s, 3600) minutes, seconds = divmod(remainder, 60) print '%s:%s:%s' % (hours, minutes, seconds) # result: 3:43:40
希望这可以帮助!
>>> 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()
函数会调用与inputprint td
相同的格式代码。 既然你不想要秒,我们可以用冒号(3部分)将string拆分,并且只把前两部分放在一起。
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) if period_value == 1: strings.append("%s %s" % (period_value, period_name)) else: strings.append("%s %ss" % (period_value, period_name)) return ", ".join(strings)
他已经有一个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)
无论时间增量是几天还是几年,这都是有效的。
我的datetime.timedelta
对象超过了一天。 所以这是另一个问题。 以上所有讨论都假定不到一天。 timedelta
实际上是一个天,秒和微秒的元组。 上面的讨论应该使用td.seconds
作为乔做的,但如果你有天,它不包括在秒值。
我在两个date时间和打印date和时间之间的时间跨度。
span = currentdt - previousdt print '%d,%d\n' % (span.days,span.seconds/3600)
提问者想要比典型的更好的格式:
>>> 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
我确实想过要在这方面增加几年的时间,但这只是读者的一个练习,因为输出在一年之内是安全的:
>>> str(datetime.timedelta(seconds=99999999)) '1157 days, 9:46:39'
我知道这是一个老回答的问题,但我使用datetime.utcfromtimestamp()
为此。 它需要秒数并返回一个datetime
,可以像任何其他datetime
时间格式化。
duration = datetime.utcfromtimestamp(end - begin) print duration.strftime('%H:%M')
只要你留在这个时间的合法范围内,即它不返回1234:35,因为小时<= 23。
我个人使用这个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)
,但我发现,一旦超过了几个小时,显示变得很快难以理解。支持大得多的人类可读的值,也是很好的本地化的。
它的启发来自于Django的contrib.humanize
模块,显然,因为你使用的是Django,所以你应该使用它。
遵循上面的Joe的示例值,我将使用模运算符,因此:
td = datetime.timedelta(hours=10.56) td_str = "%d:%d" % (td.seconds/3600, td.seconds%3600/60)
请注意,Python中的整数除法默认为舍入; 如果你想更明确的话,可以使用math.floor()或math.ceil()。
这是一个通用函数,用于将timedelta
对象或常规数字(以秒或分钟等forms)转换为格式良好的string。 我在一个重复的问题上采取了mpounsett的梦幻般的答案 ,使它更加灵活,改进了可读性,并增加了文档。
你会发现这是迄今为止最灵活的答案,因为它允许你:
- 自定义string格式,而不是硬编码。
- 留出一定的时间间隔没有问题(见下面的例子)。
function:
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
我会认真考虑Occam的Razor方法:
td = str(timedelta).split('.')[0]
这将返回一个没有微秒的string
如果你想重新生成datetime.timedelta对象,只需要这样做:
h,m,s = re.split(':', td) new_delta = datetime.timedelta(hours=int(h),minutes=int(m),seconds=int(s))
2年了,我喜欢这种语言!
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 rs = 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
我在工作中加class计算的结果也有类似的问题。 该值应始终显示在HH:MM中,即使该值大于一天,该值也可能变为负值。 我结合了一些显示的解决scheme,也许别人觉得这个解决scheme有用。 我意识到,如果timedelta值是负值,那么使用divmod方法显示的大多数解决scheme并不适用:
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:MMstring:
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'
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'
请检查此函数 – 它将timedelta对象转换为string“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)
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'
感谢大家的帮助。 我把你的许多想法放在一起,让我知道你的想法。
我给这个类添加了两个方法:
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>