内容简述:
- 1、time和datetime模块
- 2、logging模块
PS:如果你想搜索安装某个模块或者发布一个自己的模块可以到移步到:pypi.org/
1、time和datetime时间模块
① 基本操作
代码示例如下:
import time, datetime # 获取当前时间 moment = time.localtime() print("年:%s" % moment[0]) print("月:%s" % moment[1]) print("日:%s" % moment[2]) print("时:%s" % moment[3]) print("分:%s" % moment[4]) print("秒:%s" % (moment[5] + 1)) print("周几:%s" % (moment[6] + 1)) print("一年第几天:%s" % moment[7]) print("是否为夏令时:%s" % moment[8], end="\n\n") # 格式化时间(这里要注意strftime和strptime是不一样的!!!) moment1 = time.strftime('%Y-%m-%d %H:%M:%S') moment2 = time.strftime('%a %b %d %H:%M:%S %Y', time.localtime()) moment3 = time.mktime(time.strptime(moment2, '%a %b %d %H:%M:%S %Y')) print(moment1) print(moment2) print(moment3, end="\n\n") # 获得当前时间戳 print(time.time()) # 秒级 print(int(round(time.time() * 1000)), end="\n\n") # 毫秒级 # 获得当前时间(时间数组,还需strftime格式化下) print(datetime.datetime.now(), end="\n\n") # 时间戳转换为时间 # 方法一: moment4 = 1512184082 moment5 = time.localtime(moment4) # 转换成时间数组 print(time.strftime('%Y-%m-%d %H:%M:%S', moment5), end="\n\n") # 格式化 # 方法二: moment6 = datetime.datetime.utcfromtimestamp(moment4) print(moment6) moment7 = moment6.strftime('%a %b %d %H:%M:%S %Y') print(moment7, end="\n\n") # 代码延迟执行 time.sleep(5) 复制代码
运行结果如下:
年:2019 月:3 日:14 时:11 分:41 秒:57 周几:4 一年第几天:73 是否为夏令时:0 2019-03-14 11:41:56 Thu Mar 14 11:41:56 2019 1552534916.0 1552534916.3338902 1552534916334 2019-03-14 11:41:56.333890 2017-12-02 11:08:02 2017-12-02 03:08:02 Sat Dec 02 03:08:02 2017 复制代码
② struct_time,字符串,时间戳之间的转换关系
③ Python中的时间日期格式化符号
如下表所示,参考时间为(20190314 13:53:41)
符号 | 描述 | 示例 |
---|---|---|
%y | 两位数的年份表示(00-99) | 19 |
%Y | 四位数的年份表示(000-9999) | 2019 |
%m | 月份(01-12) | 03 |
%d | 月内中的一天(0-31) | 14 |
%H | 24小时制小时数(0-23) | 13 |
%I | 12小时制小时数(01-12) | 01 |
%M | 分钟数(00=59) | 53 |
%S | 秒(00-59) | 41 |
%a | 星期几的英文简写 | Thu |
%A | 星期几的英文 | Thursday |
%b | 月份的英文简写 | Mar |
%B | 月份的英文 | March |
%x | 日期 | 03/14/19 |
%X | 时间 | 13:59:04 |
%c | 日期和时间 | Thu Mar 14 13:54:56 2019 |
%j | 一年中第几天 | 073 |
%p | 以AM和PM的方式显示上午还是下午 | PM |
%U | 一年中的第几周,周天为一周的第一天 | 10 |
%W | 一年中的第几周,周一为一周的第一天 | 10 |
%w | 一周中的第几天,周天为0,周一为1 | 4 |
%z,%Z | 当前时区的名称 | |
%% | %号自身 | % |
④ 一些实用的代码片段
下面提供一些很实用的代码片段,用到的时候复制粘贴即可:
import datetime import time now = datetime.datetime.now() # 获得当前时间的前/后几天,几小时,几秒,毫秒 # 如果是想获得时间戳可以直接调用int(time.mktime(求出来的时间.timetuple())) def fetch_before_time(time_type, value, strf="%Y-%m-%d %H:%M:%S"): if time_type == 'days': if value > 0: return (datetime.datetime.now() + datetime.timedelta(days=value)).strftime(strf) else: return (datetime.datetime.now() - datetime.timedelta(days=value)).strftime(strf) elif time_type == 'hours': if value > 0: return (datetime.datetime.now() + datetime.timedelta(hours=value)).strftime(strf) else: return (datetime.datetime.now() - datetime.timedelta(hours=value)).strftime(strf) elif time_type == 'seconds': if value > 0: return (datetime.datetime.now() + datetime.timedelta(seconds=value)).strftime(strf) else: return (datetime.datetime.now() - datetime.timedelta(seconds=value)).strftime(strf) elif time_type == 'microseconds': if value > 0: return (datetime.datetime.now() + datetime.timedelta(microseconds=value)).strftime(strf) else: return (datetime.datetime.now() - datetime.timedelta(microseconds=value)).strftime(strf) # 获得第二天凌晨的时间戳 def fetch_morning_timestamp(): return int(time.time()) + (144000 - (int(time.time())) % 86400) # 构造一个由起始事件到结束时间间所有的日期列表 def init_date_list(begin_date, end_date): date_list = [] begin_date = datetime.datetime.strptime(str(begin_date), "%Y%m%d") end_date = datetime.datetime.strptime(str(end_date), "%Y%m%d") while begin_date <= end_date: date_str = begin_date.strftime("%Y%m%d") date_list.append(date_str) begin_date += datetime.timedelta(days=1) return date_list if __name__ == '__main__': print("当前时间:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) print(fetch_before_time('days', 3)) print(fetch_before_time('hours', -3)) print(fetch_before_time('seconds', 3)) print("第二天早上的时间戳:", fetch_morning_timestamp()) print("从20190101到20190301的日期列表:%s" % init_date_list(20190101, 20190301)) 复制代码
运行结果如下:
当前时间: 2019-03-14 15:44:58 2019-03-17 15:44:58 2019-03-14 18:44:58 2019-03-14 15:45:01 第二天早上的时间戳: 1552665600 从20190101到20190301的日期列表:['20190101', '20190102',...过长省略... '20190226', '20190227', '20190228', '20190301'] 复制代码
2、logging日志模块
大部分的程序都会有「 记录运行日志的需求 」,而日志信息一般有这样几类: 正常的程序运行日志 , 调试 , 错误或警告信息的输出等 。而日常开发中我们需要把 日志持久化 到本地,进行一些观察和统计,错误排查等,如果只用print函数输出的话,显然有点捉襟见寸。在Python内置了一个日志模块: logging ,它 提供了标准的日志接口,支持日志分级和存储 。
① 日志分级
在开始正式学习 logging 前,我们先了解下「日志分级」,即: 什么时候用什么等级的日志 。如下表所示:
级别 | 建议什么时候使用 |
---|---|
DEBUG | 详细的信息,常用于问题诊断 |
INFO | 记录关键节点信息,用于确认程序是否按照预期运行 |
WARNING | 程序还是正常运行,但某些不期望的事情发生时记录的信息(如磁盘可用空间较低) |
ERROR | 由于更严重的问题导致某些功能不能正常运行时记录的信息 |
CRITICAL | 发生严重错误,导致程序不能继续运行时记录的信息 |
打印各种级别的代码示例如下:
import logging if __name__ == '__main__': # 获得一个Logger logger = logging.getLogger("Test") # logging提供的简单的配置方法,自行配置的话需要手动添加handler logging.basicConfig() # 设置输出的log级别(大于或等于此级别的才会输出),默认级别Warning logger.setLevel(logging.INFO) logger.debug("=== Debug 级别的信息 ===") # 不会输出 logger.info("=== Info 级别的信息 ===") logger.warning("=== Warning 级别的信息 ===") logger.error("=== Error 级别的信息 ===") logger.critical("=== Critical 级别的信息 ===") 复制代码
运行结果如下:
INFO:Test:=== Info 级别的信息 === WARNING:Test:=== Warning 级别的信息 === ERROR:Test:=== Error 级别的信息 === CRITICAL:Test:=== Critical 级别的信息 === 复制代码
② 将日志写入到文件
日志默认是输出到Console(屏幕)上,如果我们想把详细的日志输出到log文件里,则需要用到 handler
了,理论上可以把日志输出到 各种流中 , stderr 、 文件 、 socket 等都可以,在logging中已经将各种流handler封装好了,你也可以 继承StreamHandler类自己做一些定制 ,简单的把日志写入到文件中的代码示例如下:
import logging if __name__ == '__main__': logger = logging.getLogger("Test") logger.setLevel(logging.INFO) # 输出到控制台 logger.addHandler(logging.StreamHandler()) # 输出到文件 logger.addHandler(logging.FileHandler('test.log', encoding='UTF-8')) logger.debug("=== Debug 级别的信息 ===") logger.info("=== Info 级别的信息 ===") logger.warning("=== Warning 级别的信息 ===") logger.error("=== Error 级别的信息 ===") logger.critical("=== Critical 级别的信息 ===") 复制代码
运行结果如下(同时在目录下生成了一个test.log的文件):
=== Info 级别的信息 === === Warning 级别的信息 === === Error 级别的信息 === === Critical 级别的信息 === 复制代码
嗯,你可能有这样的需求,Console打印Warning以上的日志,而log文件保存Debug级别以上的日志,那么可以修改下上面的代码,修改后的代码如下:
if __name__ == '__main__': logger = logging.getLogger("Test") logger.setLevel(logging.INFO) # 输出到控制台 s_handler = logging.StreamHandler() s_handler.setLevel(logging.WARNING) logger.addHandler(s_handler) # 输出到文件 f_handler = logging.FileHandler('test.log', encoding='UTF-8') f_handler.setLevel(logging.DEBUG) logger.addHandler(f_handler) logger.debug("=== Debug 级别的信息 ===") logger.info("=== Info 级别的信息 ===") logger.warning("=== Warning 级别的信息 ===") logger.error("=== Error 级别的信息 ===") logger.critical("=== Critical 级别的信息 ===") 复制代码
运行结果如下:
# 控制台输出: === Warning 级别的信息 === === Error 级别的信息 === === Critical 级别的信息 === # test.log文件: === Info 级别的信息 === === Warning 级别的信息 === === Error 级别的信息 === === Critical 级别的信息 === 复制代码
③ 定制日志输出格式
纠结完输出到那里,接着就输出日志的格式了,日志一般都是比较规范的,比如 日志打印的时间 , 类型 等,而不会像我们这样随意拼接一段字符串,对于日志格式的定制可以通过 logging模块
的 Formatter组件
来定制。 basicConfig()
中的handler 自带一个formatter ,通过 logging.basicConfig(**kwargs)函数
进行定制,该函数 可接收的关键字参数 如下表所示。
参数 | 描述 |
---|---|
filename | 指定日志输出目标文件的文件名,设置后信息就不会打印到控制台 |
filemode | 指定日志文件的打开模式,默认为'a',设置了filename这个才会生效 |
format | 指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序 |
datefmt | 指定日期/时间格式,该选项要在format中包含时间字段%(asctime)s时才有效 |
level | 指定日志器的日志级别 |
stream | 指定日志输出目标stream,不能和filename同时使用否则会引起ValueError异常 |
style | Python 3.2新增,默认'%'指定format格式字符串的风格,可取值为'%'、'{'和'$' |
format格式字符串的字段列表如下表所示:
参数 | 描述 |
---|---|
%(asctime)s | 日志发生的时间--人类可读时间,如:2003-07-08 16:49:45,896 |
%(created)f | 日志发生的时间--时间戳,就是当时调用time.time()函数返回的值 |
%(relativeCreated)d | 日志发生的时间相对于logging模块加载时间的相对毫秒数 |
%(msecs)d | 日志发生时间的毫秒部分 |
%(levelname)s | 该日志记录的文字形式的日志级别('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL') |
%(levelno)s | 该日志记录的数字形式的日志级别(10, 20, 30, 40, 50) |
%(name)s | 所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger |
%(message)s | 日志记录的文本内容,通过 msg % args计算得到的 |
%(pathname)s | 调用日志记录函数的源码文件的全路径 |
%(filename)s | pathname的文件名部分,包含文件后缀 |
%(module)s | filename的名称部分,不包含后缀 |
%(lineno)d | 调用日志记录函数的源代码所在的行号 |
%(funcName)s | 调用日志记录函数的函数名 |
%(process)d | 进程ID |
%(processName)s | 进程名称,Python 3.1新增 |
%(thread)d | 线程ID |
%(thread)s | 线程名称 |
简单的使用代码示例如下:
import logging if __name__ == '__main__': logger = logging.getLogger("Test") logging.basicConfig(level=logging.INFO, format="%(asctime)s %(process)d:%(processName)s- %(levelname)s === %(message)s", datefmt="%Y-%m-%d %H:%M:%S %p") logger.debug("Debug 级别的信息") logger.info("Info 级别的信息") logger.warning("Warning 级别的信息") logger.error("Error 级别的信息") logger.critical("Critical 级别的信息") 复制代码
运行结果如下:
2019-03-14 16:39:02 PM 8628:MainProcess- INFO === Info 级别的信息 2019-03-14 16:39:02 PM 8628:MainProcess- WARNING === Warning 级别的信息 2019-03-14 16:39:02 PM 8628:MainProcess- ERROR === Error 级别的信息 2019-03-14 16:39:02 PM 8628:MainProcess- CRITICAL === Critical 级别的信息 复制代码
另外要注意一点 basicConfig没有设置编码的属性 ,如果想把日志写入到文件里,而日志里又有中文的话,只能通过一开始那种 设置FileHandler对象的方式 !除了通过basicConfig()设置日志格式,还可以自定义一个Formatter对象,然后调用 setFormatter
函数进行设置。使用代码示例如下:
import logging if __name__ == '__main__': logger = logging.getLogger("Test") logger.setLevel(logging.INFO) # 自定义Formatter对象 fmt = logging.Formatter("%(asctime)s %(process)d:%(processName)s- %(levelname)s === %(message)s", datefmt="%Y-%m-%d %H:%M:%S %p") # 输出到控制台 s_handler = logging.StreamHandler() s_handler.setLevel(logging.WARNING) s_handler.setFormatter(fmt) logger.addHandler(s_handler) # 输出到文件 f_handler = logging.FileHandler('test.log', encoding='UTF-8') f_handler.setLevel(logging.DEBUG) f_handler.setFormatter(fmt) logger.addHandler(f_handler) logger.debug("Debug 级别的信息") logger.info("Info 级别的信息") logger.warning("Warning 级别的信息") logger.error("Error 级别的信息") logger.critical("Critical 级别的信息") 复制代码
运行结果如下:
# 控制台输出: 2019-03-14 16:41:09 PM 11312:MainProcess- WARNING === Warning 级别的信息 2019-03-14 16:41:09 PM 11312:MainProcess- ERROR === Error 级别的信息 2019-03-14 16:41:09 PM 11312:MainProcess- CRITICAL === Critical 级别的信息 # test.log文件: 2019-03-14 16:41:09 PM 11312:MainProcess- INFO === Info 级别的信息 2019-03-14 16:41:09 PM 11312:MainProcess- WARNING === Warning 级别的信息 2019-03-14 16:41:09 PM 11312:MainProcess- ERROR === Error 级别的信息 2019-03-14 16:41:09 PM 11312:MainProcess- CRITICAL === Critical 级别的信息 复制代码
logging除了 Handler
和 Formatter
两个组件外还有, Filter
和 LoggerAdapter
组件,不过用得
不多,有兴趣的同学可以自行到官方文档进行查阅: docs.python.org/3/library/l…