利用Python脚本实现固定格式时间差值精确计算(Decimal)

前些天测试程序,需要记录下程序不同模块的各自运行时间。

由于各个模块之间有各自的关联,运行时间会受到数据量大小的影响,所以只能一步一步运行并记录下时间再根据需要进行差值计算。

时间格式如此:  XX(小时):XX(分钟):XX.XXX(秒)  [注:秒精确到千分位]

但个别程序由于数据量过大,运行十分缓慢,需要记录的时间差值也很多,重复过程繁琐。

虽说算差值不是什么难事,都是些简单的数值计算,但是在面对上百个需要测试的程序,我实在是懒得去一个一个算。

正所谓“懒惰为人类进步的阶梯(误)”,因此,我萌生了使用Python编写一个可以进行时间差计算的小程序的想法。(2333...)

一、确定思路

  1.在本程序中,我采用的是统一单位的方法。即先将时间统一为秒,再对其进行减法运算。那么我们只需要将这个过程通过代码复现即可。

  2.在经过差值计算后,我们仍需要将结果重新格式化为原规定格式(XX:XX:XX.XXX)

  3.鉴于需要重复使用,可以考虑加入循环,特定条件退出运算

二、拟定程序结构

  本程序有五大部分:

  (1).计算主函数

  (2).格式化函数

  (3).单位转换函数

  (4).程序主函数

  (5).调用主函数

三、编写程序

  但是,在开始之前,我们需要知晓一件事。

  我们程序在进行差值计算时,会精确到秒的千分位,按理说我们定义浮点数据类型即可。

  然而,在计算机中,采用浮点数进行计算无法达到“精确到xx位小数点”的精度。

  为什么呢?我们实验一下:

  首先定义两个浮点数

  

  然后我们进行加法运算

  

  这里就出了问题,答案并不是我们想要的6.3,而是不知什么鬼的6.300000000000001。

  这里面最重要的原因就是,计算机采用二进制存储数据,使用浮点数并不能很好的表示十进制数据,会有一些"小误差"。

  (这里(包括这两个数4.2 2.1) 借鉴了http://www.hongweipeng.com/index.php/archives/1356/,栖迟大佬)

  那我们如何才能做到十进制精确计算呢?

  答案就是使用Python内置模块decimal,它可以帮助我们把浮点数转化为十进制类型,并且支持所有常用数学运算

  示例:

1 from decimal import Decimal
2 
3 a = Decimal('4.2')
4 b = Decimal('2.1')
5 
6 print(a + b)

  结果:

  

  我们发现,结果不再是鬼畜的6.300000000000001,是正常的6.3。

  而且可以观察到,经过Decimal转化得到的是一个Decimal对象,使用时需要注意,在转化浮点数时,需要其字符串化。

  那么解决了精确运算的问题,我们现在可以进行程序的编写了。

  1.首先是计算主函数:

  我们进行时间差计算,需要两个参数,起始时间和结束时间

  然后将两参数单位统一,得到统一单位后的时间差值,再对其进行格式化以及格式的还原即可

  本程序中计算主程序即是对参数单位进行统一的函数,代码如下:

  (当然在程序开头要声明引入Decimal)

 1 def Time_Cal():                                                    # 定义函数
 2     print("----------------XX:XX:XX----------------")      # 打印分行符
 3     # 程序运行后在这里输入起始时间和结束时间
 4     start_time = input("Enter your Start Time:  ")
 5     stop_time = input("Enter your Stop  Time:  ")
 6     # 使用split方法对输入的字符串以“:”为分隔符进行分割处理,并存为列表
 7     start_list = start_time.split(':')
 8     stop_list = stop_time.split(':')
 9     # 再通过不同单位划分三个部分,分别从列表获取小时、分钟、秒的值
10     start_hour = Decimal(start_list[0])
11     start_minu = Decimal(start_list[1])
12     start_sec = Decimal(start_list[2])
13     stop_hour = Decimal(stop_list[0])
14     stop_minu = Decimal(stop_list[1])
15     stop_sec = Decimal(stop_list[2])
16     # 这里就是对获取到的各个部分的值进行单位统一(基本单位为秒)
17     value_start = start_hour * 3600 + start_minu * 60 + start_sec
18     value_stop = stop_hour * 3600 + stop_minu * 60 + stop_sec
19     return value_stop,value_start
20     # 返回单位统一后的起始时间和结束时间,此时这两个参数均以秒数为单位

  2.格式化函数:

  这里格式化的原因是因为在我们计算结束后,有些位置的值为各位数,因标准格式(XX:XX:XX.XXX)规范,这里直接对缺位处进行补零

  但这里有三点要考虑,即:小时位是否需要补零、分钟位是否需要补零、秒位是否需要补零

  所以我们需要对小时、分钟、秒三部分进行判断:

  

  同样,当时间值只有分钟秒数甚至只有秒数时也要进行类似判断。

  那么在这种情况下,我们则优先对秒数处格式化函数进行定义,这样在后面判断分钟和小时是否需要补零时可以直接调用函数,减少代码量。

  代码:

1 def S_Formatting(len_s,s):
2     # 这里我们先定义对秒处进行格式化函数
3     if len_s < 2:                               # 判断秒数位是否为个位数
4         s_sec = '0' + s                        # 个位则补零 
5     else:
6         s_sec = s                               # 反之则直接向下传递
7     return s_sec                               # 返回秒数位置的最终值

  之后对分钟和小时处判断,直接调用即可:

  对分钟:

1 def M_Formatting(len_m,m,len_s,s):              # 注意这里参数要包含秒数位的值
2     if len_m < 2:
3         s_minu = '0' + m
4         s_sec = S_Formatting(len_s,s)               # 判断秒数位时直接调用即可
5     else:
6         s_minu = m
7         s_sec = S_Formatting(len_s,s)
8     return s_minu,s_sec                                 # 返回分钟和秒数的最终值

 

  对小时:

 1 def H_Formatting(len_h,h,len_m,m,len_s,s):       # 参数同样要包含分钟和秒数值
 2     if len_h < 2:
 3         s_hour = '0' + h
 4         s_minu,s_sec = M_Formatting(len_m,m,len_s,s)   # 调用分钟格式化函数
 5         
 6     else:
 7         s_hour = h
 8         s_minu,s_sec = M_Formatting(len_m,m,len_s,s)
 9   return s_hour,s_minu,s_sec                       # 返回小时、分钟、秒数的最终值

 

  3.单位转换函数:

  单位转换函数是在单位统一后,格式化之前,对传入的起始时间和结束时间进行差值运算后,通过秒数值的大小判断分钟或者秒数位是否需要进位。

  并在转换单位后调用格式化函数并将其组合为规定格式(XX:XX:XX.XXX)返回最终值。

  代码:

 1 def Switch(value_stop,value_start):                 # 这里传入转化为秒的起始时间和结束时间
 2     D_value = Decimal(value_stop - value_start)       # 计算得到时间差,为达到精确计算,调用Decimal方法
 3     # 从这里开始对是否需要进位进行判断
 4     if D_value >= 3600:                    # 这里是小时位需要进位的情况
 5         D_hour = int(D_value)             # 取整,去掉小数点
 6         hour = D_hour // 3600            # 同样取整,做除
 7         D_minu = D_hour - hour * 3600    # 得到包含分钟位的值
 8         minu = D_minu // 60              # 取整,做除
 9         sec = D_value - hour * 3600 - minu * 60     # 用时间差减去得到的小时和分钟就是秒数的值
10 
11         # 调用格式化函数
12         s_hour,s_minu,s_sec = H_Formatting(len(str(hour)),str(hour),len(str(minu)),str(minu),len(str(int(sec))),str(sec))
13         print("The Time Difference is: " + s_hour + ':' + s_minu + ':' + s_sec)         # 组合为规范格式输出
14     elif 60 <= D_value < 3600:         # 这里是分钟位进位的情况,小时值为零
15         minu = D_value // 60
16         sec = D_value - minu * 60
17         s_minu,s_sec = M_Formatting(len(str(minu)),str(minu),len(str(int(sec))),str(sec))
18         print("The Time Difference is: " + '00:' + s_minu + ':' + s_sec)
19     else:                                        # 仅有秒数值的情况
20         sec = D_value
21         s_sec = S_Formatting(len(str(int(sec))),str(sec))
22         print("The Time Difference is: " + '00:' + '00:' + s_sec)

  最后编写主函数调用函数即可。

运行结果:

 1 from decimal import Decimal                    # 调用Decimal模块
 2 
 3 def Time_Cal():
 4     print("----------------XX:XX:XX----------------")
 5     start_time = input("Enter your Start Time:  ")
 6     stop_time = input("Enter your Stop  Time:  ")
 7     start_list = start_time.split(':')
 8     stop_list = stop_time.split(':')
 9     start_hour = Decimal(start_list[0])
10     start_minu = Decimal(start_list[1])
11     start_sec = Decimal(start_list[2])
12     stop_hour = Decimal(stop_list[0])
13     stop_minu = Decimal(stop_list[1])
14     stop_sec = Decimal(stop_list[2])
15     value_start = start_hour * 3600 + start_minu * 60 + start_sec
16     value_stop = stop_hour * 3600 + stop_minu * 60 + stop_sec
17     return value_stop,value_start
18 
19 def S_Formatting(len_s,s):
20     if len_s < 2:
21         s_sec = '0' + s
22     else:
23         s_sec = s
24     return s_sec
25 
26 def M_Formatting(len_m,m,len_s,s):
27     if len_m < 2:
28         s_minu = '0' + m
29         s_sec = S_Formatting(len_s,s)
30     else:
31         s_minu = m
32         s_sec = S_Formatting(len_s,s)
33     return s_minu,s_sec
34 
35 def H_Formatting(len_h,h,len_m,m,len_s,s):
36     if len_h < 2:
37         s_hour = '0' + h
38         s_minu,s_sec = M_Formatting(len_m,m,len_s,s)
39     else:
40         s_hour = h
41         s_minu,s_sec = M_Formatting(len_m,m,len_s,s)
42     return s_hour,s_minu,s_sec
43 
44 def Switch(value_stop,value_start):
45     D_value = Decimal(value_stop - value_start)
46     if D_value >= 3600:
47         D_hour = int(D_value)
48         hour = D_hour // 3600
49         D_minu = D_hour - hour * 3600
50         minu = D_minu // 60
51         sec = D_value - hour * 3600 - minu * 60
52 
53         s_hour,s_minu,s_sec = H_Formatting(len(str(hour)),str(hour),len(str(minu)),str(minu),len(str(int(sec))),str(sec))
54         print("The Time Difference is: " + s_hour + ':' + s_minu + ':' + s_sec)
55     elif 60 <= D_value < 3600:
56         minu = D_value // 60
57         sec = D_value - minu * 60
58         s_minu,s_sec = M_Formatting(len(str(minu)),str(minu),len(str(int(sec))),str(sec))
59         print("The Time Difference is: " + '00:' + s_minu + ':' + s_sec)
60     else:
61         sec = D_value
62         s_sec = S_Formatting(len(str(int(sec))),str(sec))
63         print("The Time Difference is: " + '00:' + '00:' + s_sec)
64 
65 def main():                                                # 定义主函数
66     running = True
67     print("Hello ~~ !")
68     while running:                                         # 通过循环方便输入和计算
69         value_stop,value_start = Time_Cal()      # 调用计算主函数
70         Switch(value_stop,value_start)               # 调用单位转换函数
71         action = input("Go on ? Y/N:")
72         if action == 'Y' or action == 'y':
73             running = True
74         elif action == 'N' or action == 'n':
75             running = False
76             print("Goodbye~~")
77 
78 if __name__ == '__main__':                          # 调用主函数
79     main()
查看完整代码

 

posted @ 2018-09-12 15:42  Seikito  阅读(1382)  评论(0编辑  收藏  举报