Помогите мне перевести длинное значение, выраженное в шестнадцатеричном виде, обратно в дату / время
-
03-07-2019 - |
Вопрос
У меня есть значение даты, которое, как мне говорят, составляет 8 байт, один " длинный " (также известное как int64) и преобразуется в шестнадцатеричное:
60f347d15798c901
Как я могу преобразовать это и такие значения, используя PHP, во время / дату? Р>
Преобразование его в десятичное дает мне: 96 243 71 209 87 152 201 1
Немного больше информации: исходное значение - C # DateTime, и оно должно представлять время / дату 2 или 3 недели назад.
Решение
(Спасибо посту Томасруттера, который дал мне эпоху файлового времени Windows):
Похоже, что указанная дата является 64-битной датой в формате Windows. 60 f3 47 d1 57 98 c9 01, что эквивалентно четырех словам 01c99857d147f360 который как целое число 128801567297500000 р>
Это "количество интервалов в 100 наносекунд". прошедшие с 12:00 до полуночи 1 января, 1601 г. н.э. (C.E.) Всемирное координированное время (UTC) "
После преобразования он дает Четверг, 26 февраля 2009 г., 21:18:49 UTC
Пример кода:
<?php
// strip non-hex characters
function hexstring($str) {
$hex = array(
'0'=>'0', '1'=>'1', '2'=>'2', '3'=>'3', '4'=>'4',
'5'=>'5', '6'=>'6', '7'=>'7', '8'=>'8', '9'=>'9',
'a'=>'a', 'b'=>'b', 'c'=>'c', 'd'=>'d', 'e'=>'e', 'f'=>'f',
'A'=>'a', 'B'=>'b', 'C'=>'c', 'D'=>'d', 'E'=>'e', 'F'=>'f'
);
$t = '';
$len = strlen($str);
for ($i=0; $i<$len; ++$i) {
$ch = $str[$i];
if (isset($hex[$ch]))
$t .= $hex[$ch];
}
return $t;
}
// swap little-endian to big-endian
function flip_endian($str) {
// make sure #digits is even
if ( strlen($str) & 1 )
$str = '0' . $str;
$t = '';
for ($i = strlen($str)-2; $i >= 0; $i-=2)
$t .= substr($str, $i, 2);
return $t;
}
// convert hex string to BC-int
function hex_to_bcint($str) {
$hex = array(
'0'=>'0', '1'=>'1', '2'=>'2', '3'=>'3', '4'=>'4',
'5'=>'5', '6'=>'6', '7'=>'7', '8'=>'8', '9'=>'9',
'a'=>'10', 'b'=>'11', 'c'=>'12', 'd'=>'13', 'e'=>'14', 'f'=>'15',
'A'=>'10', 'B'=>'11', 'C'=>'12', 'D'=>'13', 'E'=>'14', 'F'=>'15'
);
$bci = '0';
$len = strlen($str);
for ($i=0; $i<$len; ++$i) {
$bci = bcmul($bci, '16');
$ch = $str[$i];
if (isset($hex[$ch]))
$bci = bcadd($bci, $hex[$ch]);
}
return $bci;
}
// WARNING! range clipping
// Windows date time has range from 29000 BC to 29000 AD
// Unix time only has range from 1901 AD to 2038 AD
// WARNING! loss of accuracy
// Windows date time has accuracy to 0.0000001s
// Unix time only has accuracy to 1.0s
function win64_to_unix($bci) {
// Unix epoch as a Windows file date-time value
$magicnum = '116444735995904000';
$t = bcsub($bci, $magicnum); // Cast to Unix epoch
$t = bcdiv($t, '10000000', 0); // Convert from ticks to seconds
return $t;
}
// get input
$dtval = isset( (Спасибо посту Томасруттера, который дал мне эпоху файлового времени Windows):
Похоже, что указанная дата является 64-битной датой в формате Windows.
60 f3 47 d1 57 98 c9 01,
что эквивалентно четырех словам
01c99857d147f360
который как целое число
128801567297500000 р>
Это "количество интервалов в 100 наносекунд".
прошедшие с 12:00 до полуночи 1 января,
1601 г. н.э. (C.E.) Всемирное координированное время (UTC) "
После преобразования он дает
Четверг, 26 февраля 2009 г., 21:18:49 UTC
Пример кода:
<*>GET["dt"]) ? strval( (Спасибо посту Томасруттера, который дал мне эпоху файлового времени Windows):
Похоже, что указанная дата является 64-битной датой в формате Windows.
60 f3 47 d1 57 98 c9 01,
что эквивалентно четырех словам
01c99857d147f360
который как целое число
128801567297500000 р>
Это "количество интервалов в 100 наносекунд".
прошедшие с 12:00 до полуночи 1 января,
1601 г. н.э. (C.E.) Всемирное координированное время (UTC) "
После преобразования он дает
Четверг, 26 февраля 2009 г., 21:18:49 UTC
Пример кода:
<*>GET["dt"]) : "0";
$dtval = hexstring($dtval); // strip non-hex chars
// convert to quadword
$dtval = substr($dtval, 0, 16); // clip overlength string
$dtval = str_pad($dtval, 16, '0'); // pad underlength string
$quad = flip_endian($dtval);
// convert to int
$win64_datetime = hex_to_bcint($quad);
// convert to Unix timestamp value
$unix_datetime = win64_to_unix($win64_datetime);
?><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Windows datetime test code</title>
</head>
<form method="get">
<label>Datetime value: <input name="dt" type="text" value="<?php echo $dtval; ?>"/></label>
<input type="submit" />
</form>
<hr />
Result:
Quad: <?php echo $quad; ?><br />
Int: <?php echo $win64_datetime; ?><br />
Unix timestamp: <?php echo $unix_datetime; ?><br />
Date: <?php echo date("D, d F Y H:i:s e", $unix_datetime); ?><br />
<body>
</body>
</html>
Другие советы
Я нашел другую ссылку , которая может указывать на некоторые более важные Информация. В этом случае Windows использует дату и время, используемые в реестре. По-видимому, они также хранятся в виде 64-битных значений.
Это выглядит немного более полезным, поскольку в нем упоминается, что окончание в C? 01 является индикатором этого типа даты. Обратите внимание, что это младший порядок байтов (т. Е. Наиболее значимые байты справа), поэтому байты расположены в неправильном порядке байтов для hexdec (), не обращая их по 2 шестнадцатеричных цифры за раз (т. Е. Начинаются с самых правых 2 шестнадцатеричных цифр, затем следующие два и т. д.).
И, согласно этому источник , р>
Один тик представляет сто наносекунд или одну десятую миллионную секунды. Значение этого свойства представляет число интервалов в 100 наносекунд, прошедших с 12:00:00 до полуночи 1 января 0001 года, которое представляет собой.
Что может сбить вас с толку, так это то, что, к сожалению, PHP не может обрабатывать 64-битные целые числа. Максимальное значение - 32 бита. Поплавки помогут, но это не мешает самому hexdec () справляться только с целыми числами. Так что это может быть сложно сделать эту математику; вам все еще может понадобиться разделить его на две части, а затем объединить их в число с плавающей точкой, приведя более значимое значение к числу с плавающей точкой и умножив его на 2 ^ 32, также приведенное к значению с плавающей точкой. Возможно, что PHP, созданный для 64-битного оборудования, может не иметь этого ограничения, но я точно не знаю.
Я полагаю, что вы можете преобразовать его в десятичное целое с помощью hexdec ().
Это будет временная метка, с которой вы можете работать с помощью date ().
Значение, которое вы указали, составляет 36 шестнадцатеричных цифр, то есть 18 байтов. Это не , а Int64
преобразуется в шестнадцатеричное.
Вернитесь к тому, кто дал вам объяснение формата, и попросите их рассказать вам правду на этот раз:)
РЕДАКТИРОВАТЬ: Хорошо, следующий шаг: выяснить, что на самом деле означает это число. Клещи с 1970 года? Миллис с нашей эры 1? Знаете ли вы, что ваша строка примера должна представлять?
Если это тот же тип 64-битная шестнадцатеричная временная метка NTP, как описано здесь , тогда вы должны разделить шестнадцатеричную строку поровну на две части, то есть представить себе разделитель между первыми 8 шестнадцатеричными цифрами и другими 8.
Преобразуйте первую половину (первые 32 бита) в целое число с помощью hexdec (), и это число будет значением даты в формате отметки времени Unix (в секундах с 1 января 1970 года по Гринвичу), которое затем можно использовать в дате () и т. д.
Вторая часть - это дробные секции, которые полезны, если вам нужна точность, превышающая одну секунду (хотя это делают не многие приложения, а встроенные в PHP функции даты и времени - за исключением microtime ()). Вы также преобразовали бы это в десятичную с помощью hexdec ().