最近项目进行开发时,接收到一个时间字符串,需要把这个时间字符串转换成指定时区的时间,并计算出纪元时间。找了很多资料文档,介绍的虽然都比较详细,但是不符合我的需求,而且同一个点介绍的情况不一样,觉得有些混乱。经过大量资料查阅并亲自实际操作后终于实现了,这里做一下记录。
参考资料:How To Convert Non-UTC Timestamp Into UNIX Epoch Time In Python
这里分两种情况:1、服务器默认时区和目标时区一致;2、服务器默认时区和目标时区不一致。
1、服务器默认时区与目标时区一致的场合:
这种场合下就没必要去转换时区了,先将利用time模块的time.strptime()将时间转换成datetime时间元组,这样就可以直接使用time模块的time.mktime(datetime时间元组),获得纪元时间。
# 将datetime转换成纪元时间
# @param dt datetime时间
# @param format 时间格式
# @return 纪元时间
def __unix_time(dt, format):
try:
# 转换为时间数组
time_arr = time.strptime(dt, format)
# 转换为UNIX时间戳
timestamp = time.mktime(time_arr)
return timestamp
except [OverflowError, ValueError]:
return None
现在来测试一下:
print(__unix_time("2019-07-14 11:23:36", "%Y-%m-%d %H:%M:%S"))
执行结果:
1563074616.0
Process finished with exit code 0
可以使用@在线时间戳转换工具进行计算,计算结果为:1563074616。说明我们的转换是成功的。
2、服务器默认时区和目标时区不一致的场合:
这种场合情况稍微复杂一点,但是不要怕,只要有耐心,什么问题都可以解决的。
如果是在中国,那么使用的时区一般都是北京时间,属于东八区,意思就是与世界标准时区时间(格林威治时间)的偏移量为+8,为了保证正确地转换时区,一般遇到情况,先不管那么多,先把本地时间转换成UTC时间,然后拿到UTC时间转换到指定时区时间,这一定是没问题的。关于时区转换的问题,time模块就显得捉襟见肘了,因此需要使用pytz配合datetime。
但是在使用datetime模块的时候值得注意的是:我们转换为本地时间的时候,需要指定时区,但是,实际上,规定的时区时间偏移是不精确的。比如:北京所在的东八区,按照规定,是偏移+8.00时,但是实际上并不是这样。我们可以通过下面的方法来验证:
这里北京所用的时区名称是:Asia/Shanghai,但是他的时区偏移是+8.06,当我们将本地时间转换成UTC时间后,再将他转回来,这个时候会发现与原来的时间相差了6分钟。这是因为使用datetime.datetime时返回的格式是LMT,这不是而标准格式,当转回的时候返回的格式是标准格式CST,这个过程就损失掉了6分钟,为了解决这个问题,记住使用时区对象tz.localize()方法来进行转换,这样就可以了。
等拿到转换时区后的datetime后,使用time.mktime()就可以取得纪元时间了。
下面直接跟代码:
# 将本地时间转换到指定时区时间,并取得纪元时间
# @param dt_str datetime本地时间
# @param l_timezone 本地时区
# @param t_timezone 目标时区
# @param time_format 入力时间格式
# @return 目标时区纪元时间
def __datetime_to_utc_epoch(dt_str, l_timezone, t_timezone, time_format):
# 本地时区
local_tz = pytz.timezone(l_timezone)
# 目标时区
target_tz = pytz.timezone(t_timezone)
# 将时间转换成datetime元组
dt = datetime.strptime(dt_str, time_format)
# 使用tz.localize()将datetime转换成本地时区时间
dt = local_tz.localize(dt)
# 利用datetime.astimezone(tz=timezone)将本地时间转换成目标时区UTC时间
t_dt_str = str(dt.astimezone(tz=target_tz))[0:19]
print("UTC 时间: {0}".format(t_dt_str))
# 利用好time.mktime()将时间转换成纪元时间
epoch = int(time.mktime(time.strptime(t_dt_str, "%Y-%m-%d %H:%M:%S")))
print("纪元时间: {0}".format(epoch))
现在测试代码:
print("=" * 50)
print("北京时区(东八区)- 东京时区(东九区)")
__datetime_to_utc_epoch("20190714112336", "Asia/Shanghai", "Asia/Tokyo", "%Y%m%d%H%M%S")
print("=" * 50)
print("东京时区(东九区)- 东京时区(东九区)")
__datetime_to_utc_epoch("2019-07-14 11:23:36", "Asia/Tokyo", "Asia/Tokyo", "%Y-%m-%d %H:%M:%S")
运行得到结果:
==================================================
北京时区(东八区)- 东京时区(东九区)
UTC 时间: 2019-07-14 12:23:36
纪元时间: 1563078216
==================================================
东京时区(东九区)- 东京时区(东九区)
UTC 时间: 2019-07-14 11:23:36
纪元时间: 1563074616
Process finished with exit code 0
借助在线转换工具:@国际时区转换 和 @在线时间戳转换工具 进行验证,成功。
下面是整个代码文件:
test_tz.py
import pytz, time
from datetime import datetime
# 将datetime转换成纪元时间
# @param dt datetime时间
# @param format 时间格式
# @return 纪元时间
def __unix_time(dt, format):
try:
# 转换为时间数组
time_arr = time.strptime(dt, format)
# 转换为UNIX时间戳
timestamp = time.mktime(time_arr)
return timestamp
except [OverflowError, ValueError]:
return None
# 将本地时间转换到指定时区时间,并取得纪元时间
# @param dt_str datetime本地时间
# @param l_timezone 本地时区
# @param t_timezone 目标时区
# @param time_format 入力时间格式
# @return 目标时区纪元时间
def __datetime_to_utc_epoch(dt_str, l_timezone, t_timezone, time_format):
# 本地时区
local_tz = pytz.timezone(l_timezone)
# 目标时区
target_tz = pytz.timezone(t_timezone)
# 将时间转换成datetime元组
dt = datetime.strptime(dt_str, time_format)
# 使用tz.localize()将datetime转换成本地时区时间
dt = local_tz.localize(dt)
# 利用datetime.astimezone(tz=timezone)将本地时间转换成目标时区UTC时间
t_dt_str = str(dt.astimezone(tz=target_tz))[0:19]
print("UTC 时间: {0}".format(t_dt_str))
# 利用好time.mktime()将时间转换成纪元时间
epoch = int(time.mktime(time.strptime(t_dt_str, "%Y-%m-%d %H:%M:%S")))
print("纪元时间: {0}".format(epoch))
if __name__ == "__main__":
# print(__unix_time("2019-07-14 11:23:36", "%Y-%m-%d %H:%M:%S"))
print("=" * 50)
print("北京时区(东八区)- 东京时区(东九区)")
__datetime_to_utc_epoch("20190714112336", "Asia/Shanghai", "Asia/Tokyo", "%Y%m%d%H%M%S")
print("=" * 50)
print("东京时区(东九区)- 东京时区(东九区)")
__datetime_to_utc_epoch("2019-07-14 11:23:36", "Asia/Tokyo", "Asia/Tokyo", "%Y-%m-%d %H:%M:%S")