Ayúdame a traducir el valor largo, expresado en hexadecimal, de nuevo en una fecha / hora

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

Pregunta

Tengo un valor de fecha, y me dicen que es de 8 bytes, un solo " long " (aka int64) valor, y convertido a hexadecimal:

60f347d15798c901

¿Cómo puedo convertir esto y valores como este, usando PHP, en una fecha / hora?

Convertirlo a decimal me da: 96 243 71 209 87 152 201 1

Un poco más de información: el valor original es un C # DateTime, y debe representar una hora / fecha hace aproximadamente 2 o 3 semanas.

¿Fue útil?

Solución

(Gracias a la publicación de thomasrutter, que me dio la época del tiempo de archivo de Windows):

La fecha dada parece ser una fecha y hora del archivo little-endian de Windows de 64 bits, 60 f3 47 d1 57 98 c9 01, que es equivalente a la quadword 01c99857d147f360 que como un entero es 128801567297500000

Este es " el número de intervalos de 100 nanosegundos que han transcurrido desde las 12:00 de la medianoche del 1 de enero de 1601 A.D. (C.E.) Tiempo Universal Coordinado (UTC) "

Después de la conversión, da Jueves, 26 de febrero de 2009 21:18:49 UTC

Código de muestra:

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

(Gracias a la publicación de thomasrutter, que me dio la época del tiempo de archivo de Windows):

La fecha dada parece ser una fecha y hora del archivo little-endian de Windows de 64 bits, 60 f3 47 d1 57 98 c9 01, que es equivalente a la quadword 01c99857d147f360 que como un entero es 128801567297500000

Este es " el número de intervalos de 100 nanosegundos que han transcurrido desde las 12:00 de la medianoche del 1 de enero de 1601 A.D. (C.E.) Tiempo Universal Coordinado (UTC) "

Después de la conversión, da Jueves, 26 de febrero de 2009 21:18:49 UTC

Código de muestra:

<*>GET["dt"]) ? strval(

(Gracias a la publicación de thomasrutter, que me dio la época del tiempo de archivo de Windows):

La fecha dada parece ser una fecha y hora del archivo little-endian de Windows de 64 bits, 60 f3 47 d1 57 98 c9 01, que es equivalente a la quadword 01c99857d147f360 que como un entero es 128801567297500000

Este es " el número de intervalos de 100 nanosegundos que han transcurrido desde las 12:00 de la medianoche del 1 de enero de 1601 A.D. (C.E.) Tiempo Universal Coordinado (UTC) "

Después de la conversión, da Jueves, 26 de febrero de 2009 21:18:49 UTC

Código de muestra:

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

Otros consejos

Encontré otra referencia que podría apuntar a algunos más relevantes información. En este caso, una fecha y hora de Windows como se utiliza en el registro. Al parecer, estos también se almacenan como valores de 64 bits.

Esto parece un poco más útil, ya que menciona que terminar en C? 01 es un indicador de este tipo de fecha. Tenga en cuenta que se trata de little endian (es decir, los bytes más significativos a la derecha), por lo que los bytes están en el orden de bytes incorrecto para hexdec () sin invertirlos 2 dígitos hexadecimales a la vez (es decir, comience con los 2 dígitos hexadecimales más a la derecha) luego los dos siguientes, etc).

Y, de acuerdo con esto fuente ,

  

Un solo tick representa cien nanosegundos o un diez millonésimo de segundo. El valor de esta propiedad representa el número de intervalos de 100 nanosegundos que han transcurrido desde las 12:00:00 de la medianoche del 1 de enero de 0001, lo que representa.

Lo que podría hacerte tropezar es que, lamentablemente, PHP no puede manejar enteros de 64 bits. Tiene un máximo de 32 bits. Los flotadores ayudarán, pero eso no impide que hexdec () solo haga frente a los ints. Entonces puede ser complicado hacer estas matemáticas; es posible que aún debas dividirlo en dos, luego combinarlos en un flotador lanzando el valor más significativo para flotar y multiplicarlo por 2 ^ 32 que también se lanza como flotador. Es posible que PHP creado para hardware de 64 bits no tenga esta limitación, pero no estoy seguro.

Creo que puedes convertirlo a decimal int con hexdec (). Ese será un cronograma en el que puedes trabajar con date ().

El valor que ha dado es de 36 dígitos hexadecimales, es decir, de 18 bytes. Eso es no un Int64 convertido a hexadecimal.

Vuelve con quien te dio la explicación del formato y pídele que te diga la verdad esta vez :)

EDITAR: Bueno, próximo paso: descubra qué significa realmente ese número. ¿Garrapatas desde 1970? Millis desde AD 1? ¿Sabes lo que significa representar tu cadena de ejemplo?

Si es el mismo tipo de La marca de tiempo NTP hexadecimal de 64 bits como se describe aquí , entonces debe dividir la cadena hexadecimal en dos, es decir, imagine un separador entre los primeros 8 dígitos hexadecimales y los otros 8.

Convierta la primera mitad (el valor de los primeros 32 bits) en un entero con hexdec (), y este entero será el valor de fecha en formato de marca de tiempo de Unix (segundos desde el 1 de enero de 1970 GMT) que luego puede usar en la fecha () función, etc.

La segunda parte es secciones fraccionarias, útil si necesita una precisión más fina que un segundo (aunque no muchas aplicaciones, y las funciones de fecha y hora integradas de PHP no están a excepción de microtime ()). También convertirías esto a decimal con hexdec ().

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top