【问题标题】:python converting string in localtime to UTC epoch timestamppython将本地时间的字符串转换为UTC纪元时间戳
【发布时间】:2015-12-19 20:12:41
【问题描述】:

我有 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。

怎么了?

【问题讨论】:

    标签: python datetime


    【解决方案1】:

    我有 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% 的可能性),例如在秋季的“回退”DST 过渡期间

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

    • localize(dt) 可能会在不明确或不存在的时间(即 DST 转换期间)返回错误结果。如果您知道时间对应于夏令时,请使用is_dst=Truetz.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

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

    • False -- 默认,假设是冬季时间
    • True -- 假设是夏季时间
    • None -- 为不明确/不存在的时间引发异常。

    is_dst 值对于现有的唯一当地时间将被忽略。

    这是来自PEP 0495 -- Local Time Disambiguation 的图表,说明了 DST 转换:

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

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

    【讨论】:

    • 我现在正在使用这个答案。但是,您能否详细说明“。如果您知道时间对应于夏令时,则使用 is_dst=True”?我想要一个可以转换所有时间的通用函数,如我的问题所示。我可以一直设置is_dst=True吗?
    • @Tommy:我已经详细说明了is_dst 标志。
    • 只是为了确保我理解:我们在 X 日东部时间晚上 11 点设置时钟到晚上 10 点。所以 [X: 10pm, X:10:59:59] 的所有时间实际上都发生了两次。因此,此间隔中的时间戳是“不明确的”。 is_dst 标志决定了我们如何在这个确切的时间间隔内解决这种歧义。
    • @Tommy:凌晨 2 点(如图所示)时钟拨回一小时,因此凌晨 1 点和凌晨 2 点之间的时间出现两次(代码示例使用凌晨 1:30 -- 在区间的中间)。
    【解决方案2】:

    首先,'%s' 并非在所有平台上都受支持,它实际上对您有用,因为您的平台 C 库的 strftime() 函数(由 Python 调用)支持它。这个函数最有可能是导致问题的原因,我猜它不知道时区,因此当与纪元时间不同时,它使用的是您的本地时区,这很可能是 EST(?)

    您应该手动减去从 epoch (1970/1/1 00:00:00) 获得的日期时间,以获取自 epoch 以来的实际秒数,而不是依赖仅适用于少数平台(我相信是 Linux)的 '%s'。示例 -

    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
    

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

    【讨论】:

    • 我做了return (utc_dt - datetime.datetime.utcfromtimestamp(0)).total_seconds(),是一样的吗?
    • 如果这对你有用,出于某种原因,只有这对我有用 - (utc_dt - datetime.datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc)).total_seconds()。您需要.replace(),因为utcfromtimestamp() 返回一个日期时间,其中tzinfo 设置为None(如documentation 中给出的)
    【解决方案3】:

    我不知道为什么,但您必须先从 utc_dt 中删除时区信息,然后才能使用 %s 进行打印。

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

    【讨论】:

    • 您的当地时间是UTC吗?这对我来说没有任何区别。
    • @AnandSKumar 我的当地时间是美国/东部时间。它在 OS X 上的 python shell 中为我生成了相同的1429578727。这可能是我系统的%s 实现。
    猜你喜欢
    • 1970-01-01
    • 2015-08-08
    • 2019-01-05
    • 2016-07-23
    • 2018-01-27
    • 1970-01-01
    • 1970-01-01
    • 2019-08-15
    • 2017-04-27
    相关资源
    最近更新 更多