
本文详细介绍了如何使用python将特定格式的自定义二进制数据转换为日期时间戳。通过对二进制字节序列的模式分析、字节反转、位移操作以及经验性常数校准,结合pandas库处理时区和日期时间对象,最终实现精确的时间戳解码。教程涵盖了从数据探索到代码实现和验证的完整过程。
在处理非标准二进制数据时,首要任务是识别数据中哪些部分代表时间信息,以及它们是如何编码的。对于给定的二进制序列,例如 30 65 1a eb e3 f2 96 c5 41,我们观察到第一个字节 (0x30) 和最后一个字节 (0x41) 在所有示例中保持不变,这暗示它们可能是分隔符或固定标识符,而非时间数据的一部分。
进一步的观察发现,在日期时间相近的样本中,某些字节的变化具有规律性。例如,在以下三个示例中:
可以注意到倒数第二个字节 (c5) 始终不变,而倒数第三个字节在12月16日是 96,在12月17日是 97。这种模式提示我们,时间信息可能编码在中间的字节序列中,并且字节顺序可能需要反转处理。
经过实验和分析,发现将中间的字节序列(去除首尾固定字节)反转并拼接成一个十六进制字符串,然后转换为整数,可以得到一个与时间变化相关的数值。进一步观察时间差异与这些整数值之间的关系,发现它们之间存在一个接近 8_388_608(即 2 ** 23)的倍数关系。这表明原始时间值可能经过了左移23位编码,因此需要通过右移23位 (>> 23) 来还原。
立即学习“Python免费学习笔记(深入)”;
这个核心解码逻辑可以抽象为一个Python函数:
def extract_raw_epoch_seconds(hex_string):
"""
从十六进制字符串中提取原始的纪元秒数。
hex_string: 包含以空格分隔的十六进制字节的字符串。
"""
# 移除首尾字节,反转中间字节顺序,拼接成一个十六进制字符串
relevant_bytes = hex_string.split()[1:-1][::-1]
combined_hex = ''.join(relevant_bytes)
# 将十六进制字符串转换为整数,然后右移23位
raw_integer = int(combined_hex, 16)
epoch_seconds_shifted = raw_integer >> 23
return epoch_seconds_shifted仅仅通过位移操作得到的数值通常不是标准的Unix纪元秒(Epoch seconds)。它需要一个额外的常数偏移量来校准到正确的日期时间。通过比对已知日期时间与解码结果,可以经验性地确定这个偏移量。在本例中,经过多次尝试,确定了一个近似的偏移量为 -4927272860。
此外,考虑到日期可能受到夏令时(Daylight Saving Time, DST)的影响,尤其是在欧洲地区,处理时区变得至关重要。使用pandas库的Timestamp对象可以方便地处理时区信息。例如,对于欧洲地区,可以选择'Europe/Zurich'作为时区。
结合上述分析,我们可以构建一个完整的Python函数,将二进制十六进制字符串转换为带有正确时区的pandas.Timestamp对象。
首先,准备示例数据,并使用pandas.Timestamp将其转换为带有指定时区的标准时间对象,以便后续比较。
import pandas as pd
# 定义时区
tz = 'Europe/Zurich'
# 示例数据:十六进制字符串 -> 对应的日期时间
examples = {
'30 65 1a eb e3 f2 96 c5 41': '16 December 2023 at 15:03',
'30 c6 36 85 70 8a 97 c5 41': '17 December 2023 at 12:37',
'30 4a 26 1b 6b 29 74 c4 41': '1 October 2022 at 12:49',
'30 23 84 b1 a8 b5 97 c5 41': '17 December 2023 at 18:45',
'30 3f 91 e7 96 b5 97 c5 41': '17 December 2023 at 18:45:30', # 注意此处的秒数
'30 a6 d6 2f d1 b5 97 c5 41': '17 December 2023 at 18:46',
'30 e8 16 9c b9 b5 97 c5 41': '17 December 2023 at 18:47',
}
# 将字符串时间转换为带时区的pandas Timestamp对象,并按时间排序
examples = dict(sorted([
(k, pd.Timestamp(v, tz=tz)) for k, v in examples.items()
], key=lambda item: item[1]))
print("处理后的示例数据:")
for k, v in examples.items():
print(f" {k}: {v}")接下来,定义用于转换的核心函数:
# 定义核心解码函数
def f(k):
"""
解码二进制十六进制字符串为校准后的纪元秒数。
k: 以空格分隔的十六进制字节字符串。
"""
# 提取并反转相关字节,转换为整数,然后右移23位
raw_val = int(''.join(k.split()[1:-1][::-1]), 16) >> 23
# 应用经验性常数偏移
return raw_val - 4927272860
# 定义将解码值转换为pandas Timestamp的函数
def to_time(k, tz):
"""
将解码后的纪元秒转换为指定时区的pandas Timestamp对象。
k: 以空格分隔的十六进制字节字符串。
tz: 时区字符串。
"""
# pandas Timestamp的构造函数接受纳秒级的整数,所以需要乘以1e9
return pd.Timestamp(f(k) * 1e9, tz=tz)
# 定义时间格式化字符串
fmt = '%F %T %Z'
# 对所有示例进行转换和验证
test_results = [
(
f'{v:{fmt}}', # 给定的原始时间
f'{to_time(k, tz=tz):{fmt}}', # 从二进制数据估计的时间
(to_time(k, tz=tz) - v).total_seconds(), # 估计时间与原始时间的差值(秒)
)
for k, v in examples.items()
]
print("\n转换结果与验证:")
for original_time, estimated_time, diff_seconds in test_results:
print(f" 原始时间: {original_time}")
print(f" 估计时间: {estimated_time}")
print(f" 差值 (秒): {diff_seconds:.1f}\n")示例输出(部分):
转换结果与验证: 原始时间: 2022-10-01 12:49:00 CEST 估计时间: 2022-10-01 12:49:30 CEST 差值 (秒): 30.0 原始时间: 2023-12-16 15:03:00 CET 估计时间: 2023-12-16 15:03:23 CET 差值 (秒): 23.0 原始时间: 2023-12-17 12:37:00 CET 估计时间: 2023-12-17 12:36:37 CET 差值 (秒): -23.0 ...
从验证结果可以看出,估计时间与原始时间之间存在数十秒的微小差异。这可能是由于原始数据编码的精度限制,或是在确定偏移量时为了简化模型而选择的近似值。
通过以上步骤,我们成功地将特定的自定义二进制时间戳数据转换为可用的日期时间对象。这种方法体现了在处理非标准数据格式时,结合模式识别、位操作和经验性校准的通用策略。
以上就是Python中自定义二进制时间戳到日期时间转换教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号