如何在python中感知不知道的date时区

我需要做什么

我有一个时区不知道的date时间对象,我需要添加一个时区,以便能够与其他时区感知的date时间对象进行比较。 我不想将我的整个应用程序转换为不知道这个传统案例的时区。

我所试过的

首先,展示问题:

Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) [GCC 4.2.1 (Apple Inc. build 5646)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import datetime >>> import pytz >>> unaware = datetime.datetime(2011,8,15,8,15,12,0) >>> unaware datetime.datetime(2011, 8, 15, 8, 15, 12) >>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC) >>> aware datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>) >>> aware == unaware Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't compare offset-naive and offset-aware datetimes 

首先,我试着astimezone:

 >>> unaware.astimezone(pytz.UTC) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: astimezone() cannot be applied to a naive datetime >>> 

这个失败并不奇怪,因为它实际上是在尝试进行转换。 replace看起来像一个更好的select(按Python:如何获得datetime.today()的值是“时区感知”? ):

 >>> unaware.replace(tzinfo=pytz.UTC) datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>) >>> unaware == aware Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't compare offset-naive and offset-aware datetimes >>> 

但是,正如你所看到的,replace似乎设置tzinfo,但不让对象知道。 我正在准备回头去处理inputstring来parsing它之前有一个时区(我使用dateutil进行parsing,如果这很重要),但这似乎令人难以置信的kludgy。

另外,我已经在python 2.6和python 2.7中试过了,结果相同。

上下文

我正在写一些数据文件的parsing器。 有一个旧格式,我需要支持datestring没有时区指示器。 我已经修复了数据源,但是我仍然需要支持传统的数据格式。 遗留数据的一次转换不是用于各种业务BS原因的选项。 虽然一般来说,我不喜欢硬编码默认时区的想法,在这种情况下,它似乎是最好的select。 我有充分的信心知道所有有问题的遗留数据都是UTC,所以我准备接受在这种情况下违约的风险。

一般来说,为了使一个天真的date时间感知,使用本地化的方法 :

 import datetime import pytz unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0) aware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC) now_aware = pytz.utc.localize(unaware) assert aware == now_aware 

对于UTC时区,由于没有夏令时计算来处理,所以不需要使用localize

 now_aware = unaware.replace(tzinfo=pytz.UTC) 

作品。 ( .replace返回一个新的date时间;它不会unaware修改。)

我曾经从dt_aware到dt_unware

 dt_unaware = dt_aware.replace(tzinfo=None) 

和dt_unware到dt_aware

 from pytz import timezone localtz = timezone('Europe/Lisbon') dt_aware = localtz.localize(dt_unware) 

但之前的回答也是一个很好的解决scheme。

所有这些示例都使用外部模块。 你可以使用datetime模块来达到同样的效果。

 from datetime import datetime from datetime import timezone dt = datetime.now() dt.replace(tzinfo=timezone.utc) print(dt.replace(tzinfo=timezone.utc).isoformat()) '2017-01-12T22:11:31+00:00' 

更less的依赖和没有pytz问题。

注意:如果你想在python3和python2中使用这个,你可以使用这个以及时区导入(UTC编码):

 try: from datetime import timezone utc = timezone.utc except ImportError: #Hi there python2 user class UTC(tzinfo): def utcoffset(self, dt): return timedelta(0) def tzname(self, dt): return "UTC" def dst(self, dt): return timedelta(0) utc = UTC() 

我在Django中使用这个语句将一个不知道的时间转换为一个意识到的:

 from django.utils import timezone dt_aware = timezone.make_aware(dt_unaware, timezone.get_current_timezone()) 

这编纂了@Sérgio和@ unutbu的答案 。 它只会与pytz.timezone对象或IANA时区string“正常工作”。

 def make_tz_aware(dt, tz='UTC', is_dst=None): """Add timezone information to a datetime object, only if it is naive.""" tz = dt.tzinfo or tz try: tz = pytz.timezone(tz) except AttributeError: pass return tz.localize(dt, is_dst=is_dst) 

这似乎是什么datetime.localize() (或.inform().awarify() )应该做的,同时接受tz参数的string和时区对象,如果没有指定时区,则默认为UTC。

我同意以前的答案,如果您可以以UTC开始,那也没问题。 但是我认为这也是人们使用具有非UTC本地时区date时间的tz aware值的常见情况

如果你只是按名字去做,可能会推断replace()将会适用,并产生正确的date时间感知对象。 不是这种情况。

replace(tzinfo = …)在其行为中似乎是随机的 。 因此是无用的。 不要使用这个!

本地化是正确的function使用。 例:

 localdatetime_aware = tz.localize(datetime_nonaware) 

或者一个更完整的例子:

 import pytz from datetime import datetime pytz.timezone('Australia/Melbourne').localize(datetime.now()) 

给我一个当前的本地时间的时区知晓date时间值:

 datetime.datetime(2017, 11, 3, 7, 44, 51, 908574, tzinfo=<DstTzInfo 'Australia/Melbourne' AEDT+11:00:00 DST>) 

在unutbu的答案的格式; 我做了一个实用程序模块来处理这样的事情,用更直观的语法。 可以用pip来安装。

 import datetime import saturn unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0) now_aware = saturn.fix_naive(unaware) now_aware_madrid = saturn.fix_naive(unaware, 'Europe/Madrid') 

为了添加本地时区; (使用dateutil)

 from dateutil import tz import datetime dt_unaware = datetime.datetime(2017, 6, 24, 12, 24, 36) dt_aware = dt_unaware.replace(tzinfo=tz.tzlocal()) 

我纯粹知道的两种方法

 from datetime import datetime import pytz naive = datetime.now() aware = naive.replace(tzinfo=pytz.UTC) 

要么

 aware = pytz.UTC.localize(naive) 

当然,你可以使用任何时区而不是UTC,