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转换: utc与当地时间的折叠

当地时间重复两次(夏季 – 折叠前,冬季时间 – 之后)。

为了能够自动消除当地时间,您需要一些额外的信息,例如,如果您阅读了一系列当地时间,那么它可能会帮助您,如果您知道它们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