将JSON时间戳字符串转换为pandas dataframe中的python日期

时间:2014-10-22 17:35:03

标签: python json datetime pandas

我有一个我从JSON读过的pandas数据帧,一个日期列是一个奇怪的时间戳格式,如下所示

  

" /日期(1405961743000 + 0100)/"

。如何将整个列转换为python日期?

我已经能够通过在前10个数字fromtimestamp上使用日期时间datetime.datetime.fromtimestamp(1405961743)函数手动将该日期转换为python日期,但我很难转换整个列。

我猜我需要从每个条目中选择适当的数字,转换为整数,然后使用fromtimestamp函数,但我是python(和pandas)的新手,所以我很难做到这一点。

任何帮助都将不胜感激。

由于

3 个答案:

答案 0 :(得分:1)

显然,如果你知道JSON的来源会更好,并且可以查看文档/询问作者/等。知道该日期格式背后的实际意图。 (它甚至可能由Python代码生成,使用您可以自己使用的库...)

但是看看这些数字,我可以很好地猜测这意味着什么:1405961743000是自Unix时代以来的毫秒(这解释了为什么你可以使用它的前10位数字作为自Unix以来的秒数时代,至少在2014年左右的相当宽的范围内),+0100是GMT的时区偏移,格式为+HHMM

因此,您不想提取前10个数字,转换为int,并调用fromtimestamp,而是要将所有内容提取到+-,转换为int除以1000,然后调用fromtimestamp。虽然你给我们的唯一例子碰巧有0毫秒的事实意味着他们都很有可能,在这种情况下,这种差异无关紧要......

无论如何,由您决定如何处理时区偏移。你想知道当地的日期时间吗? GMT日期时间?天真的当地日期?它们很容易从时间戳和偏移量中获得(虽然“意识到”意味着使用像GMT-05:00这样的假时区,当然没有任何历史或DST信息),但你必须决定你想要哪一个。


无论您最终做什么,您可能需要考虑扩展JSON解码器以使其自动化,如the docs中的示例所示。 (与正则表达式r'/Date\((\d+)([+-]\d{4})\)/'匹配的任何字符串,第一组是时间戳,第二组是偏移量。)

但也许不是。特别是因为parse_string似乎没有被覆盖,至少从3.4开始,所以看起来你必须对其进行单一操作。见this code我拍了一下作为概念证明;你可能能够做得更好一点,但是如果他们没有为它提供一个钩子,那么你可以做得多清洁是有限制的。


PS,如果你自己一直在扩展JSON,你可能想要考虑一种更标准化和自我记录的方式来做到这一点。 json模块文档中显示的dict格式,您可以有效地指定要调用的构造函数和传递它的参数,这对于人们弄清楚(以及添加钩子)来说要容易得多。或者,或者,有一种准标准的方式将YAML格式编码为JSON格式,YAML是可扩展的(并且已经具有标准时间戳扩展名)。

答案 1 :(得分:1)

我最近不得不解决同样的问题。幸运的是,我找到了这篇文章,并设法调整了该解决方案以格式化来自 MS Project Online 的基于 OData 的 API 的 JSON 文件中的所有日期。非常感谢@abarnert@jfs!这是我使用的代码:

    from datetime import datetime, timedelta, timezone
    import re
    
    
    def ms_to_timestamp(ticks: str, offset: str, date_format: str = "%Y-%m-%d %H:%M:%S") -> str:
        epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
        utc_dt = epoch + timedelta(milliseconds=int(ticks))
        timestamp = utc_dt.strftime(date_format)
    
        if offset:
            offset = int(offset)
            hours, minutes = divmod(abs(offset), 100)
    
            if offset < 0:
                hours, minutes = -hours, -minutes
    
            dt = utc_dt.astimezone(timezone(timedelta(hours=hours, minutes=minutes)))
            timestamp = dt.strftime(date_format)
    
        return timestamp
    
    
    def format_datetime(string: str) -> str:
        dates = re.findall(r'Date\((\d+)([+-]\d{4})?\)', string)
    
        for d in dates:
            timestamp = ms_to_timestamp(ticks=d[0], offset=d[1])
            string = string.replace(f"/Date({d[0]}{d[1]})/", timestamp)
    
        return string
    
    
    if __name__ == '__main__':
        text = "example 1: /Date(1615885200000)/ ; example 2: /Date(1405961743000+0100)/"
        new_text = format_datetime(text)
        print(f"Before: {text}\nAfter: {new_text}")

答案 2 :(得分:0)

时间字符串为OData version 2 JSON verbose format for Datetime

  

“/Date(<ticks>[“+” | “-” <offset>])/”
  <ticks> =毫秒数   自1970年1月1日午夜起   <offset> =要添加的分钟数或   减去

作为@Matt Johnson mentions格式可以在ASP.NET或WCF应用程序中看到。

#!/usr/bin/env python3
import re
from datetime import datetime, timedelta, timezone

time_string = "/Date(1405961743000+0100)/"
epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
ticks, offset = re.match(r'/Date\((\d+)([+-]\d{4})?\)/$', time_string).groups()
utc_dt = epoch + timedelta(milliseconds=int(ticks))
print(utc_dt, utc_dt.strftime('%Z'))
if offset:
   offset = int(offset)
   # http://www.odata.org/documentation/odata-version-2-0/json-format
   # says offset is minutes (an error?)
   dt = utc_dt.astimezone(timezone(timedelta(minutes=offset)))
   print(dt, dt.strftime('%Z'))
   # but it looks like it could be HHMM
   hours, minutes = divmod(abs(offset), 100)
   if offset < 0:
      hours, minutes = -hours, -minutes
   dt = utc_dt.astimezone(timezone(timedelta(hours=hours, minutes=minutes)))
   print(dt, dt.strftime('%Z'))

Output

2014-07-21 16:55:43+00:00 UTC+00:00
2014-07-21 18:35:43+01:40 UTC+01:40
2014-07-21 17:55:43+01:00 UTC+01:00

看起来应该忽略odata.org文档,并且应将偏移量视为HHMM格式。