【问题标题】:python: c# binary datetime encodingpython: c# 二进制日期时间编码
【发布时间】:2011-03-11 07:35:45
【问题描述】:

我需要从二进制文件中提取金融价格数据。此价格数据通常由一段 C# 代码提取。我遇到的最大问题是获得有意义的日期时间。

二进制数据如下所示:

'\x14\x11\x00\x00{\x14\xaeG\xe1z(@\x9a\x99\x99\x99\x99\x99(@q=\n\xd7\xa3p(@\x9a\x99\x99\x99\x99\x99(@\xac\x00\x19\x00\x00\x00\x00\x00\x08\x01\x00\x00\x00"\xd8\x18\xe0\xdc\xcc\x08'

正确提取出来的C#代码是:

StockID = reader.ReadInt32();
Open = reader.ReadDouble();
High = reader.ReadDouble();
Low = reader.ReadDouble();
Close = reader.ReadDouble();
Volume = reader.ReadInt64();
TotalTrades = reader.ReadInt32();
Timestamp = reader.ReadDateTime();

这就是我在 python 中得到的地方。我对此有一些担忧。

In [1]: barlength = 56; barformat = 'i4dqiq'
In [2]: pricebar = f.read(barlength)
In [3]: pricebar
Out[3]: '\x95L\x00\x00)\\\x8f\xc2\xf5\xc8N@D\x1c\xeb\xe26\xcaN@\x7fj\xbct\x93\xb0N@\xd7\xa3p=\n\xb7N@\xf6\xdb\x02\x00\x00\x00\x00\x00J\x03\x00\x00\x00"\xd8\x18\xe0\xdc\xcc\x08'
In [4]: struct.unpack(barformat, pricebar)
Out[4]: 
(19605,                # stock id
 61.57,                # open
 61.579800000000006,   # high
 61.3795,              # low
 61.43,                # close
 187382,               # volume -- seems reasonable
 842,                  # TotalTrades -- seems reasonable
 634124502600000000L   # datetime -- no idea what this means!
)

我使用了python内置的struct module,但有些担心。

  1. 我不确定 C# 代码中的 Int32 和 Int64 对应的格式字符是什么,尽管多次尝试返回相同的 python 元组。

  2. 我很担心,因为某些字段的输出似乎对我指定的格式不是很敏感:例如,如果我将 TotalTrades 字段指定为已签名or unsigned int OR signed or unsigned long (l, L, i, or I)

  3. 我无法理解日期返回字段。这其实是我最大的问题。

【问题讨论】:

  • 能贴出C#阅读器类的源码吗?

标签: c# python binary


【解决方案1】:

据我所知,.net 时间戳是自 0001-01-01T00:00:00Z 以来的滴答声,其中滴答声为 100 纳秒。所以:

>>> x = 634124502600000000
>>> secs = x / 10.0 ** 7
>>> secs
63412450260.0
>>> import datetime
>>> delta = datetime.timedelta(seconds=secs)
>>> delta
datetime.timedelta(733940, 34260)
>>> ts = datetime.datetime(1,1,1) + delta
>>> ts
datetime.datetime(2010, 6, 18, 9, 31)
>>>

日期部分是 2010-06-18。您所在的时区与 UTC 相差 9.5 小时吗?如果您要提供两个时间戳值以及预期的答案,那么在验证此计算时会非常有用。

解决您的问题“”“我很担心,因为某些字段的输出似乎对我指定的格式不是很敏感:例如,如果我指定 TotalTrades 字段返回相同的金额as either signed or unsigned int OR signed or unsigned long (l, L, i, or I)""":它们不敏感,因为 (1) "long" 和 "int" 表示相同(32 位)和 (2 ) 所有可能的无符号数中较小的一半具有与有符号数相同的表示。例如,在 8 位数字中,数字 0 到 127(含)具有相同的位模式,无论有符号还是无符号。

【讨论】:

  • 感谢您对有符号/无符号整数的解释。我真的不知道,但现在我相当肯定我应该使用未签名的,因为总交易永远不应该是负数。
【解决方案2】:

如果没有看到包含ReadInt32ReadDoubleReadDateTime 等方法的 C# 源代码,就不可能给出明确的答案,但是...

  1. 我不太确定il 格式字符之间有什么区别,但我认为您在Int32 和@ 中使用i/l 是正确的987654330@ 为Int64

  2. 同样,我不知道 i/lI/L 格式字符之间的区别,但由于它们都表示 32 位整数,因此它们的二进制表示应该是02147483647 之间的所有值都相同。如果TotalTrades 可能为负数或超过2147483647,那么您应该进一步调查。如果没有,请不要担心。

  3. 在我看来,您的序列化日期字段可能等同于 DateTime.Ticks

    如果是这种情况,那么序列化值将是滴答数——即 100 纳秒间隔的数量——因为 00:00:00 上的 1 January 0001

    据此推算,您问题中显示的值 -- 634124502600000000 -- 将代表18 June 2010 上的09:31:00

【讨论】:

  • i/I 和 l/L 分别用于有符号/无符号 int 和 long。感谢您的回复。
  • @Arthur:我的意思是我不确定il(都描述为有符号32 位整数)或IL 之间的区别(两者都描述为无符号 32 位整数)。我猜这个命名是对 C/C++ 的倒退,其中整数和长整数的大小取决于实现,尽管就struct 模块而言,它们似乎完全相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-05
  • 2020-10-13
  • 2013-05-31
  • 2012-08-20
  • 1970-01-01
  • 1970-01-01
  • 2012-07-25
相关资源
最近更新 更多