让 Python 响应 Windows 时区的变化
Posted
技术标签:
【中文标题】让 Python 响应 Windows 时区的变化【英文标题】:Make Python respond to Windows timezone changes 【发布时间】:2011-05-20 15:30:11 【问题描述】:当 Python 在 Windows 下运行时,如果在 Python 实例的生命周期内更改了时区,则 time.localtime 不会报告正确的时间。在 Linux 下,time.tzset 始终可以运行以缓解此类问题,但在 Windows 中似乎没有等效项。
有没有办法解决这个问题而不会做一些荒谬的事情,哦,我不知道......
#!/bin/env python
real_localtime = eval(subprocess.Popen(
["python","-c", "import time;repr(time.localtime())"],
stdout=subprocess.PIPE).communicate()[0])
【问题讨论】:
我可以确认这一点,对我来说似乎是一个错误。 @Rafe 为什么不需要评估?我想要一个可以使用的元组,而不是字符串。 【参考方案1】:更合理的解决方案是将 Kernel32 的 GetLocalTime 与 pywin32 或 ctypes 一起使用。任何时区更改都会立即反映出来。
import ctypes
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)]
SystemTime = SYSTEMTIME()
lpSystemTime = ctypes.pointer(SystemTime)
ctypes.windll.kernel32.GetLocalTime(lpSystemTime)
print SystemTime.wHour, SystemTime.wMinute
【讨论】:
【参考方案2】:不,如果不执行您所做的操作,则无法解决此问题。这有点荒谬,但是如果您需要在 Windows 中正确的时区并且在程序执行过程中发生了变化,则必须这样做。
这可能不是错误(文档非常清楚tzset()
函数仅在 Unix 上可用)。这更可能是 Windows 中的一个弱点,它阻止了 Python 程序员在其下实现tzset()
。您可以提出功能增强请求,但自 Python 2.3(7 年)以来一直如此,因此不太可能真正实现。
【讨论】:
一个功能请求对我个人没有多大好处,因为我仍然使用 2.X,但我想我以后可以饶过别人。有没有办法让重新加载功能在内置模块上工作?当普通的旧重新加载功能不起作用时,我尝试了“del time; del sys.modules['time']”但没有这样的运气。 @EricPruitt 如果您尝试以“正常”方式重新加载,则可能不会。您的解决方案有点杂乱无章,但它必须起作用 我想我会使用 ctypes 或 pywin32 并尝试使用Kernel32.lib's GetLocalTime。【参考方案3】:最重要的是,在 VC 版本 6 中,tzset() 无法正常工作。但是,对于 VC 版本 8,tzset() 现在可以正常工作(我认为它可能也在版本 7 中工作,但我没有那个版本可以检查)。
所以现在要做的就是在源代码中启用 HAVE_WORKING_TZSET 并重新编译(和测试)。
根据我的经验,TZ 的不同设置的所有功能需求都需要一个有效的 tzset()。每次更改 C Lang TZ var -或- Windows TIME_ZONE_INFORMATION 时都必须调用 tzset()。这在 VC 版本 6 中是不可能的,这就是未启用 HAVE_WORKING_TZSET 的原因(但现在应该至少适用于 VC 版本 8 及更高版本)。
顺便说一句。对于我所做的所有日期/时间的事情,我总是有一个 SetUtcTime() 和 UnsetUtcTime() ,它将 TZ 设置为 GMT 并相应地调用 tzset() 。我也有功能 临时设置为另一个时区。这是正确执行此操作的唯一方法!在多年的经验中,我可以说其他任何事情都是麻烦的。而 calendar.timegm() 不是 正确的。使用 tzset()。
这是它现在工作的证明(所以请去 bug 作者修复 windows 代码):
(我是从另一台电脑上输入的,所以希望没有拼写错误,但它是 我提出的观点,而不是代码)。
注意:以下都是 PYTHON(我从 python 的 ctype 接口调用 C Lang) 注意:因为我在这里通过 DLL 边界设置 TZ 和线程本地和所有 那个废话,它不能用作解决方法。必须重新启用 HAVE_WORKING_TZSET。
import time
from ctypes import *
dTime = time.time ()
nTime = int (dTime)
intTime = c_int (nTime)
print time.ctime (dTime)
print c_char_p (cdll.msvcrt.ctime (addressof (intTime))).value
-> ... 21:02:40 ... (python) -> ... 21:02:40 ...(C 语言)
cdll.msvcrt._putenv ('TZ=GMT')
cdll.msvcrt._tzset ()
(通常会调用 time.tzset() 并调用 inittimezone() 来更新 python的时区变量)
print time.ctime (dTime)
print c_char_p (cdll.msvcrt.ctime (addressof (intTime))).value
-> ... 21:02:40 ... (python) -> ... 11:02:40 ...(C 语言)
(因此,如果为(版本 8 及更高版本)定义了 HAVE_WORKING_TZSET,您将得到:)
-> ... 11:02:40 ... (python) -> ... 11:02:40 ...(C 语言)
只需检查源代码即可了解我的意思。
我用最新的python'2.0'系列检查了这个:刚刚2.7.2。
【讨论】:
以上是关于让 Python 响应 Windows 时区的变化的主要内容,如果未能解决你的问题,请参考以下文章
为啥 python datetime replace timezone 返回不同的时区?