python将本地时间string转换为UTC时代时间戳
我有YMD hms格式的string,有时区被剥离。 但是我知道他们是在东部夏令时的。
我正在尝试将它们转换为UTC时间的纪元时间戳。
我写了下面的函数:
def ymdhms_timezone_dst_to_epoch(input_str, tz="US/Eastern"): print(input_str) dt = datetime.datetime.fromtimestamp(time.mktime(time.strptime(input_str,'%Y-%m-%d %H:%M:%S'))) local_dt = pytz.timezone(tz).localize(dt) print(local_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z')) utc_dt = local_dt.astimezone(pytz.utc) print(utc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z')) e = int(utc_dt.strftime("%s")) print(e) return e Given string `2015-04-20 21:12:07` this prints: 2015-04-20 21:12:07 2015-04-20 21:12:07 EDT-0400 #<- so far so good? 2015-04-21 01:12:07 UTC+0000 #<- so far so good? 1429596727
这看起来不错,直到时代的时间戳。 但http://www.epochconverter.com/epoch/timezones.php?epoch=1429596727说,它应该毛格林威治标准时间Apr 21 2015 06:12:07 UTC。
哪里不对?
我有YMD hms格式的string,有时区被剥离。 但是我知道他们是在东部夏令时的。
便携的方法是使用pytz
:
#!/usr/bin/env python from datetime import datetime import pytz # $ pip install pytz naive_dt = datetime.strptime('2015-04-20 21:12:07', '%Y-%m-%d %H:%M:%S') tz = pytz.timezone('US/Eastern') eastern_dt = tz.normalize(tz.localize(naive_dt)) print(eastern_dt) # -> 2015-04-20 21:12:07-04:00
我正在尝试将它们转换为UTC时间的纪元时间戳。
timestamp = (eastern_dt - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds() # -> 1429578727.0
请参阅在Python中将datetime.date转换为UTC时间戳 。
你的代码有多个问题:
-
time.mktime()
可能会返回错误的结果,导致模糊的input时间(50%几率),例如,在“回退”DST在秋季转换期间 -
time.mktime()
和datetime.fromtimestamp()
可能无法访问系统上的历史时区数据库(特别是Windows) -
localize(dt)
可能返回一个错误的结果模糊或不存在的时间,即在DST转换期间。 如果您知道时间对应于夏令时,则使用is_dst=True
。 这里需要tz.normalize()
来调整input中可能存在的不存在的时间 -
utc_dt.strftime("%s")
不可移植,它不尊重tzinfo对象 。 它将input解释为本地时间,即,除非您的本地时区是UTC,否则它会返回错误的结果。
我可以随时设置is_dst = True吗?
如果您不介意在模糊或不存在的时间内得到不准确的结果,例如,在美国/纽约时区的秋季有DST转换:
>>> from datetime import datetime >>> import pytz # $ pip install pytz >>> tz = pytz.timezone('America/New_York') >>> ambiguous_time = datetime(2015, 11, 1, 1, 30) >>> time_fmt = '%Y-%m-%d %H:%M:%S%z (%Z)' >>> tz.localize(ambiguous_time).strftime(time_fmt) '2015-11-01 01:30:00-0500 (EST)' >>> tz.localize(ambiguous_time, is_dst=False).strftime(time_fmt) # same '2015-11-01 01:30:00-0500 (EST)' >>> tz.localize(ambiguous_time, is_dst=True).strftime(time_fmt) # different '2015-11-01 01:30:00-0400 (EDT)' >>> tz.localize(ambiguous_time, is_dst=None).strftime(time_fmt) Traceback (most recent call last): ... pytz.exceptions.AmbiguousTimeError: 2015-11-01 01:30:00
时钟在2a点转回 在十一月的第一个星期天 :
is_dst
消歧标志可能有三个值:
-
False
– 默认,假定冬天的时候 -
True
– 假定夏天 -
None
– 提出不明确/不存在时间的例外。
对于现有的唯一本地时间, is_dst
值将被忽略。
以下是来自PEP 0495 – 本地时间消歧的图表,说明了DST转换:
当地时间重复两次(夏季 – 折叠前,冬季时间 – 之后)。
为了能够自动消除当地时间,您需要一些额外的信息,例如,如果您阅读了一系列当地时间,那么它可能会帮助您,如果您知道它们sorting: 本地时间parsing订单时间戳(UTC)夏令时 。
首先'%s'
在所有平台上都不被支持,其实际上是为你工作的,因为你的平台C库的strftime()
函数(由Python调用)支持它。 这个函数是最可能导致这个问题的原因,我猜测它不是时区感知的,因此当与时代有所不同时,它使用的是当地的时区,这很可能是EST(?)
我不相信依赖只能在less数平台上运行的'%s'
(我相信),你应该手动减去从epoch( 1970/1/1 00:00:00
)得到的date时间,时代。 示例 –
e = (utc_dt - datetime.datetime(1970,1,1,0,0,0,tzinfo=pytz.utc)).total_seconds()
演示 –
>>> (utc_dt - datetime.datetime(1970,1,1,0,0,0,tzinfo=pytz.utc)).total_seconds() 1429578727.0
这正确对应于你得到的date。
我不完全知道为什么,但在使用%s
打印之前,必须从utc_dt
删除时区信息。
e = int(utc_dt.replace(tzinfo=None).strftime("%s")) print(e) return e