Convert a python UTC datetime to a local datetime using only python standard library?
我有一个使用datetime.utcnow()创建并持久化在数据库中的python datetime实例。
为了进行显示,我想使用默认的本地时区(即,如果日期时间是使用datetime.now()创建的),将从数据库中检索到的日期时间实例转换为本地日期时间。
如何仅使用Python标准库(例如,不依赖pytz)将UTC日期时间转换为本地日期时间?
似乎有一种解决方案是使用datetime.astimezone(tz),但是如何获得默认的本地时区?
在python 3.3+中:
1 2 3 4 | from datetime import datetime, timezone def utc_to_local(utc_dt): return utc_dt.replace(tzinfo=timezone.utc).astimezone(tz=None) |
。
在python 2/3中:
1 2 3 4 5 6 7 8 9 | import calendar from datetime import datetime, timedelta def utc_to_local(utc_dt): # get integer timestamp to avoid precision lost timestamp = calendar.timegm(utc_dt.timetuple()) local_dt = datetime.fromtimestamp(timestamp) assert utc_dt.resolution >= timedelta(microseconds=1) return local_dt.replace(microsecond=utc_dt.microsecond) |
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import pytz local_tz = pytz.timezone('Europe/Moscow') # use your local timezone name here # NOTE: pytz.reference.LocalTimezone() would produce wrong result here ## You could use `tzlocal` module to get local timezone on Unix and Win32 # from tzlocal import get_localzone # $ pip install tzlocal # # get local timezone # local_tz = get_localzone() def utc_to_local(utc_dt): local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz) return local_tz.normalize(local_dt) # .normalize might be unnecessary |
。例子
1 2 3 4 5 6 | def aslocaltimestr(utc_dt): return utc_to_local(utc_dt).strftime('%Y-%m-%d %H:%M:%S.%f %Z%z') print(aslocaltimestr(datetime(2010, 6, 6, 17, 29, 7, 730000))) print(aslocaltimestr(datetime(2010, 12, 6, 17, 29, 7, 730000))) print(aslocaltimestr(datetime.utcnow())) |
。产量Python3.3
1 2 3 | 2010-06-06 21:29:07.730000 MSD+0400 2010-12-06 20:29:07.730000 MSK+0300 2012-11-08 14:19:50.093745 MSK+0400 |
Python2
1 2 3 | 2010-06-06 21:29:07.730000 2010-12-06 20:29:07.730000 2012-11-08 14:19:50.093911 |
。吡兹
1 2 3 | 2010-06-06 21:29:07.730000 MSD+0400 2010-12-06 20:29:07.730000 MSK+0300 2012-11-08 14:19:50.146917 MSK+0400 |
注:它考虑了MSK时区的DST和最近的UTC偏移量变化。
我不知道非pytz解决方案是否适用于Windows。
你不能只使用标准库,因为标准库没有任何时区。你需要Pytz或Dateutil。
1 2 3 4 5 6 7 8 9 10 | >>> from datetime import datetime >>> now = datetime.utcnow() >>> from dateutil import tz >>> HERE = tz.tzlocal() >>> UTC = tz.gettz('UTC') The Conversion: >>> gmt = now.replace(tzinfo=UTC) >>> gmt.astimezone(HERE) datetime.datetime(2010, 12, 30, 15, 51, 22, 114668, tzinfo=tzlocal()) |
或者,通过实现自己的时区,您可以在没有pytz或dateutil的情况下完成它。但那是愚蠢的。
我想我知道了:计算出从epoch开始的秒数,然后使用time.localtime转换为本地timzeone,然后将time结构转换回datetime…
1 2 3 4 5 6 7 8 9 | EPOCH_DATETIME = datetime.datetime(1970,1,1) SECONDS_PER_DAY = 24*60*60 def utc_to_local_datetime( utc_datetime ): delta = utc_datetime - EPOCH_DATETIME utc_epoch = SECONDS_PER_DAY * delta.days + delta.seconds time_struct = time.localtime( utc_epoch ) dt_args = time_struct[:6] + (delta.microseconds,) return datetime.datetime( *dt_args ) |
号
它正确应用夏/冬DST:
1 2 3 4 | >>> utc_to_local_datetime( datetime.datetime(2010, 6, 6, 17, 29, 7, 730000) ) datetime.datetime(2010, 6, 6, 19, 29, 7, 730000) >>> utc_to_local_datetime( datetime.datetime(2010, 12, 6, 17, 29, 7, 730000) ) datetime.datetime(2010, 12, 6, 18, 29, 7, 730000) |
你不能用标准库。使用pytz模块,您可以将任何naive/aware日期时间对象转换为任何其他时区。让我们看一些使用python 3的例子。
Naive objects created through class method
utcnow()
号
要将一个幼稚的对象转换为任何其他时区,首先必须将其转换为感知的日期时间对象。可以使用
变量
1 2 3 4 5 6 7 8 9 | import datetime,pytz dtobj1=datetime.datetime.utcnow() #utcnow class method print(dtobj1) dtobj3=dtobj1.replace(tzinfo=pytz.UTC) #replace method dtobj_hongkong=dtobj3.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method print(dtobj_hongkong) |
号
Naive objects created through class method
now()
号
因为
1 2 3 4 5 6 7 | dtobj2=datetime.datetime.now() mytimezone=pytz.timezone("Europe/Vienna") #my current timezone dtobj4=mytimezone.localize(dtobj2) #localize function dtobj_hongkong=dtobj4.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method print(dtobj_hongkong) |
号
基于阿列克谢的评论。这也应该适用于DST。
1 2 3 4 5 6 7 8 | import time import datetime def utc_to_local(dt): if time.localtime().tm_isdst: return dt - datetime.timedelta(seconds = time.altzone) else: return dt - datetime.timedelta(seconds = time.timezone) |
号
标准的python库根本不附带任何
TZINFO类的文档确实提供了一些有用的示例。在本节末尾查找大型代码块。
这是一种糟糕的方法,但它避免了创建定义。它符合基本python3库的要求。
1 2 3 4 5 6 | # Adjust from UST to Eastern Standard Time (dynamic) # df.my_localtime should already be in datetime format, so just in case df['my_localtime'] = pd.to_datetime.df['my_localtime'] df['my_localtime'] = df['my_localtime'].dt.tz_localize('UTC').dt.tz_convert('America/New_York').astype(str) df['my_localtime'] = pd.to_datetime(df.my_localtime.str[:-6]) |
号
这里有另一种方法可以改变datetime格式的时区(我知道我在这上面浪费了精力,但是我没有看到这个页面,所以我不知道怎么做),不需要分秒。因为我的项目不需要它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | def change_time_zone(year, month, day, hour): hour = hour + 7 #<-- difference if hour >= 24: difference = hour - 24 hour = difference day += 1 long_months = [1, 3, 5, 7, 8, 10, 12] short_months = [4, 6, 9, 11] if month in short_months: if day >= 30: day = 1 month += 1 if month > 12: year += 1 elif month in long_months: if day >= 31: day = 1 month += 1 if month > 12: year += 1 elif month == 2: if not year%4==0: if day >= 29: day = 1 month += 1 if month > 12: year += 1 else: if day >= 28: day = 1 month += 1 if month > 12: year += 1 return datetime(int(year), int(month), int(day), int(hour), 00) |
号
我发现最简单的方法是得到你所在位置的时间偏移量,然后从小时中减去它。
1 2 3 4 5 6 7 | def format_time(ts,offset): if not ts.hour >= offset: ts = ts.replace(day=ts.day-1) ts = ts.replace(hour=ts.hour-offset) else: ts = ts.replace(hour=ts.hour-offset) return ts |
号
这对我很有用,在Python3.5.2中。
在Python2和3中工作的简单(但可能有缺陷)方法:
1 2 3 4 5 | import time import datetime def utc_to_local(dt): return dt - datetime.timedelta(seconds = time.timezone) |
。
它的优点是写一个反函数很简单