Python:C# 二进制日期编码

3

我需要从二进制文件中提取金融价格数据。通常使用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#代码是:

提取它的正确的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模块,但是对它有一些顾虑。

  1. 我不确定C#代码中的哪些格式字符对应于Int32和Int64,尽管尝试了几种不同的方法,但返回的Python元组相同。

  2. 我感到担忧的是,某些字段的输出似乎对我指定的格式不太敏感:例如,如果我将TotalTrades字段指定为signed或unsigned int或signed或unsigned long(l、L、i或I),则返回的值相同。

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


你能发布C#读取器类的源代码吗? - dtb
2个回答

3
据我所知,.net时间戳是自0001-01-01T00:00:00Z起以tick为单位计算的,其中一个tick等于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字段指定为signed或unsigned int或signed或unsigned long(l,L,i或I),则返回的金额相同”,它们不敏感是因为(1)“long”和“int”意思相同(32位),以及(2)所有可能的无符号数字的较小一半与有符号数字具有相同的表示形式。例如,在8位数字中,数字0到127(含)具有相同的比特模式,无论是有符号还是无符号。

谢谢你关于有符号/无符号整数的解释。我之前并不是很清楚,但现在我相当确定应该使用无符号整数,因为总交易量永远不应该是负数。 - Arthur Dent

0

在没有看到包含 ReadInt32ReadDoubleReadDateTime 等方法的 C# 源代码之前,很难给出明确的答案,但是...

  1. 我不确定il格式字符之间的区别,但我认为你在使用i/l来表示Int32q来表示Int64是正确的。

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

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

    如果是这样,那么序列化值将是从0001年1月1日00:00:00起计算的滴答数--即100纳秒间隔的数量。

    按照这个计算方式,您问题中显示的值 -- 634124502600000000 -- 将代表2010年6月18日9:31:00


i/I和l/L分别用于带符号/无符号int和long。感谢回复。 - Arthur Dent
@Arthur:我的意思是我不确定il之间的区别(它们都被描述为有符号32位整数),或者IL之间的区别(它们都被描述为无符号32位整数)。我猜这种命名方式是对C/C++的回溯,因为int和long的大小取决于实现,但就struct模块而言,它们似乎完全相同。 - LukeH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接