Python: 计算出本地时区

我想将日志文件中的 UTC 时间戳与本地时间戳进行比较。在创建本地 datetime对象时,我使用如下代码:

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0,
tzinfo=pytz.timezone('Israel'))

我想找到一个自动工具,将取代 tzinfo=pytz.timezone('Israel')与当前的本地时区。

Any ideas?

171753 次浏览

试试 约会,它有一个 当地人类型,可以满足您的需要。

对于简单的事情,可以使用以下 tzinfo实现,它查询操作系统的时区偏移量:

import datetime
import time


class LocalTZ(datetime.tzinfo):
_unixEpochOrdinal = datetime.datetime.utcfromtimestamp(0).toordinal()


def dst(self, dt):
return datetime.timedelta(0)


def utcoffset(self, dt):
t = (dt.toordinal() - self._unixEpochOrdinal)*86400 + dt.hour*3600 + dt.minute*60 + dt.second + time.timezone
utc = datetime.datetime(*time.gmtime(t)[:6])
local = datetime.datetime(*time.localtime(t)[:6])
return local - utc




print datetime.datetime.now(LocalTZ())
print datetime.datetime(2010, 4, 27, 12, 0, 0, tzinfo=LocalTZ())


# If you're in the EU, the following datetimes are right on the DST change.
print datetime.datetime(2013, 3, 31, 0, 59, 59, tzinfo=LocalTZ())
print datetime.datetime(2013, 3, 31, 1, 0, 0, tzinfo=LocalTZ())
print datetime.datetime(2013, 3, 31, 1, 59, 59, tzinfo=LocalTZ())


# The following datetime is invalid, as the clock moves directly from
# 01:59:59 standard time to 03:00:00 daylight savings time.
print datetime.datetime(2013, 3, 31, 2, 0, 0, tzinfo=LocalTZ())


print datetime.datetime(2013, 10, 27, 0, 59, 59, tzinfo=LocalTZ())
print datetime.datetime(2013, 10, 27, 1, 0, 0, tzinfo=LocalTZ())
print datetime.datetime(2013, 10, 27, 1, 59, 59, tzinfo=LocalTZ())


# The following datetime is ambigous, as 02:00 can be either DST or standard
# time. (It is interpreted as standard time.)
print datetime.datetime(2013, 10, 27, 2, 0, 0, tzinfo=LocalTZ())

避免非标准模块(似乎是 datetime 模块缺少的一种方法) :

from datetime import datetime
utcOffset_min = int(round((datetime.now() - datetime.utcnow()).total_seconds())) / 60   # round for taking time twice
utcOffset_h = utcOffset_min / 60
assert(utcOffset_min == utcOffset_h * 60)   # we do not handle 1/2 h timezone offsets


print 'Local time offset is %i h to UTC.' % (utcOffset_h)

基于 Thoku 上面的答案,这里有一个将时区分解为最接近半小时的答案(这与一些时区相关,如南澳大利亚) :

from datetime import datetime
round((round((datetime.now()-datetime.utcnow()).total_seconds())/1800)/2)

将日志文件中的 UTC 时间戳与本地时间戳进行比较。

它是一种可移植的 很难在当地时区找到 Olson TZ 的名字。幸运的是,您不需要它来执行比较。

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

from datetime import datetime


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


tz = get_localzone()
local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc) #NOTE: utc.normalize() is unnecessary here

与迄今为止提出的其他解决方案不同,上述代码避免了以下问题:

  • local time can be ambiguous i.e., a precise comparison might be impossible for some local times
  • Utc 偏移量对于过去日期的相同本地时区名称可能不同。一些支持时区感知的日期时间对象(例如,dateutil)的库没有考虑到这一点

注意: 要从一个初始的 datetime 对象中获取时区感知的 datetime 对象,应该使用 *:

local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None)

而不是:

#XXX fails for some timezones
local_dt = datetime(2010, 4, 27, 12, 0, 0, 0, tzinfo=tz)

如果给定的本地时间不明确或不存在,则 is_dst=None强制执行异常。

如果确定所有本地时间戳对本地时区使用相同(当前) utc 偏移量,那么可以只使用 stdlib 执行比较:

# convert a naive datetime object that represents time in local timezone to epoch time
timestamp1 = (datetime(2010, 4, 27, 12, 0, 0, 0) - datetime.fromtimestamp(0)).total_seconds()


# convert a naive datetime object that represents time in UTC to epoch time
timestamp2 = (datetime(2010, 4, 27, 9, 0) - datetime.utcfromtimestamp(0)).total_seconds()

timestamp1timestamp2可以直接比较。

注:

  • timestamp1公式只有当时刻的 UTC 偏移量(datetime.fromtimestamp(0))与现在相同时才有效
  • fromtimestamp() creates a naive datetime object in the current local timezone
  • utcfromtimestamp()以 UTC 格式创建一个初始日期时间对象。

我也在问自己同样的问题,我在1中找到了答案:

看看第8.1.7节: strftime 的格式“% z”(小写的 Z 大写字母也返回时区,但不是4位数字格式,而是以时区缩写的形式,如[3])返回“ +/-4DIGIT”格式,这是电子邮件标题的标准格式(参见 RFC 2822的3.3节,参见[2] ,它废除了为电子邮件标题指定时区的其他方式)。

因此,如果希望时区采用这种格式,请使用:

time.strftime("%z")

[1] http://docs.python.org/2/library/datetime.html

[2] https://www.rfc-editor.org/rfc/rfc2822#section-3.3

[3]时区缩写: http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations,仅供参考。

下面是一种仅使用标准库获取本地时区的方法(只适用于 * nix 环境) :

>>> '/'.join(os.path.realpath('/etc/localtime').split('/')[-2:])
'Australia/Sydney'

您可以使用它来创建 pytz时区:

>>> import pytz
>>> my_tz_name = '/'.join(os.path.realpath('/etc/localtime').split('/')[-2:])
>>> my_tz = pytz.timezone(my_tz_name)
>>> my_tz
<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD>

... 然后你可以应用到 datetime:

>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059)


>>> now.replace(tzinfo=my_tz)
>>> now
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059, tzinfo=<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD>)

首先获得 pytz 和 tzlocal 模块

pip install pytz tzlocal

那么

from tzlocal import get_localzone
local = get_localzone()

然后你就可以做

from datetime import datetime
print(datetime.now(local))

来自 约会的 tzlocal 。

Code example follows. Last string suitable for use in filenames.

>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> str(datetime.now(tzlocal()))
'2015-04-01 11:19:47.980883-07:00'
>>> str(datetime.now(tzlocal())).replace(' ','-').replace(':','').replace('.','-')
'2015-04-01-111947-981879-0700'
>>>

首先,注意这个问题提供了一个有意识的 datetime 对象的不正确初始化:

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0,
...                                  tzinfo=pytz.timezone('Israel'))

通过计算结果对象的 UTC 偏移量可以看出问题:

>>> print(local_time.utcoffset())
2:21:00

(注意结果是一个小时的奇数分数。)

要使用 pytz 正确地初始化感知日期时间,应该使用 localize()方法,如下所示:

>>> local_time=pytz.timezone('Israel').localize(datetime.datetime(2010, 4, 27, 12))
>>> print(local_time.utcoffset())
3:00:00

现在,如果您需要一个本地 pytz 时区作为新的 tzinfo,那么您应该使用 tzlocal 包,正如其他人所解释的那样,但是如果您所需要的只是一个具有正确的本地时区偏移量和缩写的实例,然后从 Python 3.3开始,那么您可以调用没有参数的 astimezone()方法来将一个可感知的 datetime实例转换为您的本地时区:

>>> local_time.astimezone().strftime('%Y-%m-%d %H:%M %Z %z')
'2010-04-27 05:00 EDT -0400'

在 Python 3. x 中,本地时区可以这样计算:

import datetime
LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo

这是 datetime密码的一个棘手的使用。

For python < 3.6, you'll need

import datetime
LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone(datetime.timedelta(0))).astimezone().tzinfo

基于 J.F.塞巴斯蒂安的回答,你可以使用标准库:

import time, datetime
local_timezone = datetime.timezone(datetime.timedelta(seconds=-time.timezone))

测试在3.4,应该工作在3.4 +

下面是@vbem 的解决方案的一个略微简洁的版本:

from datetime import datetime as dt


dt.utcnow().astimezone().tzinfo

唯一的实质性区别是我用 datetime.datetime.utcnow()代替了 datetime.datetime.now(datetime.timezone.utc)。为了简洁起见,我还将 datetime.datetime别名为 dt

就我的目的而言,我希望 UTC 偏移量以秒为单位:

dt.utcnow().astimezone().utcoffset().total_seconds()
now_dt = datetime.datetime.now()
utc_now = datetime.datetime.utcnow()
now_ts, utc_ts = map(time.mktime, map(datetime.datetime.timetuple, (now_dt, utc_now)))
offset = int((now_ts - utc_ts) / 3600)

希望这个能帮到你。

你可能对 钟摆感到满意

>>> pendulum.datetime(2015, 2, 5, tz='local').timezone.name
'Israel'

钟摆有一个设计良好的 API 来操作日期。所有的东西都是 TZ 感知的。

我还一直在寻找一种简单的方法来读取本地主机配置,并根据它获取可识别时区的 local _ time。在 python 3.6 + 中,最简单的方法是使用 dateutil.tz,它将读取 /etc/localtime并帮助获得可以识别时区的 datetime 对象。

这里有更多的信息: https://dateutil.readthedocs.io/en/stable/tz.html

完成您所期望的任务的实现如下:

from datetime import datetime
from dateutil import tz
local_time = datetime.now(tz.gettz())

这将为您提供以下当地时间:

2019-10-18 13:41:06.624536-05:00

我在研究这个主题时使用的其他资源: Paul Ganssle Presentation about time zones: Https://www.youtube.com/watch?v=l4uckco9fwy

pytz: The Fastest Footgun in the West Https://blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html

使用标准 libs,下面的代码似乎适用于3.7 + 版本:

from datetime import timedelta
from datetime import timezone
import time


def currenttz():
if time.daylight:
return timezone(timedelta(seconds=-time.altzone),time.tzname[1])
else:
return timezone(timedelta(seconds=-time.timezone),time.tzname[0])

我想将日志文件中的 UTC 时间戳与本地时间戳进行比较

如果这是您的意图,那么我就不用担心指定特定的 tzinfo 参数或任何其他外部库。自 Python 3.5以来,只需要内置的 datetime 模块就可以自动创建 UTC 和本地时间戳。

import datetime
f = "%a %b %d %H:%M:%S %Z %Y"         # Full format with timezone


# tzinfo=None
cdatetime = datetime.datetime(2010, 4, 27, 12, 0, 0, 0)  # 1. Your example from log
cdatetime = datetime.datetime.now()   # 2. Basic date creation (default: local time)
print(cdatetime.strftime(f))          # no timezone printed
# Tue Apr 27 12:00:00  2010


utctimestamp = cdatetime.astimezone(tz=datetime.timezone.utc)  # 1. convert to UTC
utctimestamp = datetime.datetime.now(tz=datetime.timezone.utc) # 2. create in UTC
print(utctimestamp.strftime(f))
# Tue Apr 27 17:00:00 UTC 2010


localtimestamp = cdatetime.astimezone()               # 1. convert to local [default]
localtimestamp = datetime.datetime.now().astimezone()  # 2. create with local timezone
print(localtimestamp.strftime(f))
# Tue Apr 27 12:00:00 CDT 2010

Strftime ()的“% Z”参数将时区缩写打印到时间戳中供人阅读。

要创建一个 ISO 格式的字符串,该字符串使用以色列本地时区的 ISO 表示形式 包括(+04:00) :

以色列的服务器上:

>>> datetime.now(datetime.now().astimezone().tzinfo).isoformat()
'2021-09-07T01:02.030042+04:00'

这将创建一个“时区感知”日期对象,该对象将与 UTC 或本地时间中的任何其他日期时间对象进行适当的比较。但是如果你像我一样在旧金山的服务器上同时运行这个程序,时区 ISO 表示(以及日期/时间字符串本身)会发生变化:

美国加州旧金山(Pacific)的服务器上:

>>> datetime.now(datetime.now().astimezone().tzinfo).isoformat()
'2021-09-06T14:01:02.030042-07:00'

在这两种情况下,datetime对象将彼此兼容。所以如果你减去它们,你会得到一个0的时间差:

在 Python 3.6 + 的 任何地方服务器上:

>>> (datetime.fromisoformat('2021-09-06T14:01:02.030042-07:00') -
...  datetime.fromisoformat('2021-09-07T01:01:02.030042+04:00'))
datetime.timedelta(0)