用配置文件,修改linux系统下的时区(所用系统 CentOS8)

1.问题来源

在linux上使用python的logging模块的时候,发现了一个问题,那就是模块里面的%(asctime)s打印的时间并非东八区的时间,而是格林尼治时间,比东八区的时间少了8小时

对于日志来说,这怎么行?总不能每次看日志的时候,自己手动给时间加8小时吧!那样对debug来说可不是什么方便事!

2.解决

百度了一下后,发现是我系统的时区问题。这个Centos系统是用docker安装的,内部的时区没有正常设置

1
date

通过date命令可以查看系统当前的时间

1
Sat Mar  4 01:29:59 UTC 2023

会发现是3月4日的凌晨1点,但实际上我是在上午9点写下的这篇博客

image-20230304093451196

这就需要我们修改时区了!


刚开始,我尝试用tzselect命令进行时区的选择,再选择了上海时区后,系统的时间还是有问题。然后发现,需要修改文件配置,才能让时间生效

1
2
3
/etc/timezone # 时区的配置
/etc/localtime # 时间
/usr/share/zoneinfo/Asia #这里边放着亚洲主要城市的时间

而我的系统中,第一个文件压根不存在!

要用下面的两个命令来修改配置文件(root下执行)

1
echo "Asia/Shanghai" > /etc/timezone
1
2
rm -rf /etc/localtime
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

修改完毕,再次执行date命令,可以看到时间已经正常了

1
Sat Mar  4 09:31:33 CST 2023

python的logging模块中打印的时间也正常了

1
2
3
4
5
6
[23-03-04 09:31:39] DEBUG:log.py:debug:9 | test in main
[23-03-04 09:31:39] ERROR:log.py:exception:24 | Exception occurred
Traceback (most recent call last):
File "/home/kook/code/py-test/log.py", line 32, in test
a = 10/0
ZeroDivisionError: division by zero

3.python-logging优化

虽然如此,但logging本身其实是可以设置时区的,提供一份简单的模板代码;

在下面的代码中,用了beijing这个函数来获取东八区的时间,这样这份代码在任何系统上执行,都将会打印东八区的时间了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import logging
from datetime import datetime,timezone,timedelta

LOGGER_NAME = "bot-log" # 日志对象名字,这个没啥用
LOGGER_FILE = "bot.log" # 如果想修改log文件的名字和路径,修改此变量
"""日志文件路径"""


def beijing(sec, what):
"""日志返回北京时间的处理"""
utc_dt = datetime.now(timezone.utc) # 获取当前时间
beijing_time = utc_dt.astimezone(timezone(timedelta(hours=8))) # 转换为北京时间
return beijing_time.timetuple()
# 日志时间改为北京时间
logging.Formatter.converter = beijing # type:ignore

# 只打印info以上的日志(debug低于info)
logging.basicConfig(level=logging.INFO,
format="[%(asctime)s] %(levelname)s:%(filename)s:%(funcName)s:%(lineno)d | %(message)s",
datefmt="%y-%m-%d %H:%M:%S")
# 获取一个logger对象
_log = logging.getLogger(LOGGER_NAME)
"""自定义的logger对象"""
# 实例化控制台handler和文件handler,同时输出到控制台和文件
# cmd_handler = logging.StreamHandler() # 默认设置里面,就会往控制台打印信息;自己又加一个,导致打印俩次
file_handler = logging.FileHandler(LOGGER_FILE, mode="a", encoding="utf-8")
fmt = logging.Formatter(fmt="[%(asctime)s] %(levelname)s:%(filename)s:%(funcName)s:%(lineno)d | %(message)s",
datefmt="%y-%m-%d %H:%M:%S")
file_handler.setFormatter(fmt)
_log.addHandler(file_handler)

针对replit这类不支持自定义时区的平台,这样也更方便。