Извлечение даты и времени из двоичной строки данных с помощью

#python #datetime #struct #reverse-engineering

#python #дата и время #структура #обратная разработка

Вопрос:

У меня есть стороннее приложение, которое хранит данные временных рядов в виде упакованного двоичного файла. Я пытаюсь создать инструмент для преобразования данных, хранящихся в этом файле.

Ниже показан снимок этих данных.

 41 16 00 00 01 00 D7 11 00 00 01 00 E8 55 A6 20 08 1E D0 08 00 00 00 60 59 D5 
86 40 03 E8 F5 2C 22 08 1E D0 08 00 00 00 00 C0 0B 87 40 01 E8 95 B3 23 08 1E 
D0 08 00 00 00 40 1E 00 87 40 01 E8 35 3A 25 08 1E D0 08 00 00 00 60 13 F8 86
40 01 E8 D5 C0 26 08 1E D0 08 00 00 00 40 65 09 87 40 01 E8 75 47 28 08 1E D0 
08 00 00 00 20 8A F6 86 40 01 E8 15 CE 29 08
  

Я знаю, что этот блок данных соответствует следующим значениям.

 5/13/2013 17:46:11.558  730.6686401
5/13/2013 17:46:14.118  737.46875
5/13/2013 17:46:16.678  736.0147705
  

Я могу извлечь значения: они имеют тип double . Например, 8 байтов 00 00 00 60 59 D5 86 40 соответствуют 730.6686401 .

Но я озадачен тем, как извлечь формат даты и времени. Я знаю, что он где-то спрятан в этой строке. Как я могу выяснить, в каком формате указано время?

Я использую struct модуль Python для преобразования типов.

У кого-нибудь есть идеи?

Комментарии:

1. Судя по другим 2 значениям с плавающей запятой, закодированным как двойные, между ними всего 9 байт для кодирования значения даты и времени.

2. Кроме того, последовательность [08 1E D0 08] повторяется 6 раз, всегда с интервалом в 13 байтов. В этом блоке всего 3 значения или их больше 3?

3. @aruisdante: я бы сказал, что там как минимум 6 наборов.

4. Последовательность [E8 X5] также повторяется (в данном случае 7, но похоже, что этот блок может быть усечен, и была бы другая последовательность 08 1E), где X — переменное число, за 2 байта до последовательности 08 1E

5. Может ли 8 байт быть достаточно для хранения информации?

Ответ №1:

Если вы берете 8 байтов непосредственно перед одним из double , и рассматриваете его как целое число (младшее, как double), то вы получите следующие числа:

 635040567715583464
635040567741183464
635040567766783464
  

Если вы разделите эти числа на 10 ** 7, то вы получите дату в виде количества секунд (и долей секунды). По крайней мере, это соответствует минутам, секундам и долям секунды. В течение нескольких часов я получаю ошибку off-by-two (часовой пояс?). Для полной даты номер дня 735000(*) соответствует 13.05.2013 следующим образом. Это количество дней в году 1:

 >>> datetime.date(1,1,1)   datetime.timedelta(735000)
datetime.date(2013, 5, 13)
  

(*) это любое из этих чисел, деленное на 10**7 * 60 * 60 * 24

Или за один шаг:

 >>> x = 635040567715583464 / 10.**7 / 86400
>>> datetime.datetime(1,1,1)   datetime.timedelta(x)
datetime.datetime(2013, 5, 13, 15, 46, 11, 558353)
  

Комментарии:

1. datetime поддерживает ordinals ( datetime.datetime.fromordinal(735000) ) . Таким образом, числа являются смещениями от эпохи 1/1/1 00: 00:00 вместо эпохи UNIX?

2. итак ordinal, rem = divmod(635040567715583464, 10**7 * 86400) , затем datetime.datetime.fromordinal(ordinal) datetime.timedelta(microseconds=rem/10.0) вы получаете правильную дату datetime.datetime(2013, 5, 12, 15, 46, 11, 558346) , предположительно в UTC.

3. Я не уверен, что именно fromordinal(735000) делает, но в результате получается один выходной (12-го вместо 13-го). Конечно, конечный результат по-прежнему составляет 2 часа, поэтому, возможно, нам действительно следует использовать fromordinal() и считать, что результат равен 22 или 26 часам.

4. fromordinal() интерпретирует целое число как дни, начиная с 1/1/0001. Если там есть ошибка, которая должна быть легко исправлена.

5. Я углубился в разницу в 2 часа. Выход может быть связан с тем, что данные были собраны по европейскому летнему времени. @Armin Rigo, дает ли преобразование времени время в UTC?