Python 记录器时间使用更新的 OS 时区(替换 Windows 中的 time.tzset())

Python logger time use updated OS timezone (replacement of time.tzset() in Windows)

更新: 原始问题似乎无效,因为即使我设法强制记录器使用 datetime.now(),它仍然没有解决我的最终目标,即在不重新启动 [=41= 的情况下使日志记录时间戳响应 OS 时区更改】 翻译。我在下面提供了我找到的答案。

如何强制记录器使用 datetime.now() 而不是 time.asctime()?我需要日志严格遵循 Windows OS 提供的时间,但 time.asctime() 在认为需要时会尝试转换时区。如何覆盖此行为?

目前我使用格式字符串 '{asctime}: {levelname} - {message}'

的自定义 logging.format 子类

这样做的目的是因为我的python脚本在执行过程中改变了OS时区。我希望日志在脚本更改后立即跟随更新的时区。我试图在 logging.format 子类中定义一个 converter 函数,但这导致日志中的时区即使在我更改后也没有更新。

我使用的代码(来自文档https://docs.python.org/3.9/library/logging.html#logging.Formatter.formatTime):

class custom(logging.Formatter):
    def converter(self, timestamp):
        return datetime.now()

尝试了这里的每一个答案:,都没有用,因为它们都没有更新到我的脚本在 OS 中设置的新时区。我试了importlib.reload(tzlocal)也没用

我找到的唯一明智的答案是使用 time.tzset() 但它显然在 Windows

上不可用

经过一些研究,我使用 ctypes 解决了我自己的问题,这是受此 answer 的启发。本质上,我通过添加对 Windows 系统 API 的调用来覆盖 logging.Formatter.formatTime 函数以获取当前系统时间。这是一种与所有现有 python 模块(time, datetime, pytz 等)完全不同的方法,因为启动 python 解释器时不会缓冲时区信息。

代码:

class real_time_formatter(logging.Formatter):
    def formatTime(self, record, datefmt=None):
        class SYSTEMTIME(ctypes.Structure):
            _fields_ = [('wYear', ctypes.c_int16),
                        ('wMonth', ctypes.c_int16),
                        ('wDayOfWeek', ctypes.c_int16),
                        ('wDay', ctypes.c_int16),
                        ('wHour', ctypes.c_int16),
                        ('wMinute', ctypes.c_int16),
                        ('wSecond', ctypes.c_int16),
                        ('wMilliseconds', ctypes.c_int16)]

        lpSystemTime = ctypes.pointer(SystemTime)
        ctypes.windll.kernel32.GetLocalTime(lpSystemTime)
        year = '0' * (4 - len(str(SystemTime.wYear))) + str(SystemTime.wYear)
        month = '0' * (2 - len(str(SystemTime.wMonth))) + str(SystemTime.wMonth)
        day = '0' * (2 - len(str(SystemTime.wDay))) + str(SystemTime.wDay)
        hour = '0' * (2 - len(str(SystemTime.wHour))) + str(SystemTime.wHour)
        minute = '0' * (2 - len(str(SystemTime.wMinute))) + str(SystemTime.wMinute)
        second = '0' * (2 - len(str(SystemTime.wSecond))) + str(SystemTime.wSecond)
        ms = '0' * (3 - len(str(SystemTime.wMilliseconds))) + str(SystemTime.wMilliseconds)
        return f'{year}-{month}-{day} {hour}:{minute}:{second}:{ms}'  # 2003-01-23 00:29:50,411

streamHandler.setFormatter(real_time_formatter())

这模仿了 python {asctime} 格式,当然您可以随意更改它,因为它只是一个 f 字符串。