16進数で表現された長い値を日付/時刻に戻すのを手伝ってください
-
03-07-2019 - |
質問
日付の値がありますが、それは8バイトで、単一の「長い」 (別名int64)値、16進数に変換:
60f347d15798c901
PHPを使用して、これとこのような値を時刻/日付に変換するにはどうすればよいですか?
10進数に変換すると、次のようになります。 96243 71209 87152201 1
もう少し情報:元の値はC#DateTimeであり、約2〜3週間前の時刻/日付を表す必要があります。
解決
(thomasrutterの投稿のおかげで、Windowsのファイルタイムエポックが得られました):
指定された日付は、Windows 64ビットリトルエンディアンファイルの日付、時刻、 60 f3 47 d1 57 98 c9 01、 これはクワッドワードと同等です 01c99857d147f360 整数として 128801567297500000
これは" 100ナノ秒間隔の数です 1月1日午前0時から経過した 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ビットリトルエンディアンファイルの日付、時刻、
60 f3 47 d1 57 98 c9 01、
これはクワッドワードと同等です
01c99857d147f360
整数として
128801567297500000
これは&quot; 100ナノ秒間隔の数です
1月1日午前0時から経過した
1601 A.D.(C.E.)協定世界時(UTC)&quot;
変換後、
木、2009年2月26日21:18:49 UTC
サンプルコード:
<*>GET["dt"]) ? strval((thomasrutterの投稿のおかげで、Windowsのファイルタイムエポックが得られました):
指定された日付は、Windows 64ビットリトルエンディアンファイルの日付、時刻、
60 f3 47 d1 57 98 c9 01、
これはクワッドワードと同等です
01c99857d147f360
整数として
128801567297500000
これは&quot; 100ナノ秒間隔の数です
1月1日午前0時から経過した
1601 A.D.(C.E.)協定世界時(UTC)&quot;
変換後、
木、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で終わることはこのタイプの日付の指標であると述べているため、これはもう少し役立つように見えます。これはリトルエンディアン(つまり、右側の最上位バイト)であるため、バイトは一度に2桁の16進数を反転せずにhexdec()のバイト順序が間違っていることに注意してください(つまり、右端の2桁の16進数で始まり、次の2つなど)。
そして、 thisソース、
単一のティックは、100ナノ秒または1000万分の1秒を表します。このプロパティの値は、0001年1月1日の深夜12:00:00から経過した100ナノ秒間隔の数を表します。
あなたをつまずかせるかもしれないのは、残念ながらPHPは64ビット整数を処理できないことです。 32ビットで最大になります。フロートは役立ちますが、それはhexdec()自体がintに対処することだけを止めません。したがって、この計算を行うのは複雑かもしれません。まだ2つに分割してから、より重要な値をfloatにキャストし、2 ^ 32を乗算してfloatとしてキャストすることにより、それらをfloatに結合する必要があるかもしれません。 64ビットハードウェア用に構築されたPHPにこの制限がない可能性がありますが、私にはわかりません。
hexdec()で10進整数に変換できると思います。
これは、 date()。
指定した値は36桁の16進数、つまり18バイトです。これは、 Int64
が16進数に変換された ではありません。
形式の説明をくれた人に戻り、今回は真実を伝えるように頼んでください:)
編集:さて、次のステップ:その数字が実際に何を意味するのかを調べてください。 1970年以降のダニ? AD 1以降のMillis?サンプル文字列が何を表すのか知っていますか?
同じタイプのここで説明する64ビットの16進数NTPタイムスタンプ、16進数文字列を2つに均等に分割する必要があります。つまり、最初の8桁の16進数と他の8桁の区切りを想像してください。
前半(最初の32ビットの価値)をhexdec()で整数に変換すると、この整数はUnixタイムスタンプ形式(1970年1月1日GMTからの秒数)の日付値になり、日付で使用できます()関数など
2番目の部分は小数部です。1秒よりも細かい精度が必要な場合に便利です(ただし、多くのアプリケーションでは必要ありません。また、PHPに組み込まれている日付および時刻関数はmicrotime()を除きます)。また、hexdec()を使用してこれを10進数に変換します。