python将本地时间的字符串转换为UTC纪元时间戳

时间:2015-09-22 18:04:36

标签: python datetime

我有YMD hms格式的字符串,其中删除了时区。但我知道他们在东部时间有夏令时。

我正在尝试将它们转换为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说它应该适合 格林威治标准时间2015年4月21日06:12:07 UTC。

有什么问题?

3 个答案:

答案 0 :(得分:3)

  

我有YMD hms格式的字符串,其中删除了时区。但我知道他们在东部时间有夏令时。

便携式方法是使用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

请参阅Converting datetime.date to UTC timestamp in Python

您的代码中存在多个问题:

  • time.mktime()可能会因模糊输入时间(50%几率)而返回错误的结果,例如,在&#34;退回&#34;秋季DST过渡

  • time.mktime()datetime.fromtimestamp()如果无法访问系统上的历史时区数据库(特别是Windows),则过去/未来日期可能会失败

  • localize(dt)可能会为模糊或不存在的时间返回错误的结果,即在DST转换期间。如果您知道时间对应于夏令时,请使用is_dst=True。此处需要tz.normalize(),以便在输入中调整可能的不存在时间

  • utc_dt.strftime("%s") is not portable and it does not respect tzinfo object。它将输入解释为本地时间,即除非您的本地时区是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

时钟被转回at 2a.m. on the first Sunday in November

clocks are turned back

is_dst消歧标志可能有三个值:

  • False - 默认,假设冬令时
  • True - 假设夏令时
  • None - 针对模糊/不存在的时间提出异常。
现有的唯一本地时间忽略

is_dst值。

这是来自PEP 0495 -- Local Time Disambiguation的情节,用于说明DST过渡: utc vs. local time in the fold

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

为了能够自动消除当地时间的歧义,您需要一些额外的信息,例如,如果您阅读了一系列当地时间,那么如果您知道它们已排序,则可能会有所帮助:Parsing of Ordered Timestamps in Local Time (to UTC) While Observing Daylight Saving Time

答案 1 :(得分:2)

首先,所有平台都不支持locList="123 789" for i in $locList; do awk -vvar=$i '$2 ~ var{print $4, $5}' file; done ,它实际上适合您,因为您的平台C库的'%s'函数(由Python调用)支持它。这个函数最有可能引起这个问题,我猜它不是时区感知的,因此当从时间段上获取差异时它正在使用你的本地时区,这很可能是EST(?)

你应该手动减去从纪元(strftime())获得的日期时间,而不是依赖'%s',它只适用于少数几个平台(我认为是linux),以获得自纪元以来的实际秒数。示例 -

1970/1/1 00:00:00

演示 -

e = (utc_dt - datetime.datetime(1970,1,1,0,0,0,tzinfo=pytz.utc)).total_seconds()

这正确对应于您获得的日期时间。

答案 2 :(得分:0)

我不确切知道原因,但您必须先从utc_dt删除时区信息,然后再使用%s进行打印。

e = int(utc_dt.replace(tzinfo=None).strftime("%s"))
print(e)
return e