Me ajudar a traduzir o valor de comprimento, expresso em hexadecimal, de volta para uma data / hora

StackOverflow https://stackoverflow.com/questions/610603

Pergunta

Eu tenho um valor de data, o que me disseram é de 8 bytes, "longo" valor de um único (aka int64) e convertido para hex:

60f347d15798c901

Como posso converter este e os valores como esta, usando PHP, em uma data / hora?

convertê-lo para decimal me dá: 243 71 209 96 87 152 201 1

Um pouco mais informação:. O valor original é um C # DateTime, e deve representar uma data / hora cerca de 2 ou 3 semanas atrás

Foi útil?

Solução

(graças ao post de thomasrutter, que me deu a época FILETIME Windows):

A data prevista parece ser um Windows de 64 bits little-endian arquivo data-hora, 60 F3 47 d1 57 98 01 C9, o qual é equivalente ao quadword 01c99857d147f360 que, como é um número inteiro 128801567297500000

Este é "o número de intervalos de 100 nanossegundos que se passaram desde 12:00 à meia-noite de 1 de Janeiro, 1601 dC (dC) Tempo Universal Coordenado (UTC) "

Após a conversão, dá Qui, 26 de fevereiro de 2009 21:18:49 UTC

Exemplo de código:

<?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>

Outras dicas

outra referência que pode apontar para alguns mais relevante em formação. Neste caso, a data e hora do Windows, usado no registro. Aparentemente, estes também são armazenados como valores de 64 bits.

Isto está olhando um pouco mais útil, como ele menciona que termina em C? 01 é um indicador deste tipo de data. Note-se que este é little endian (ie, a maioria dos bytes significativos à direita) para que os bytes estão na ordem byte errado para hexdec () sem reverter-lhes 2 dígitos hexadecimais de cada vez (ou seja, começar com mais à direita 2 dígitos hexadecimais, em seguida, ao lado de dois, etc).

E, de acordo com este fonte ,

Uma única carraça representa cem nanossegundos ou uma de dez milésimo de segundo. O valor dessa propriedade representa o número de intervalos de 100 nanossegundos que têm decorrido desde 12:00:00 meia-noite, 1º de janeiro de 0001, o que representa.

O que pode te enganar é que, infelizmente, PHP não pode lidar com 64 bits inteiros. Ele consegue no máximo 32 bits. Flutuadores vai ajudar, mas isso não impede que hexdec () em si a partir de apenas lidar com ints. Por isso, pode ser complicado fazer essa matemática; você ainda pode precisar dividi-lo em dois, em seguida, combiná-los em uma bóia, lançando o valor mais significativo para flutuar e multiplicando-o por 2 ^ 32 também escalado como float. É possível que PHP construído para hardware de 64 bits pode não tem esta limitação, mas eu não sei ao certo.

Eu acredito que você pode convertê-lo em um int decimal com hexdec(). Isso vai ser um timestap que você pode trabalhar com date().

O valor que você deu é de 36 dígitos hexadecimais, ou seja, 18 bytes-estima. Isso é não um Int64 convertido em hexadecimal.

Volte para quem você deu a explicação do formato e pedir-lhes para dizer a verdade desta vez:)

EDIT: Ok, o próximo passo: descobrir o que esse número é realmente significou a média. Carrapatos desde 1970? Milissegundos desde 1 AD? Você sabe o que seu exemplo string é a intenção de representar?

Se for o mesmo tipo de 64 bit hex NTP timestamp como descrito aqui , então você deve estar dividindo a string hex igualmente em dois, ou seja, imaginar um separador entre os 8 primeiros dígitos hexadecimais e os outros 8.

Converter a primeira metade (no valor primeiros 32 bits') em um número inteiro com hexdec (), e este número inteiro será o valor de data no formato timestamp Unix (segundos desde 1 de janeiro de 1970 GMT), que você pode usar na data (função), etc.

A segunda parte é seções fracionários, útil se você precisa mais fina precisão de um segundo (embora não muitas aplicações fazer, e PHP é construído em data e hora funções não exceto para microtime ()). Você também iria converter isso em decimal com hexdec ().

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top