如何获取系统时区设置并将其传递给pytz.timezone?

use*_*627 51 python timezone pytz

我们可以使用time.tzname获取本地时区名称,但该名称与之不兼容pytz.timezone.

实际上,返回的名称time.tzname含糊不清.此方法('CST', 'CST')在我的系统中返回,但"CST"可以指示四个时区:

  • 中部时区(北美) - 在北美的中部时区观察
  • 中国标准时间
  • 中原标准时间 - "中原标准时间"一词现在在台湾很少使用
  • 澳大利亚中央标准时间(ACST)

jfs*_*jfs 66

tzlocal模块返回对应于本地时区的pytz tzinfo对象:

import time
from datetime import datetime

import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal

# get local timezone    
local_tz = get_localzone() 

# test it
# utc_now, now = datetime.utcnow(), datetime.now()
ts = time.time()
utc_now, now = datetime.utcfromtimestamp(ts), datetime.fromtimestamp(ts)

local_now = utc_now.replace(tzinfo=pytz.utc).astimezone(local_tz) # utc -> local
assert local_now.replace(tzinfo=None) == now
Run Code Online (Sandbox Code Playgroud)

即使在夏令时转换期间,当本地时间可能不明确时,它也能工作.

local_tz即使当地时区的utc偏移量不同,也适用于过去的日期.dateutil.tz.tzlocal()在这种情况下,基于解决方案失败,例如,在欧洲/莫斯科时区(2013年的例子):

>>> import os, time
>>> os.environ['TZ'] = 'Europe/Moscow'
>>> time.tzset()
>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> from tzlocal import get_localzone
>>> dateutil_tz = tzlocal()
>>> tzlocal_tz = get_localzone()
>>> datetime.fromtimestamp(0, dateutil_tz)                              
datetime.datetime(1970, 1, 1, 4, 0, tzinfo=tzlocal())
>>> datetime.fromtimestamp(0, tzlocal_tz)
datetime.datetime(1970, 1, 1, 3, 0, tzinfo=<DstTzInfo 'Europe/Moscow' MSK+3:00:00 STD>)
Run Code Online (Sandbox Code Playgroud)

dateutil 在1970-01-01上返回错误的 UTC + 4偏移而不是正确的UTC + 3.

对于那些在2017年遇到这种情况的人 dateutil.tz.tzlocal()来说还是打破了.上面的例子现在有效,因为莫斯科当前的utf偏移量是UTC + 3(偶然等于1970年的utc偏移量).为了演示错误,我们可以选择utc offset为UTC + 4的日期:

>>> import os, time
>>> os.environ['TZ'] = 'Europe/Moscow'
>>> time.tzset()
>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> from tzlocal import get_localzone
>>> dateutil_tz = tzlocal()
>>> tzlocal_tz = get_localzone()
>>> ts = datetime(2014, 6,1).timestamp() # get date in 2014 when gmtoff=14400 in Moscow
>>> datetime.fromtimestamp(ts, dateutil_tz)
datetime.datetime(2014, 5, 31, 23, 0, tzinfo=tzlocal())
>>> datetime.fromtimestamp(ts, tzlocal_tz)
datetime.datetime(2014, 6, 1, 0, 0, tzinfo=<DstTzInfo 'Europe/Moscow' MSK+4:00:00 STD>)
Run Code Online (Sandbox Code Playgroud)

dateutil 在2014-06-01上返回错误的 UTC + 3偏移而不是正确的UTC + 4.

  • 时区似乎表现得像Hoffstadter定律那样:它们比你想象的要复杂得多,即使你考虑到它们比你想象的更复杂. (9认同)
  • 对于那些在2017年遇到这种情况的人,`dateutil.tz.tzlocal()`不再被破坏,并且没有表现出上述行为. (4认同)
  • @WhyNotHugo:`dateutil.tz.tzlocal()`仍然破碎.我已经更新了答案. (3认同)

Mar*_*ers 33

使用tzlocal功能python-dateutil:

from dateutil.tz import tzlocal

localtimezone = tzlocal()
Run Code Online (Sandbox Code Playgroud)

在内部,这是一个使用time.timezonetime.altzone(基于切换time.daylight)的类,但是从中创建了一个合适的时区对象.

您可以使用此替代pytz时区.

另一种方法是从操作系统读取当前配置的时区,但这在操作系统与操作系统之间存在很大差异.在Mac OS X上,您需要阅读以下输出systemsetup -gettimezone:

$ systemsetup -gettimezone
Time Zone: Europe/Copenhagen
Run Code Online (Sandbox Code Playgroud)

在Debian和Ubuntu系统上,您可以阅读/etc/timezone:

$ cat /etc/timezone
Europe/Oslo
Run Code Online (Sandbox Code Playgroud)

在RedHat和direved系统上,您需要从/etc/sysconfig/clock以下位置读取它:

$ grep ZONE /etc/sysconfig/clock
ZONE="Europe/Oslo"
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,但是“pytz.timezone”需要一个时区名称。 (2认同)
  • 但是`pytz`已经在我的项目的很多地方使用了,我不想仅仅因为这个问题就替换它。 (2认同)
  • 注意:[dateutil 在 DST 转换期间可能会失败,而 pytz 工作](https://gist.github.com/3838828) (2认同)
  • 如果当地时区的utc偏移时间当时不同,则dateutil.tz.tzlocal()不适用于过去的日期。 (2认同)

use*_*627 9

一个非常简单的方法来解决这个问题:

import time

def localTzname():
    offsetHour = time.timezone / 3600
    return 'Etc/GMT%+d' % offsetHour
Run Code Online (Sandbox Code Playgroud)

更新:@MartijnPieters说'这不适用于夏令时/夏季.' 那这个版本怎么样?

import time

def localTzname():
    if time.daylight:
        offsetHour = time.altzone / 3600
    else:
        offsetHour = time.timezone / 3600
    return 'Etc/GMT%+d' % offsetHour
Run Code Online (Sandbox Code Playgroud)

  • 日期和时间数学就像加密:DIY是危险的.留给专家. (8认同)
  • `time.daylight`没有说明DST现在是否生效,只是说时区是否有DST.您可以按如下方式计算utc偏移量:`is_dst = time.daylight和time.localtime().tm_isdst> 0`.您可以将POSIX时间戳传递给`localtime()`,以在不同的时刻计算`is_dst`.`utc_offset = - (time.altzone if is_dst else time.timezone)`(注意:符号与名称中使用的符号相反) (5认同)
  • 这不适用于[半小时和45分钟时区](http://www.timeanddate.com/time/time-zones-interesting.html). (3认同)

sir*_*rex 8

从Python 3.6开始,您只需运行即可将naive_datetime.astimezone()系统时区添加到naive_datetime对象中。

如果在不带参数的情况下(或在tz = None的情况下)被调用,则系统本地时区将作为目标时区。转换后的datetime实例的.tzinfo属性将设置为具有从OS获得的区域名称和偏移量的timezone实例。

https://docs.python.org/3/library/datetime.html#datetime.datetime.astimezone

例:

>>> import datetime
>>> datetime.datetime.now().astimezone().isoformat(timespec='minutes')
'2018-10-02T13:09+03:00'
Run Code Online (Sandbox Code Playgroud)

  • 这个答案正是我所需要的,它甚至不需要第三方库! (2认同)