python:C# 二进制日期时间编码

3 投票
2 回答
1624 浏览
提问于 2025-04-16 00: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模块,但对此有一些疑虑。

  1. 我不确定在C#代码中,Int32和Int64对应的格式字符是什么,虽然我尝试了几种不同的方式,返回的Python元组都是一样的。

  2. 我有点担心,因为某些字段的输出似乎对我指定的格式不太敏感:例如,TotalTrades字段无论我把它指定为有符号或无符号的整型,或者有符号或无符号的长整型(l, L, i, 或 I),返回的结果都是一样的。

  3. 我对日期返回字段完全搞不懂。这实际上是我最大的问题。

2 个回答

0

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

  1. 我不太确定 il 这两个格式字符有什么区别,但我觉得你用 i/l 来表示 Int32 是对的,用 q 来表示 Int64 也没问题。

  2. 同样,我也不知道 i/lI/L 这几个格式字符之间的区别,但因为它们都表示 32 位整数,所以在 02147483647 之间的所有值,它们的二进制表示应该是一样的。如果 TotalTrades 可能是负数,或者超过 2147483647,那就需要进一步调查。如果不是,那就不用担心了。

  3. 我觉得你的序列化日期字段可能相当于 DateTime.Ticks

    如果是这样的话,序列化的值就是从 0001年1月1日 00:00:00 开始的 100 纳秒间隔的数量。

    根据这个计算,你问题中显示的值 634124502600000000 代表的时间是 2010年6月18日 09:31:00

3

据我所知,.net中的时间戳是从公元0001年1月1日00:00:00开始计算的,单位是“滴”,每个“滴”相当于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年6月18日。你所在的时区是比协调世界时(UTC)快9.5小时吗?如果你能提供两个时间戳值和预期的结果,这样可以更好地验证这个计算。

关于你提到的“我有点担心,因为某些字段的输出似乎对我指定的格式不太敏感:例如,TotalTrades字段无论我指定为有符号整数还是无符号整数,或者有符号长整型还是无符号长整型(l, L, i, 或 I),返回的结果都是一样的”这个问题:它们之所以不敏感是因为(1)“长整型”和“整型”是一样的(都是32位),(2)所有可能的无符号数字的一半较小的部分与有符号数字的表示是相同的。例如,在8位数字中,0到127的数字,无论是有符号还是无符号,它们的位模式都是一样的。

撰写回答