将UTC时间转换为纪元时间
我想分析交通流量和天气数据之间的关系。交通数据有一个UNIX时间戳(也叫epoch),但我在把天气数据中的时间戳(在天气数据中)转换成epoch时遇到了麻烦。问题是我在挪威,而天气数据中的UTC时间戳和我的时区(GMT+1)不一样。
我最初的做法
我首先尝试把它转换成epoch,并把数据当作在GMT+1时区来处理。然后我通过减去UTC和GMT+1之间的秒数差来进行补偿。
这个做法的问题
我意识到这个方法非常原始,并且不太优雅(实际上可能只是个丑陋的临时解决方案)。不过,最大的问题是UTC和GMT+1之间的差异并不是固定的(因为夏令时的原因)。
问题
有没有什么可靠的方法可以在Python中把UTC时间转换成UNIX时间戳(考虑到我的机器在GMT+1)?时间戳的格式是:
Y-m-d HH:MM:SS
编辑:尝试了rmunns的解决方案:
def convert_UTC_to_epoch(timestamp):
tz_UTC = pytz.timezone('UTC')
time_format = "%Y-%m-%d %H:%M:%S"
naive_timestamp = datetime.datetime.strptime(timestamp, time_format)
aware_timestamp = tz_UTC.localize(naive_timestamp)
epoch = aware_timestamp.strftime("%s")
return (int) (epoch)
但这并没有正常工作,下面有证据:
#Current time at time of the edit is 15:55:00 UTC on June 9th 2014.
>>> diff = time.time() - convert_UTC_to_epoch("2014-06-09 15:55:00")
>>> diff
3663.25887799263
>>> #This is about an hour off.
4 个回答
你可以使用 time
和 datetime
这两个模块:
import time, datetime
date = "14-05-07 12:14:16" #Change to whatever date you want
date = time.strptime(date, "%y-%m-%d %H:%M:%S")
epoch = datetime.datetime.fromtimestamp(time.mktime(date)).strftime('%s')
这样运行会得到:
>>> import time, datetime
>>> date = "14-05-07 12:14:16"
>>> date = time.strptime(date, "%y-%m-%d %H:%M:%S")
>>> epoch = datetime.datetime.fromtimestamp(time.mktime(date)).strftime('%s')
>>> epoch
'1399490056'
>>>
pytz模块可能会对你有帮助。它让你可以写出像下面这样的代码:
import pytz
import datetime
tz_oslo = pytz.timezone('Europe/Oslo')
time_format = "%Y-%m-%d %H:%M:%S"
naive_timestamp = datetime.datetime(2014, 6, 4, 12, 34, 56)
# Or:
naive_timestamp = datetime.datetime.strptime("2014-06-04 12:34:56", time_format)
aware_timestamp = tz_oslo.localize(naive_timestamp)
print(aware_timestamp.strftime(time_format + " %Z%z"))
这段代码应该会打印出“2014-06-04 14:34:56 CEST+0200”。
请注意pytz手册中的以下内容:
处理时间的推荐方式是始终使用UTC时间,只有在生成供人类阅读的输出时才转换为当地时间。
所以在写代码的时候要记住这一点:只进行一次当地时间的转换,这样在比较两个时间戳时会简单得多。
更新:这里有几个你可能会觉得有用的视频:
- 关于日期时间你需要知道的事,这是Taavi Burns在PyCon 2012上的演讲(30分钟)
- 驾车双重头:日期时间和日志分析,这是一个分为两部分的演讲。(注意:视频中有烦人的嗡嗡声,但我找不到声音更好的版本)。第一部分是我刚才提到的“关于日期时间你需要知道的事”的演讲,第二部分提供了一些解析日志文件和进行有用操作的实用技巧。(50分钟)
更新2:你在更新的问题中提到的convert_UTC_to_epoch()
函数(我在下面重现了)返回的是当地时间,而不是UTC时间:
def convert_UTC_to_epoch(timestamp):
tz_UTC = pytz.timezone('UTC')
time_format = "%Y-%m-%d %H:%M:%S"
naive_timestamp = datetime.datetime.strptime(timestamp, time_format)
aware_timestamp = tz_UTC.localize(naive_timestamp)
epoch = aware_timestamp.strftime("%s")
return (int) (epoch)
问题在于你使用了strftime("%s")
,这个用法没有文档说明,并且返回了错误的结果。Python并不支持%s
这个参数,但它似乎可以工作,因为它被传递给了你系统的strftime()
函数,而这个函数支持%s
参数——但是它返回的是当地时间!你把一个UTC时间戳当作当地时间解析,这就是为什么会差一个小时的原因。(更神秘的是,为什么不是差两个小时——挪威现在不是在夏令时吗?难道你不应该是UTC+2吗?)
从下面的交互式Python会话中可以看到,我在UTC+7时区,而你的convert_UTC_to_epoch()
函数对我来说差了七个小时。
# Current time is 02:42 UTC on June 10th 2014, 09:42 local time
>>> time.timezone
-25200
>>> time.time() - convert_UTC_to_epoch("2014-06-10 02:42:00")
25204.16531395912
>>> time.time() + time.timezone - convert_UTC_to_epoch("2014-06-10 02:42:00")
6.813306093215942
调用strftime("%s")
时,将6月10日的02:42解释为当地时间,这相当于6月9日的19:42 UTC。从6月10日的02:42 UTC(这是time.time()
返回的)减去6月9日的19:42 UTC,结果差了七个小时。有关为什么你永远不应该使用strftime("%s")
的更多细节,请参见将python日期时间转换为epoch与strftime。
(顺便说一下,如果你看到我之前在“更新2”标题下写的内容,声称time.time()
返回的是当地时间,请忽略它——我错了。我最初也被strftime("%s")
的错误所迷惑,就像你一样。)
另外,datetime
这个模块有它自己的 .strptime()
方法。
http://en.wikipedia.org/wiki/Unix_time
Unix 纪元是指1970年1月1日00:00:00(协调世界时,UTC),也可以写作1970-01-01T00:00:00Z,符合ISO 8601标准。
import datetime
unix_epoch = datetime.datetime(1970, 1, 1)
log_dt = datetime.datetime.strptime("14-05-07 12:14:16", "%y-%m-%d %H:%M:%S")
seconds_from_epoch = (log_dt - unix_epoch).total_seconds()
>>> 1399490056.0
解决方法是使用日历模块(灵感来自这里)
>>>#Quick and dirty demo
>>>print calendar.timegm(datetime.datetime.utcnow().utctimetuple()) - time.time()
>>>-0.6182510852813721
下面是转换的函数:
import calendar, datetime, time
#Timestamp is a datetime object in UTC time
def UTC_time_to_epoch(timestamp):
epoch = calendar.timegm(timestamp.utctimetuple())
return epoch