Python实现ParseDuration-支持解析字符串格式的时间单位,例如将小时或者分钟数转换为秒

python的time模块不支持单独将字符串格式的分钟数和小时数转换为秒,比如将“5m”转换为“300”(秒),不支持将“0.2h5.1m12.123s”转换为“1038.123”(秒)。

但是这种字符串格式的分钟数或者小时数写法,在一些配置或者用户交互中还是比较有用的。

为了实现这种功能,通过模拟golang的`time`模块中的`ParseDuration(s string) (duration, error)`函数,使用Python代码实现如下:

#-*- coding:utf-8 -*-
import sys
import logging reload(sys) # reload 才能调用 setdefaultencoding 方法
sys.setdefaultencoding('utf-8') # 设置 'utf-8' from cfg import config class TimeTool(object):
def __init__(self):
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
self.logger = logging.getLogger("HistoryReader")
self.logger.addHandler(handler)
self.logger.setLevel(config.LOG_LEVEL)
self.Nanosecond = 1
self.Microsecond = 1000 * self.Nanosecond
self.Millisecond = 1000 * self.Microsecond
self.Second = 1000 * self.Millisecond
self.Minute = 60 * self.Second
self.Hour = 60 * self.Minute
self.unitMap = {
"ns": int(self.Nanosecond),
"us": int(self.Microsecond),
"µs": int(self.Microsecond), # U+00B5 = micro symbol
"μs": int(self.Microsecond), # U+03BC = Greek letter mu
"ms": int(self.Millisecond),
"s": int(self.Second),
"m": int(self.Minute),
"h": int(self.Hour),
}
pass def leadingInt(self, s):
x, rem, err = int(0), str(""), "time: bad [0-9]*"
i = 0
while i < len(s):
c = s[i]
if c < '0' or c > '9':
break
#print x
if x > (1 << 63-1)/10:
#print "x > (1 << 63-1)/10 => %s > %s" %(x, (1 << 63-1)/10)
return 0, "", err
x = x * 10 + int(c) - int('0')
if x < 0:
#print "x < 0 => %s < 0" %(x)
return 0, "", err
i+=1
return x, s[i:], None def leadingFraction(self, s):
x, scale, rem = int(0), float(1), ""
i, overflow = 0, False
while i < len(s):
c = s[i]
if c < '0' or c > '9':
break
if overflow:
continue
if x > (1<<63-1)/10 :
overflow = True
continue
y = x*10 + int(c) - int('0')
if y < 0:
overflow = True
continue
x = y
scale *= 10
i += 1
return x, scale, s[i:] """
将小时,分钟,转换为秒
比如: 5m 转换为 300秒;5m20s 转换为320秒
time 单位支持:"ns", "us" (or "µs"), "ms", "s", "m", "h"
"""
def ParseDuration(self, s):
if s == "" or len(s) < 1:
return 0 orig = s
neg = False
d = float(0) if s != "":
if s[0] == "-" or s[0] == "+":
neg = s[0] == "-"
s = s[1:] if s == "0" or s == "":
return 0 while s != "":
v, f, scale = int(0), int(0), float(1) print "S: %s" %s
# the next character must be [0-9.]
if not (s[0] == "." or '0' <= s[0] and s[0] <= '9'):
self.logger.error("time1: invalid duration %s, s:%s" % (orig, s))
return 0 # Consume [0-9]*
pl = len(s)
v, s, err = self.leadingInt(s)
if err != None:
self.logger.error("time2, invalid duration %s" %orig)
return 0
pre = pl != len(s) # consume (\.[0-9]*)?
post = False
if s != "" and s[0] == ".":
s = s[1:]
pl = len(s)
f, scale, s = self.leadingFraction(s)
post = pl != len(s)
if not pre and not post:
self.logger.error("time3, invalid duration %s" %orig)
return 0 # Consume unit.
i = 0
while i < len(s):
c = s[i]
if c == '.' or '0' <= c and c <= '9':
break
i+=1
if i == 0:
self.logger.error("time4: unkonw unit in duration: %s" %orig)
return 0
print "s:%s, i:%s, s[:i]:%s" %(s, i, s[:i])
u = s[:i]
s = s[i:]
if not self.unitMap.has_key(u):
self.logger.error("time5: unknow unit %s in duration %s" %(u, orig))
return 0
unit = self.unitMap[u]
if v > (1<<63-1)/unit:
self.logger.error("time6: invalid duration %s" %orig)
return 0
v *= unit
if f > 0 :
v += int(float(f) * (float(unit) / scale))
if v < 0:
self.logger.error("time7: invalid duration %s" %orig)
return 0
d += v
if d < 0 :
self.logger.error("time8: invalid duration %s" %orig)
return 0 if neg :
d = -d
return float(d)

 

使用实例:

#-*- coding:utf-8 -*-
from timeTools import TimeTool if __name__ == "__main__":
tools = TimeTool()
s = tools.ParseDuration("1m20.123s")
print s

默认打印单位是“Nanosecond”,如果想要打印单位为“second”的话,只需要将parse结果除以`TimeTool.Second`即可,例如:

```python

tools = TimeTool()
s = tools.ParseDuration("1m20.123s")
print s/tools.Second

```

上一篇:Androd安全——混淆技术完全解析


下一篇:MVC中ajax调用Controller的方法