6

我有一个旧数据格式的 DateTime 结构,我无权访问它的任何规范。有一个字段指示数据的日期时间,但它不是我认识的任何格式。它似乎存储为一个 32 位整数,每天递增 20。有没有人遇到过这样的事情?

编辑:

示例:1088631936 DEC = 80 34 E3 40 00 00 00 00 HEX = 09/07/2007

编辑:

首先,抱歉耽搁了。我曾希望在周末做一些事情,但无法做到。

其次,这种日期格式比我最初想象的要奇怪。它似乎是某种指数或对数方法,因为日期不会以增加的速度变化。

第三,我用于解释这些值的已失效应用程序仅显示日期部分,所以我不知道时间部分是什么。

示例数据:(十六进制值是大端,日期是 mm/dd/yyyy)

0x40000000之后= 01/01/1900
0x40010000 = 01/01/1900
0x40020000 = 01/01/1900
0x40030000 = 01/01/1900
0x40040000 = 01/01/1900
0x40050000 = 01/01/1900
0x40060000 = 01/01/1900
0x40070000 = 01/01/1900
0x40080000 = 1900年1月2日
0x40090000 = 1900年1月2日
0x400A0000 = 1900年1月2日0x400B0000 = 1900年1月2日0x400C0000 = 1900年1月2日
0x400D0000 = 1900年1月2 日
0x400E0000 = 01/02/1900 0x400F0000 = 01/02/1900 0x40100000 = 01/03/1900 0x40110000 = 01/03/1900 0x40120000 = 01/01/03/1900 03/1900 0x40130000013000003/03/03/03/1403/140403/140403/140403 / 140404040404040404040X4040X4040X4040X4040X4040X4040X4040X4040X4040X4040X4040X4040X4000转/04/1900 0x40160000 = 01/04/1900










0x40170000 =
1900年1月
4日0x40180000
= 1900年1月5日
0x40190000 = 1900年1月5日0x401A0000 = 1900年1月5日0x401B0000 = 1900年1月5日0x401C0000 = 1900年1月6日
0x401D0000 = 1900
年1月6日
0x401E0000 = 01/06/1900
0x401F0000 = 01/06/1900
0x40200000 = 01/07/1900
0x40210000 = 01/07/1900
0x40220000 = 01/08/1900 = 0x40230000 =
01/08/10000
....
01/08/10000 /1901
0x40810000 = 06/27/1901
0x40820000 = 07/29/1901
....
0x40D00000 = 11/08/1944
0x40D10000 = 08/29/1947

编辑:我终于想通了,但由于我已经放弃了赏金积分,我将推迟解决方案,以防有人想试一试。

顺便说一句,这没有时间组件,它纯粹是为了存储日期。

4

5 回答 5

7

它不是整数,它是一个 32 位浮点数。我还没有完全确定格式,它不是 IEEE。

编辑:明白了。1 位符号,11 位指数,偏移量为 0x3ff,20 位尾数,隐含位在左侧。在 C 中,仅假设正数:

double offset = pow(2, (i >> 20) - 0x3ff) * (((i & 0xfffff) + 0x100000) / (double) 0x100000);

这会产生 0x40000000 = 2.0,因此开始日期必须是 1899 年 12 月 30 日。

再次编辑:既然你很友善地接受了我的回答,而且你似乎担心速度,我想我会稍微改进一下。您不需要实数的小数部分,因此我们可以仅使用按位运算将其直接转换为整数。这次在 Python 中完成测试结果。为了更好的可读性,我包含了一些中间值。除了没有负数的限制之外,这个版本在指数超过 19 时可能会出现问题,但这应该让你在 3335 年之前保持良好状态。

>>> def IntFromReal32(i):
        exponent = (i >> 20) - 0x3ff
        mantissa = (i & 0xfffff) + 0x100000
        return mantissa >> (20 - exponent)

>>> testdata = range(0x40000000,0x40240000,0x10000) + range(0x40800000,0x40830000,0x10000) + [1088631936]
>>> from datetime import date,timedelta
>>> for i in testdata:
        print "0x%08x" % i, date(1899,12,30) + timedelta(IntFromReal32(i))


0x40000000 1900-01-01
0x40010000 1900-01-01
0x40020000 1900-01-01
0x40030000 1900-01-01
0x40040000 1900-01-01
0x40050000 1900-01-01
0x40060000 1900-01-01
0x40070000 1900-01-01
0x40080000 1900-01-02
0x40090000 1900-01-02
0x400a0000 1900-01-02
0x400b0000 1900-01-02
0x400c0000 1900-01-02
0x400d0000 1900-01-02
0x400e0000 1900-01-02
0x400f0000 1900-01-02
0x40100000 1900-01-03
0x40110000 1900-01-03
0x40120000 1900-01-03
0x40130000 1900-01-03
0x40140000 1900-01-04
0x40150000 1900-01-04
0x40160000 1900-01-04
0x40170000 1900-01-04
0x40180000 1900-01-05
0x40190000 1900-01-05
0x401a0000 1900-01-05
0x401b0000 1900-01-05
0x401c0000 1900-01-06
0x401d0000 1900-01-06
0x401e0000 1900-01-06
0x401f0000 1900-01-06
0x40200000 1900-01-07
0x40210000 1900-01-07
0x40220000 1900-01-08
0x40230000 1900-01-08
0x40800000 1901-05-26
0x40810000 1901-06-27
0x40820000 1901-07-29
0x40e33480 2007-09-07
于 2009-03-25T05:33:53.330 回答
3

您确定这些值对应于 2007 年 9 月 7 日吗?

我问是因为 1088631936 是自 Linux(等)零日期以来的秒数:01/01/1970 00:00:00 到 06/30/2004 21:45:36。

在我看来,自这个通常的零日期以来,该值是秒数,这似乎是合理的。

编辑:我知道这很可能不是正确的答案。这只是一种方法(一种有效的方法),但我认为需要更多信息(见评论)。编辑这个(再次)将问题带到前面,希望其他人回答它或给出想法。我:具有公平、运动和分享的精神:D

于 2009-03-21T06:03:51.437 回答
1

我会说 vmarquez 很接近。

以下是日期 2009-3-21 和 2009-3-22 作为 unix epochtime:

In [8]: time.strftime("%s", (2009, 3, 21, 1, 1, 0, 0,0,0))
Out[8]: '1237590060'

In [9]: time.strftime("%s", (2009, 3, 22, 1, 1, 0, 0,0,0))
Out[9]: '1237676460'

在这里它们是十六进制的:

In [10]: print("%0x %0x" % (1237590060, 1237676460))
49c4202c 49c571ac

如果您只取前 5 位数字,则增长为 21。哪种格式符合您的格式,是否?

于 2009-03-21T19:01:13.283 回答
1

一些上下文会很有用。如果您的数据文件在字面上或至少在比喻上看起来像这个文件,那么 vmarquez 就赚钱了。

http://www.slac.stanford.edu/comp/net/bandwidth-tests/eventanalysis/all_100days_sep04/node1.niit.pk

该引用是由可用带宽估计工具 (ABwE) 生成的数据——奇怪的是它实际上包含 1088631936 值以及上下文。那个例子


 date     time       abw     xtr   dbcap   avabw   avxtr  avdbcap      rtt    timestamp
06/30/04 14:43:48  1.000   0.000   1.100   1.042   0.003    1.095  384.387   1088631828
06/30/04 14:45:36  1.100   0.000   1.100   1.051   0.003    1.096  376.408   1088631936
06/30/04 14:47:23  1.000   0.000   1.100   1.043   0.003    1.097  375.196   1088632043
似乎与建议的 21:45:36 时间值有 7 小时的偏移。(可能是斯坦福本地的,在夏令时运行。)

于 2009-03-22T16:40:06.063 回答
0

好吧,您只向我们展示了您的程序如何使用 8 位数字中的 2 位,所以我们必须假设其他 6 位被忽略(因为您的程序可以使用其他数字做任何它想做的事情)。

因此,我们可以说输入格式是:40mn0000,其中 m 和 n 是两个十六进制数字。

然后,输出为: 01/01/1900 + floor((2^(m+1)-2) + n*2^(m-3)) 天

解释:

  1. 在每个示例中,请注意将 n 增加 1 会使天数增加 2^(m-3)。
  2. 请注意,每次 n 从 F 变为 0 时,m 都会递增。

使用这两个规则,并玩弄数字,你会得到上面的等式。(除了由于输出不显示小数天数而添加的 floor)。

我想您可以通过将两个单独的十六进制变量 m 和 n 替换为单个 2 位十六进制数 H 来重写此代码。但是,我认为这会使等式变得更加丑陋。

于 2009-03-25T04:59:47.250 回答