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

How to get system timezone setting and pass it to pytz.timezone?

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

实际上,time.tzname返回的名称是不明确的。此方法在我的系统中返回('CST', 'CST'),但'cst'可以指示四个时区:

  • 中部时区(北美)-观察北美中部时区
  • 中国标准时间
  • 春元标准时间-台湾现在很少使用"春元标准时间"这个词。
  • 澳大利亚中部标准时间


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
>>> 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>)

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

对于那些在2017年遇到这种情况的人来说,dateutil.tz.tzlocal()仍然是失败的。上面的例子现在起作用了,因为当前的UTF偏移量是莫斯科的UTC+3(偶然等于1970年的UTC偏移量)。为了证明错误,我们可以选择当UTC偏移量为UTC+4时的日期:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> 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>)

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


使用python-dateutil包中的tzlocal功能:

1
2
3
from dateutil.tz import tzlocal

localtimezone = tzlocal()

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

你用这个代替pytz时区。

另一种方法是从操作系统中读取当前配置的时区,但是这在操作系统和操作系统之间有很大的不同。在Mac OS X上,您需要读取systemsetup -gettimezone的输出:

1
2
$ systemsetup -gettimezone
Time Zone: Europe/Copenhagen

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

1
2
$ cat /etc/timezone
Europe/Oslo

在RedHat和Direved系统上,您需要从/etc/sysconfig/clock中读取:

1
2
$ grep ZONE /etc/sysconfig/clock
ZONE="Europe/Oslo"


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

1
2
3
4
5
import time

def localTzname():
    offsetHour = time.timezone / 3600
    return 'Etc/GMT%+d' % offsetHour

最新消息:@martijnpieers说"这不适用于夏令时"。那么这个版本呢?

1
2
3
4
5
6
7
8
import time

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


由于python 3.6,您只需运行naive_datetime.astimezone(),系统时区将添加到naive_datetime对象中。

If called without arguments (or with tz=None) the system local timezone is assumed for the target timezone. The .tzinfo attribute of the converted datetime instance will be set to an instance of timezone with the zone name and offset obtained from the OS.

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

例子:

1
2
3
>>> import datetime
>>> datetime.datetime.now().astimezone().isoformat(timespec='minutes')
'2018-10-02T13:09+03:00'


我不知道这对你是否有用,但我认为它能回答你更普遍的问题:

如果您的日期处于不明确的时区,如CST,那么简单的日期(仅限python 3.2+,抱歉)可以自动执行搜索,并允许您执行喜欢某些国家/地区的操作。

例如:

1
2
3
4
5
6
7
>>> SimpleDate('2013-07-04 18:53 CST')
Traceback [...
simpledate.AmbiguousTimezone: 3 distinct timezones found: <DstTzInfo 'Australia/Broken_Hill' CST+9:30:00 STD>; <DstTzInfo 'America/Regina' LMT-1 day, 17:01:00 STD>; <DstTzInfo 'Asia/Harbin' LMT+8:27:00 STD> (timezones=('CST',), datetime=datetime.datetime(2013, 7, 4, 18, 53), is_dst=False, country=None, unsafe=False)
>>> SimpleDate('2013-07-04 18:53 CST', country='CN')
SimpleDate('2013-07-04 18:53 CST')
>>> SimpleDate('2013-07-04 18:53 CST', country='CN').utc
SimpleDate('2013-07-04 10:53 UTC', tz='UTC')

请注意,通过指定一个国家,您如何充分减少可能值的范围以允许转换为UTC。

它是通过在Pytz中对时区进行搜索来实现的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>> SimpleDate('2013-07-04 18:53 CST', country='CN', debug=True)
...
PyTzFactory: Have country code CN
PyTzFactory: Country code CN has 5 timezones
PyTzFactory: Expanded country codes to 5 timezones
PyTzFactory: Expanding ('CST',)
PyTzFactory: Name lookup failed for CST
PyTzFactory: Found CST using Asia/Shanghai
PyTzFactory: Found CST using Asia/Harbin
PyTzFactory: Found CST using Asia/Chongqing
PyTzFactory: Found CST using Asia/Urumqi
PyTzFactory: Found CST using Asia/Kashgar
PyTzFactory: Expanded timezone to 5 timezones
PyTzFactory: New offset 8:00:00 for Asia/Shanghai
PyTzFactory: Known offset 8:00:00 for Asia/Harbin
PyTzFactory: Known offset 8:00:00 for Asia/Chongqing
PyTzFactory: Known offset 8:00:00 for Asia/Urumqi
PyTzFactory: Known offset 8:00:00 for Asia/Kashgar
PyTzFactory: Have 1 distinct timezone(s)
PyTzFactory: Found Asia/Shanghai
...
SimpleDate('2013-07-04 18:53 CST')

最后,为了直接回答所问的问题,它还包装了TZLocal,如这里的另一个答案所述,因此,如果不提供时区,它将自动执行您期望的操作。例如,我住在智利,所以

1
2
3
4
>>> SimpleDate()
SimpleDate('2013-07-04 19:21:25.757222 CLT', tz='America/Santiago')
>>> SimpleDate().tzinfo
<DstTzInfo 'America/Santiago' CLT-1 day, 20:00:00 STD>

给出我所在地区的时区(不明确或不明确)。


1
import pytz

假设在对象列表对象中有UTC日期时间值列表。

1
tz=pytz.timezone('Asia/Singapore')

在下面的url中找到相应的时区位置字符串参数有PYTZ时区列表吗?

现在我们的TZ反对新加坡时间

1
2
3
4
result=[]
for i in OBJ:
    i=i+tz.utcoffset(i)
    result.append(i)

结果列表对象具有各自时区的日期时间值