48

如何将时区感知日期时间对象转换为本地时区的等效非时区感知日期时间?

我的特定应用程序使用 Django(尽管这实际上是一个通用的 Python 问题):

import iso8601

……

date_str="2010-10-30T17:21:12Z"

……

d = iso8601.parse_date(date_str)

foo = app.models.FooModel(the_date=d)
foo.save()

这会导致 Django 抛出错误:

raise ValueError("MySQL backend does not support timezone-aware datetimes.")

我需要的是:

d = iso8601.parse_date(date_str)
local_d = SOME_FUNCTION(d)
foo = app.models.FooModel(the_date=local_d)

SOME_FUNCTION会是什么?

4

4 回答 4

80

一般来说,要将任意时区感知日期时间转换为天真的(本地)日期时间,我会使用该pytz模块并astimezone转换为本地时间,replace并使日期时间天真:

In [76]: import pytz

In [77]: est=pytz.timezone('US/Eastern')

In [78]: d.astimezone(est)
Out[78]: datetime.datetime(2010, 10, 30, 13, 21, 12, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)

In [79]: d.astimezone(est).replace(tzinfo=None)
Out[79]: datetime.datetime(2010, 10, 30, 13, 21, 12)

但由于您的特定日期时间似乎在 UTC 时区,您可以这样做:

In [65]: d
Out[65]: datetime.datetime(2010, 10, 30, 17, 21, 12, tzinfo=tzutc())

In [66]: import datetime

In [67]: import calendar

In [68]: datetime.datetime.fromtimestamp(calendar.timegm(d.timetuple()))
Out[68]: datetime.datetime(2010, 10, 30, 13, 21, 12)

顺便说一句,您最好将日期时间存储为天真的 UTC 日期时间,而不是天真的本地日期时间。这样,您的数据与本地时间无关,并且您仅在必要时转换为本地时间或任何其他时区。有点类似于尽可能使用 unicode,并且仅在必要时进行编码。

因此,如果您同意将日期时间存储在原始 UTC 中是最好的方法,那么您需要做的就是定义:

local_d = d.replace(tzinfo=None)
于 2011-03-27T21:50:31.383 回答
72

在最新版本的 Django(至少 1.4.1)中:

from django.utils.timezone import localtime

result = localtime(some_time_object)
于 2012-08-17T16:09:04.703 回答
3

一个可移植的健壮解决方案应该使用 tz 数据库。要将本地时区作为对象,请使用模块pytz tzinfotzlocal

#!/usr/bin/env python
import iso8601
import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone()
aware_dt = iso8601.parse_date("2010-10-30T17:21:12Z") # some aware datetime object
naive_local_dt = aware_dt.astimezone(local_timezone).replace(tzinfo=None)

注意:使用类似的东西可能很诱人:

#!/usr/bin/env python3
# ...
naive_local_dt = aware_dt.astimezone().replace(tzinfo=None)

但如果本地时区有一个可变的 utc 偏移量,但 python 不使用给定平台上的历史时区数据库,它可能会失败。

于 2015-08-23T07:55:38.887 回答
0

使用python-dateutil您可以解析 iso-8561 格式的日期,dateutil.parsrser.parse()这将使您了解datetimeUTC/祖鲁时区。

使用.astimezone()您可以将其转换为另一个时区的感知日期时间。

使用.replace(tzinfo=None)会将感知日期时间转换为天真的日期时间。

from datetime import datetime
from dateutil import parser as datetime_parser
from dateutil.tz import tzutc,gettz

aware = datetime_parser.parse('2015-05-20T19:51:35.998931Z').astimezone(gettz("CET"))
naive = aware.replace(tzinfo=None)

一般来说,最好的办法是将所有日期转换为 UTC 并以这种方式存储它们,然后根据需要将它们转换回本地。我aware.astimezone(tzutc()).replace(tzinfo=None)用来确保使用 UTC 并转换为天真。

于 2015-09-29T10:04:34.880 回答