为什么我的电脑上datetime.now()和datetime.today()显示的是UTC时间而不是本地时间?

13

datetime.now()datetime.today()在我的电脑上返回的是UTC时间,尽管文档中说它们应该返回本地时间。

这是我运行的脚本:

#!/usr/bin/python

import time
import datetime

if __name__ == "__main__":
   print(datetime.datetime.now())
   print(datetime.datetime.today())
   print(datetime.datetime.fromtimestamp(time.time()))

这里是输出结果:

2017-11-29 22:47:35.339914
2017-11-29 22:47:35.340399
2017-11-29 22:47:35.340399

运行 date 后的输出如下:

Wed, Nov 29, 2017  3:47:43 PM
我安装的程序返回UTC时间,如何获取本地时间? PS 我们在MST时区,即UTC-7。 PS 2 我知道有方法可以将UTC时间转换为本地时间,例如在“使用Python标准库将Python UTC时间转换为本地时间?”中讲解的那些方法。然而,我想了解根本问题的原因,并不是在寻找解决自己代码问题的方法。

回复@jwodder的评论:

执行后的输出为:

print(time.altzone)
print(time.timezone)
print(time.tzname)
-3600
0
('Ame', 'ric')

1
请参见:https://dev59.com/r2455IYBdhLWcg3wD_yZ - rassar
1
@rassar,感谢提供链接。它有用的信息,但并没有回答我所提出的问题。 - R Sahu
1
你的系统时区可能设置为UTC。time.tzname和相关常量有什么值? - jwodder
1
date 显示我的时区;如果你执行 date -R,它会显示什么? - Nick T
4
你的时区肯定出了问题。我猜'Ame', 'ric'America的开头。不知道怎么会这样。在我的电脑上,time.tzname返回的是('Pacific Standard Time', 'Pacific Daylight Time')。你没有指定你的操作系统等信息,但需要找出在你的系统上如何设置时区... - Stephen Rauch
显示剩余3条评论
3个回答

6

如你在你的答案中提到的那样,关键在于TZ环境变量。在类Unix系统上,它支持更友好的值,例如"US/Pacific"或"America/Denver",但在Windows上却不支持。虽然在Windows上不可用,但time.tzset函数的文档描述了您需要设置TZ的格式来获得所需内容。这并不美观,但可以使用:

C:\Users\zorb>set TZ=MST+07MDT,M3.2.0,M11.1.0
C:\Users\zorb>python.exe
>>> import time
>>> time.tzname
('MST', 'MDT')
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2018, 2, 9, 16, 27, 7, 164062)

这是太平洋时间15:27时的时间格式。该格式结构如下:

  • 标准时间缩写(MST)
  • 标准时间的UTC偏移量,以小时为单位(+07)
  • 夏令时缩写
  • 夏令时开始时间(见下文)
  • 夏令时结束时间(见下文)

夏令时开始和结束的格式为:

  • M(表示“基于月份”)
  • 月份数字-3/三月或11/十一月,在本例中。
  • 月份中的周数-1到5,表示下面命名的日期的第1到第5次出现。
  • 星期几-0表示星期日,6表示星期六

还有指定夏令时开始和结束时间的选项(但默认为02:00:00,因此在此情况下不必要),以及夏令时的偏移量(但默认为1小时,因此也不必要)。

(编辑)事实证明,这实际上是glibc功能,而不是Python功能。 在glibc文档中可以找到更详细的信息。


1
这听起来很有前途。我一定会使用你的建议进一步调查。 - R Sahu
1
很高兴听到这个消息! - Nathan Vērzemnieks

2

最初看起来是使用cygwin引起的问题。

Cygwin显示UTC时间而不是本地时间的问题进一步隔离了问题,发现是cygwin中环境变量TZ的值造成的。

更新后的脚本:

import time
import datetime

if __name__ == "__main__":
   print(datetime.datetime.now())
   print(datetime.datetime.today())
   print(datetime.datetime.fromtimestamp(time.time()))
   print(time.altzone)
   print(time.timezone)
   print(time.tzname)

在未设置TZ的Windows CMD shell下运行时的输出:

"D:\Program Files\Python35\python.exe" test.py

2017-11-30 09:39:47.236798
2017-11-30 09:39:47.236799
2017-11-30 09:39:47.236799
21600
25200
('Mountain Standard Time', 'Mountain Daylight Time')

在cygwin bash shell下运行时的输出,其中TZ设置为"America/Denver"

 /cygdrive/D/Program\ Files/Python35/python.exe test.py

2017-11-30 16:39:45.419884
2017-11-30 16:39:45.419884
2017-11-30 16:39:45.419884
-3600
0
('Ame', 'ric')

它设置为"America/Denver"。当我执行时

env TZ="" /cygdrive/D/Program\ Files/Python35/python.exe test.py

我得到了一个更加合理的输出:
2017-11-30 09:56:08.643368
2017-11-30 09:56:08.643368
2017-11-30 09:56:08.643368
21600
25200
('Mountain Standard Time', 'Mountain Daylight Time')

当我在Windows CMD shell中将环境变量TZ设置为"America/Denver"时,我得到了与在cygwin shell中运行时相同的输出。
对于Python如何使用环境变量TZ以及其正确值是什么,我并不清楚。

1
我永远不会使用Cygwin的另一个原因。 - Nick T
1
@NickT,然而cygwin并不是问题的关键。真正的问题在于,如果环境变量TZ被设置了,即使只是在CMD控制台中,问题仍然存在。这是一个根本性的Python问题。 - R Sahu
那么您是在Cygwin shell中使用非Cygwin版本的Python吗?那么是的,TZ约定很可能不兼容。如果您希望Python理解Unix风格的TZ约定,最好使用Cygwin版本的Python。 - Ove
@Ove,理想情况下是的。然而,有时候这并不是一个选择。 - R Sahu

1

我认为在使用Windows上的glibc时间和时区库的一些事情上存在一些奇怪的行为。最近我在python和emacs中都注意到了这种行为。

最好的方法可能是将TZ设置为“丑陋”的版本,如最佳答案中所述,因为它似乎可以解决python和emacs中的问题,并在cygwin中正确工作。

我尝试的另一个解决方法是确保未设置TZ环境变量。以下示例说明了在纽约时间10:18左右在python中出现的问题。无论是在Windows上的cygwin还是CMD中使用,我都会得到类似的结果。 Emacs使用current-time-string函数说明它是一个glibc问题或至少是python和emacs都在使用的某个库。有趣的是,在将TZ设置为“America/New York”时,cygwin中的date命令给出了正确的结果,但如果未设置TZ,则不正确。

总结:在Windows上,一些东西(例如python、emacs)似乎不接受“America/New_York”作为TZ,而另一些东西(例如cygwin)则接受它。使用类似于EST+05EDT,M4.1.0,M10.5.0的东西来表示东部时间(或适当的丑陋等效物)可以解决问题。

$ echo $TZ
America/New_York

$ python -i
Python 3.6.4 |Anaconda, Inc.| (default, Jan 16 2018, 10:22:32) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2018, 5, 14, 15, 38, 6, 174073)
>>> datetime.datetime.now()
datetime.datetime(2018, 5, 14, 15, 38, 57, 141708)
>>> quit()

$ export TZ=

$ python -i
Python 3.6.4 |Anaconda, Inc.| (default, Jan 16 2018, 10:22:32) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2018, 5, 14, 10, 38, 41, 102117)

你尝试过使用被接受的答案中提到的形式来设置 TZ 吗? - R Sahu
是的。已更新答案以反映此事。谢谢。 - oxer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接