Python – 将UTCdate时间string转换为本地date时间

我从来不需要将时间转换为utc。 最近有一个请求,让我的应用程序是时区意识,我一直在圈自己运行。 很多关于将本地时间转换为utc的信息,我发现这些信息是相当基本的(也许我也是这么做的),但是我找不到任何有关将utc时间转换为最终用户时区的信息。

简而言之,android应用程序发送给我(appengine应用程序)的数据,并在该数据是一个时间戳。 要将该时间戳存储为utc我正在使用:

datetime.utcfromtimestamp(timestamp) 

这似乎是工作。 当我的应用程序存储数据时,它正在存储为5小时(我是EST -5)

数据被存储在appengine的BigTable中,当被检索出来的时候,就像这样:

 "2011-01-21 02:37:21" 

如何将此string转换为用户正确时区中的DateTime?

另外,用户时区信息的推荐存储空间是什么? (你通常如何储存tz信息,例如:“-5:00”或“EST”等等)?我确定我的第一个问题的答案可能包含第二个答案的参数。

如果您不想提供自己的tzinfo对象,请查看python-dateutil库。 它在zoneinfo(Olson)数据库之上提供了tzinfo实现,以便您可以通过某种规范的名称来引用时区规则。

 from datetime import datetime from dateutil import tz # METHOD 1: Hardcode zones: from_zone = tz.gettz('UTC') to_zone = tz.gettz('America/New_York') # METHOD 2: Auto-detect zones: from_zone = tz.tzutc() to_zone = tz.tzlocal() # utc = datetime.utcnow() utc = datetime.strptime('2011-01-21 02:37:21', '%Y-%m-%d %H:%M:%S') # Tell the datetime object that it's in UTC time zone since # datetime objects are 'naive' by default utc = utc.replace(tzinfo=from_zone) # Convert time zone central = utc.astimezone(to_zone) 

编辑展开的示例以显示strptime用法

编辑2固定的API使用,以显示更好的入口点方法

编辑3包含时区的自动检测方法(Yarin)

请参阅tzinfo对象上的datetime文档。 你必须实现自己想要支持的时区。 在文档的底部是例子。

这是一个简单的例子:

 from datetime import datetime,tzinfo,timedelta class Zone(tzinfo): def __init__(self,offset,isdst,name): self.offset = offset self.isdst = isdst self.name = name def utcoffset(self, dt): return timedelta(hours=self.offset) + self.dst(dt) def dst(self, dt): return timedelta(hours=1) if self.isdst else timedelta(0) def tzname(self,dt): return self.name GMT = Zone(0,False,'GMT') EST = Zone(-5,False,'EST') print datetime.utcnow().strftime('%m/%d/%Y %H:%M:%S %Z') print datetime.now(GMT).strftime('%m/%d/%Y %H:%M:%S %Z') print datetime.now(EST).strftime('%m/%d/%Y %H:%M:%S %Z') t = datetime.strptime('2011-01-21 02:37:21','%Y-%m-%d %H:%M:%S') t = t.replace(tzinfo=GMT) print t print t.astimezone(EST) 

产量

 01/22/2011 21:52:09 01/22/2011 21:52:09 GMT 01/22/2011 16:52:09 EST 2011-01-21 02:37:21+00:00 2011-01-20 21:37:21-05:00a 

这是一个不依赖任何外部库的弹性方法:

 from datetime import datetime import time def datetime_from_utc_to_local(utc_datetime): now_timestamp = time.time() offset = datetime.fromtimestamp(now_timestamp) - datetime.utcfromtimestamp(now_timestamp) return utc_datetime + offset 

这可以避免DelboyJay例子中的时间问题。 埃里克·范·奥斯滕(Erik van Oosten)修正案中的时间问题较less。

作为一个有趣的脚注,上面计算的时区偏移量可能与以下看似等效的expression式有所不同,这可能是由于夏令时规则的变化:

 offset = datetime.fromtimestamp(0) - datetime.utcfromtimestamp(0) # NO! 

更新:这段代码有使用当前时间的UTC偏移量的弱点,这可能与inputdate时间的UTC偏移量不同。 查看有关此答案的其他解决scheme的评论。

为了避开不同的时间,从过去的时间中获取新纪元。下面是我所做的:

 def utc2local (utc): epoch = time.mktime(utc.timetuple()) offset = datetime.fromtimestamp (epoch) - datetime.utcfromtimestamp (epoch) return utc + offset 

如果你想要得到正确的结果,即使对应于一个模糊的本地时间(例如,在DST转换期间)和/或本地utc偏移在当地时区的不同时间是不同的,那么使用pytz时区:

 #!/usr/bin/env python from datetime import datetime import pytz # $ pip install pytz import tzlocal # $ pip install tzlocal local_timezone = tzlocal.get_localzone() # get pytz tzinfo utc_time = datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S") local_time = utc_time.replace(tzinfo=pytz.utc).astimezone(local_timezone) 

如果使用django,则可以使用timezone.localtime方法(请参阅https://docs.djangoproject.com/en/dev/topics/i18n/timezones/ )。

 from django.utils import timezone date # datetime.datetime(2014, 8, 1, 20, 15, 0, 513000, tzinfo=<UTC>) timezone.localtime(date) # datetime.datetime(2014, 8, 1, 16, 15, 0, 513000, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>) 

我传统上推迟到前端 – 从后端发送时间作为UTC的时间戳或其他date时间格式,然后让客户端计算出时区偏移量,并将这些数据呈现在适当的时区。

对于一个web应用程序,这在javascript中很容易实现 – 您可以使用内置方法很容易地找出浏览器的时区偏移量,然后正确地从后端渲染数据。

这是一个快速和肮脏的版本,使用本地系统设置来计算时差。 注意:如果您需要转换为您的当前系统未运行的时区,则这不起作用。我已经在BST时区下的英国设置中对此进行了testing

 from datetime import datetime def ConvertP4DateTimeToLocal(timestampValue): assert isinstance(timestampValue, int) # get the UTC time from the timestamp integer value. d = datetime.utcfromtimestamp( timestampValue ) # calculate time difference from utcnow and the local system time reported by OS offset = datetime.now() - datetime.utcnow() # Add offset to UTC time and return it return d + offset 

您可以使用calendar.timegm将您的时间转换为自Unix纪元和time.localtime以来转换回的time.localtime

 import calendar import time time_tuple = time.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S") t = calendar.timegm(time_tuple) print time.ctime(t) 

给予Fri Jan 21 05:37:21 2011 (因为我在UTC + 03:00时区)。

如果您不想使用除datetime以外的任何其他模块,则此答案应该很有帮助。

datetime.utcfromtimestamp(timestamp)返回一个天真的datetime对象(不是一个意识到的)。 意识到的是时区意识,天真不是。 如果要在时区之间进行转换(例如,在UTC和本地时间之间),则需要知道这一点。

如果你不是一个初始化date的开始,但是你仍然可以在UTC时间创build一个天真的datetime时间对象,你可能想试试这个Python 3.x代码来转换它:

 import datetime d=datetime.datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S") #Get your naive datetime object d=d.replace(tzinfo=datetime.timezone.utc) #Convert it to an aware datetime object in UTC time. d=d.astimezone() #Convert it to your local timezone (still aware) print(d.strftime("%d %b %Y (%I:%M:%S:%f %p) %Z")) #Print it with a directive of choice 

小心不要错误地认为,如果您的时区当前是MDT,那么由于打印MST,所以夏令时对于上面的代码不起作用。 你会注意到,如果你将月份更改为8月份,它将打印MDT。

另一个简单的方法来获得一个知道的datetime对象(也是在Python 3.x中)是创build一个指定的时区开始。 以下是使用UTC的示例:

 import datetime, sys aware_utc_dt_obj=datetime.datetime.now(datetime.timezone.utc) #create an aware datetime object dt_obj_local=aware_utc_dt_obj.astimezone() #convert it to local time #The following section is just code for a directive I made that I liked. if sys.platform=="win32": directive="%#d %b %Y (%#I:%M:%S:%f %p) %Z" else: directive="%-d %b %Y (%-I:%M:%S:%f %p) %Z" print(dt_obj_local.strftime(directive)) 

如果您使用Python 2.x,则可能必须创build子类datetime.tzinfo并使用它来帮助您创build一个有意识的datetime对象,因为datetime.timezone在Python 2.x中不存在。