Python:如何获得datetime.today()是“时区感知”的值?

我想从datetime.today()的值中减去一个date值来计算多久以前。 但它抱怨说:

 TypeError: can't subtract offset-naive and offset-aware datetimes 

datetime.today()似乎不是“时区意识”,而我的其他date值是。 如何获得datetime.today()值的时区知道? 现在是在当地时间给我的时间,恰好是PST,即UTC-8小时。 最糟糕的情况,有没有办法我可以手动inputdatetime.today()返回的datetime对象的时区值并将其设置为UTC-8? 当然,理想的解决scheme是让它自动知道时区。

在标准库中,没有跨平台的方式来创build感知时区而不创build自己的时区类。

在Windows上,有win32timezone.utcnow() ,但这是pywin32的一部分。 我宁愿build议使用pytz库 ,它拥有大多数时区的最新数据库。

使用本地时区可能非常棘手(请阅读pytz文档!),所以您可能更希望在整个应用程序中使用UTC。 您可以像这样获取当前date/时间:

 import pytz from datetime import datetime datetime.utcnow().replace(tzinfo=pytz.utc) 

请注意, datetime.today()datetime.now()返回的是本地时间,而不是UTC时间,所以向其中应用.replace(tzinfo=pytz.utc)将是不正确的。

另一个好方法是:

 datetime.now(pytz.utc) 

这是有点短,也是一样的。

警告:

不要使用UTC时间以外的任何操作来进行date和时间的操作。 您可能会试图使用不同的时区来进行一些奇特的date时间操作,但是如果不注意,这可能会失败:

尝试:

 d = datetime.datetime.now(pytz.timezone('America/Los_Angeles') >>> datetime.datetime(2017, 9, 14, 22, 18, 51, 892210, tzinfo=<DstTzInfo 'America/Los_Angeles' PDT-1 day, 17:00:00 DST>) # add some days to the date that is in a localized timezone d = d + datetime.datetime.timedelta(days=90) >>> datetime.datetime(2017, 12, 13, 22, 18, 51, 892210, tzinfo=<DstTzInfo 'America/Los_Angeles' PDT-1 day, 17:00:00 DST>) 

这是错误的:应该是:

 >>> datetime.datetime(2017, 12, 13, 21, 18, 51, 892210, tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 17:00:00 DST>) 

由于夏时制的变化。

如果您在UTC时间执行此操作,然后将其转换为本地化时区:

 d = datetime.datetime.now(pytz.UTC) >>> datetime.datetime(2017, 9, 15, 5, 34, 28, 716403, tzinfo=<UTC>) # Add offset in UTC time d = d + datetime.timedelta(days=90) >>> datetime.datetime(2017, 12, 14, 5, 34, 28, 716403, tzinfo=<UTC>) # Cast to local timezone d.astimezone(pytz.timezone('America/Los_Angeles')) >>> datetime.datetime(2017, 12, 13, 21, 34, 28, 716403, tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>) 

你得到正确的结果。

在特定的时区获取当前时间:

 import datetime import pytz my_date = datetime.datetime.now(pytz.timezone('US/Pacific')) 

另一种构build表示当前时间的时区感知date时间对象的方法:

 import datetime import pytz pytz.utc.localize( datetime.datetime.utcnow() ) 

这是一个可以在Python 2和Python 3上运行的stdlib解决scheme:

 from datetime import datetime now = datetime.now(utc) # timezone-aware datetime.utcnow() today = datetime(now.year, now.month, now.day, tzinfo=utc) # midnight 

其中today是一个意识到的date时间实例,表示以UTC开头的一天(午夜),而utc是一个tzinfo对象( 来自文档的示例 ):

 from datetime import tzinfo, timedelta ZERO = timedelta(0) class UTC(tzinfo): def utcoffset(self, dt): return ZERO def tzname(self, dt): return "UTC" def dst(self, dt): return ZERO utc = UTC() 

相关: 在给定UTC时间的几种方法获得午夜(开始一天)的性能比较。
注意:更复杂的是,对于具有不固定的utc偏移量的时区获得午夜 。

在Python 3中,标准库使得它更容易:

 >>> import datetime >>> datetime.datetime.now(datetime.timezone.utc) datetime.datetime(2016, 8, 26, 14, 34, 34, 74823, tzinfo=datetime.timezone.utc) 

如果您想要一个只使用标准库的解决scheme,并且可以在Python 2和Python 3中使用,请参阅JF Sebastien的答案 。

pytz是一个Python库,允许使用Python 2.3或更高版本进行准确的跨平台时区计算。

用stdlib,这是不可能的。

在SO上看到类似的问题。

如果你正在使用Django,你可以设置datenon-tz意识(只有utc)。

在settings.py中注释以下行:

 USE_TZ = True 

以下是使用stdlib生成它的一种方法:

 import time from datetime import datetime FORMAT='%Y-%m-%dT%H:%M:%S%z' date=datetime.strptime(time.strftime(FORMAT, time.localtime()),FORMAT) 

date将存储本地date和UTC偏移量 ,而不是UTC时区的date,所以如果您需要确定在哪个时区生成date,则可以使用此解决scheme。 在这个例子中,在我的当地时区:

 date datetime.datetime(2017, 8, 1, 12, 15, 44, tzinfo=datetime.timezone(datetime.timedelta(0, 7200))) date.tzname() 'UTC+02:00' 

关键是将%z指令添加到表示FORMAT,以指示生成的时间结构的UTC偏移量。 其他表示格式可以在date时间模块文档中查阅

如果您需要UTC时区的date,则可以用time.gmtime()replacetime.localtime()

 date=datetime.strptime(time.strftime(FORMAT, time.gmtime()),FORMAT) date datetime.datetime(2017, 8, 1, 10, 23, 51, tzinfo=datetime.timezone.utc) date.tzname() 'UTC' 

编辑

这只适用于python3 。 z指令在python 2 _strptime.py代码中不可用

为什么不使用dateutil这里描述: http ://joelinoff.com/blog/?p=802

 from dateutil.tz import tzlocal # Get the current date/time with the timezone. now = datetime.datetime.now(tzlocal()) 

utc时区中获取一个可utc时区的date就足以让date扣除工作。

但是如果你想在你当前的时区使用时区感知的date, tzlocal就是要走的路:

 from tzlocal import get_localzone # pip install tzlocal from datetime import datetime datetime.now(get_localzone()) 

PS dateutil有一个类似的function( dateutil.tz.tzlocal )。 但是,尽pipe共享名称,它有一个完全不同的代码基础,这正如JF塞巴斯蒂安所指出的 ,可以给出错误的结果。

如果你得到当前的时间和date在python然后导入date和时间,pytz包python之后,你会得到当前的date和时间,如..

 from datetime import datetime import pytz import time str(datetime.strftime(datetime.now(pytz.utc),"%Y-%m-%d %H:%M:%S%t"))