dbf 文件(dBase 7 格式)中的时间戳字段没有意义
Timestamp field in a dbf file (dBase 7 format) is not making sense
我看过 [1] 和 [2],但我完全糊涂了(因为 dbf 文件是一个版本
4 文件,[1] 应该适用)。一方面,为什么 [1] 声明时间戳的日期部分是自公元前 4713 年 1 月 1 日以来的天数?这真是令人费解。其次,假设它是自公元前 4713 年以来的天数,我在获取值时遇到了一些问题。
首先,我的 dbf 文件有一个时间戳字段,它有一个 8 字节长的值。实际上
日期是 2000/8/16 17:21:41。在dbf文件中,8字节序列如下
0x42ccb20e0340df00.
从[1]开始,它说前4个字节是日期,第二个4个字节是时间。如果原来
字节序列实际上是 little-endian (0x42ccb20e) 那么应该是 0x0eb2cc42
得出246598722的值。所以日期是0x0eb2cc42(246598722),时间是0x00df4003
(14630915)。
我一定是遗漏了什么或者计算出了什么问题。 246598722 相当于 675612 年(假设 1 年 = 365 天,因为添加闰年会让我感到困惑......而且真的不应该那么多)。
从 [2] 开始,我不应该使用 01/01/4173bc 作为基础,而是 12/31/1899(嗯,1/1/1900)。但是,我的日期值甚至不在 [2] 显示的范围内。
现在如果我取实际值 (2000/8/16) 并使用 [1] 和 [2],我得到以下结果:
方法 [1]:2450501 天:(2000 - -4713) * 365 + (8 * 30) + 16
方法 [2]:36756 天:[100 * 365 + 8 * 30 + 16](超过天数)
dbf 文件没有损坏(否则,如果我查看 dBase 中的时间戳,它就会出错
并展示一些疯狂的东西)。
我考虑过使用 big-endian,但由于值更大,所以更没有意义。我什至想到了它实际上是自任一日期以来经过的秒数的可能性,但这使得这些值的意义更小。即 246598722 = 经过的秒数(从 2000 年 8 月 16 日开始倒计时)将使基准年成为 1812 年。(计算:246898722 / (3600 * 365) = 187.8985,因此 2000 - 187.8985 = 1812.1015)
谁能指出我哪里做错了?
谢谢!
[1] - https://www.dbase.com/Knowledgebase/INT/db7_file_fmt.htm
[2] - Convert dBase Timestamp
感谢[3],我终于找到了答案。
基本上时间戳8字节序列是作为一个整体使用,注意事项如下:
大端存储
最后一个字节未使用。
这是儒略日数字。
所以在我的例子中,它是 0x42ccb20e0340df00 并截断了最后一个字节,
我得到 0x42ccb20e0340df。
然后下面的python代码得到正确的信息:
import datetime
base = 0x42cc418ba99a00
frm_date = int('42ccb20e0340df', 16)
final_ts = (frm_date - base) / 500
final_date = datetime.datetime.utcfromtimestamp(final_ts)
输出 2000-8-16 17:21:41 和几毫秒,我忽略了。
所以我猜测理论上是上面的代码将 'base' 日期移动到
1970/1/1 从 1/1/1,这有帮助,因为 utcfromtimestamp() 没有
使用 1970/1/1 之前的任何值。
我的困惑源于它不使用 4713BC 作为
基准年,而是使用 1/1/1,尽管我仍在尝试弄清楚如何获得 1970/1/1 的值 0x42cc418ba99a00。
[3] -
对于任何 dBASE 问题,我建议您访问 dBASE 新闻组,他们有一个非常有用且知识渊博的社区。
我看过 [1] 和 [2],但我完全糊涂了(因为 dbf 文件是一个版本 4 文件,[1] 应该适用)。一方面,为什么 [1] 声明时间戳的日期部分是自公元前 4713 年 1 月 1 日以来的天数?这真是令人费解。其次,假设它是自公元前 4713 年以来的天数,我在获取值时遇到了一些问题。
首先,我的 dbf 文件有一个时间戳字段,它有一个 8 字节长的值。实际上 日期是 2000/8/16 17:21:41。在dbf文件中,8字节序列如下 0x42ccb20e0340df00.
从[1]开始,它说前4个字节是日期,第二个4个字节是时间。如果原来 字节序列实际上是 little-endian (0x42ccb20e) 那么应该是 0x0eb2cc42 得出246598722的值。所以日期是0x0eb2cc42(246598722),时间是0x00df4003 (14630915)。
我一定是遗漏了什么或者计算出了什么问题。 246598722 相当于 675612 年(假设 1 年 = 365 天,因为添加闰年会让我感到困惑......而且真的不应该那么多)。
从 [2] 开始,我不应该使用 01/01/4173bc 作为基础,而是 12/31/1899(嗯,1/1/1900)。但是,我的日期值甚至不在 [2] 显示的范围内。
现在如果我取实际值 (2000/8/16) 并使用 [1] 和 [2],我得到以下结果:
方法 [1]:2450501 天:(2000 - -4713) * 365 + (8 * 30) + 16 方法 [2]:36756 天:[100 * 365 + 8 * 30 + 16](超过天数)
dbf 文件没有损坏(否则,如果我查看 dBase 中的时间戳,它就会出错 并展示一些疯狂的东西)。
我考虑过使用 big-endian,但由于值更大,所以更没有意义。我什至想到了它实际上是自任一日期以来经过的秒数的可能性,但这使得这些值的意义更小。即 246598722 = 经过的秒数(从 2000 年 8 月 16 日开始倒计时)将使基准年成为 1812 年。(计算:246898722 / (3600 * 365) = 187.8985,因此 2000 - 187.8985 = 1812.1015)
谁能指出我哪里做错了?
谢谢!
[1] - https://www.dbase.com/Knowledgebase/INT/db7_file_fmt.htm [2] - Convert dBase Timestamp
感谢[3],我终于找到了答案。
基本上时间戳8字节序列是作为一个整体使用,注意事项如下:
大端存储
最后一个字节未使用。
这是儒略日数字。
所以在我的例子中,它是 0x42ccb20e0340df00 并截断了最后一个字节, 我得到 0x42ccb20e0340df。
然后下面的python代码得到正确的信息:
import datetime
base = 0x42cc418ba99a00
frm_date = int('42ccb20e0340df', 16)
final_ts = (frm_date - base) / 500
final_date = datetime.datetime.utcfromtimestamp(final_ts)
输出 2000-8-16 17:21:41 和几毫秒,我忽略了。
所以我猜测理论上是上面的代码将 'base' 日期移动到 1970/1/1 从 1/1/1,这有帮助,因为 utcfromtimestamp() 没有 使用 1970/1/1 之前的任何值。
我的困惑源于它不使用 4713BC 作为 基准年,而是使用 1/1/1,尽管我仍在尝试弄清楚如何获得 1970/1/1 的值 0x42cc418ba99a00。
[3] -
对于任何 dBASE 问题,我建议您访问 dBASE 新闻组,他们有一个非常有用且知识渊博的社区。