我有一个日期值,我被告知是 8 个字节,一个“长”(又名 int64)值,并转换为十六进制:
60f347d15798c901
如何使用 PHP 将这个和类似的值转换为时间/日期?
将其转换为十进制给我: 96 243 71 209 87 152 201 1
更多信息:原始值是 C# DateTime,应该表示大约 2 或 3 周前的时间/日期。
我有一个日期值,我被告知是 8 个字节,一个“长”(又名 int64)值,并转换为十六进制:
60f347d15798c901
如何使用 PHP 将这个和类似的值转换为时间/日期?
将其转换为十进制给我: 96 243 71 209 87 152 201 1
更多信息:原始值是 C# DateTime,应该表示大约 2 或 3 周前的时间/日期。
我找到了另一个参考,它可能指向一些更相关的信息。在这种情况下,注册表中使用的 Windows 日期和时间。显然,这些也存储为 64 位值。
这看起来更有帮助,因为它提到以 C?01 结尾是此类日期的指示符。请注意,这是小端序(即右侧的最高有效字节),因此 hexdec() 的字节顺序错误,而不会一次将它们反转 2 个十六进制数字(即,从最右边的 2 个十六进制数字开始,然后是接下来的两个,等等)。
而且,根据这个消息来源,
一个滴答表示一百纳秒或百万分之一秒。此属性的值表示自 0001 年 1 月 1 日午夜 12:00:00 以来经过的 100 纳秒间隔数,它表示。
不幸的是,PHP 无法处理 64 位整数,这可能会让您感到困惑。它的最大值为 32 位。浮点数会有所帮助,但这并不能阻止 hexdec() 本身仅处理整数。所以做这个数学可能很复杂;您可能仍需要将其分成两部分,然后通过将更重要的值转换为浮点数并将其乘以 2^32 将它们组合成浮点数,也将其转换为浮点数。 为 64 位硬件构建的 PHP 可能没有此限制,但我不确定。
(感谢 thomasrutter 的帖子,它给了我 Windows 文件时间时代):
给定的日期似乎是 Windows 64 位 little-endian 文件日期时间,60 f3 47 d1 57 98 c9 01,相当于四字 01c99857d147f360,整数为 128801567297500000
这是“自公元 1601 年 1 月 1 日 (CE) 协调世界时 (UTC) 午夜 12:00 以来经过的 100 纳秒间隔数”
转换后,它给出了 Thu, 26 February 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($_GET["dt"]) ? strval($_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>
您给出的值是 36 个十六进制数字,即 18 个字节。那不是Int64
转换为十六进制。
回到给你解释格式的人那里,让他们这次告诉你真相:)
编辑:好的,下一步:找出这个数字的实际含义。自 1970 年以来的蜱虫?公元 1 年以来的米利斯?你知道你的示例字符串是什么意思吗?
我相信您可以将其转换为十进制整数,hexdec().
这将是您可以使用的时间戳date().
如果它与此处描述的 64 位十六进制 NTP 时间戳类型相同,那么您应该将十六进制字符串一分为二,也就是说,想象前 8 个十六进制数字和其他 8 个数字之间的分隔符。
使用 hexdec() 将前半部分(前 32 位的值)转换为整数,该整数将是 Unix 时间戳格式的日期值(自 1970 年 1 月 1 日 GMT 以来的秒数),然后您可以在 date() 函数中使用, ETC。
第二部分是小数部分,如果您需要小于一秒的精度(虽然没有多少应用程序这样做,PHP 的内置日期和时间函数除了 microtime() 之外没有),这很有用。您还可以使用 hexdec() 将其转换为十进制。