帮我翻译长值,以十六进制表示,回到日期/时间
-
03-07-2019 - |
题
我有一个日期值,我告诉它是8个字节,一个“长”字节。 (又名int64)值,并转换为十六进制:
60f347d15798c901
如何将这个和使用PHP的值转换为时间/日期?
将其转换为十进制为我提供: 96 243 71 209 87 152 201 1
更多信息:原始值是C#DateTime,应该代表大约2或3周前的时间/日期。
解决方案
(感谢thomasrutter的帖子,它给了我Windows文件时间纪录):
给定日期似乎是Windows 64位little-endian文件的日期时间, 60 f3 47 d1 57 98 c9 01, 这相当于四字 01c99857d147f360 它是一个整数 128801567297500000
这是“100纳秒间隔的数量 从1月1日午夜12点开始, 1601 A.D.(C.E。)世界协调时间(UTC)“
转换后,它给出了 星期四,2009年2月26日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((感谢thomasrutter的帖子,它给了我Windows文件时间纪录):
给定日期似乎是Windows 64位little-endian文件的日期时间,
60 f3 47 d1 57 98 c9 01,
这相当于四字
01c99857d147f360
它是一个整数
128801567297500000
这是“100纳秒间隔的数量
从1月1日午夜12点开始,
1601 A.D.(C.E。)世界协调时间(UTC)“
转换后,它给出了
星期四,2009年2月26日21:18:49 UTC
示例代码:
<*>GET["dt"]) ? strval((感谢thomasrutter的帖子,它给了我Windows文件时间纪录):
给定日期似乎是Windows 64位little-endian文件的日期时间,
60 f3 47 d1 57 98 c9 01,
这相当于四字
01c99857d147f360
它是一个整数
128801567297500000
这是“100纳秒间隔的数量
从1月1日午夜12点开始,
1601 A.D.(C.E。)世界协调时间(UTC)“
转换后,它给出了
星期四,2009年2月26日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个十六进制数字开始,然后是下两个,等等。
并且,根据这个源,
单个刻度表示一百纳秒或一百万分之一秒。此属性的值表示自0001年1月1日午夜12:00:00起经过的100纳秒间隔的数量。
令你失望的是,遗憾的是PHP无法处理64位整数。最大值为32位。浮点数会有所帮助,但这并不能阻止hexdec()本身只处理整数。所以做这个数学可能很复杂;您可能仍需要将其拆分为两个,然后通过将更重要的值转换为float并将其乘以2 ^ 32并将其转换为float来将它们组合成浮点数。 为64位硬件构建的PHP可能没有这个限制,但我不确定。
我相信您可以使用 hexdec()将其转换为十进制int。
这将是您可以使用 date()进行处理的时间戳。
您给出的值是36个十六进制数字,即18个字节。那是不 Int64
转换为十六进制。
回到给你解释格式的人那里,让他们这次告诉你真相:))
编辑:好的,下一步:找出这个数字实际意味着什么。自1970年以来蜱虫?公元1年以来的Millis?你知道你的示例字符串代表什么吗?
如果是相同类型的这里描述的64位十六进制NTP时间戳,那么你应该将十六进制字符串分成两部分,即想象一下前8个十六进制数字和另外8个数字之间的分隔符。
将前半部分(前32位值)转换为带有hexdec()的整数,此整数将是Unix时间戳格式的日期值(自格林威治标准时间1970年1月1日起的秒数),您可以在日期中使用该日期值()函数等。
第二部分是小数部分,如果你需要精度超过一秒(虽然没有多少应用程序可以做到,但PHP的内置日期和时间函数不包括microtime()),这很有用。您还可以使用hexdec()将其转换为十进制。