Domanda

Ho un valore di data, che mi viene detto è di 8 byte, un singolo "long". (aka int64) e convertito in esadecimale:

60f347d15798c901

Come posso convertire questo e valori come questo, usando PHP, in un orario / data?

La conversione in decimale mi dà: 96 243 71 209 87 152 201 1

Altre informazioni: il valore originale è un DateTime C # e dovrebbe rappresentare un orario / data circa 2 o 3 settimane fa.

È stato utile?

Soluzione

(Grazie al post di thomasrutter, che mi ha dato l'epoca di Filetime di Windows):

La data indicata sembra essere una data-ora del file little-endian di Windows a 64 bit, 60 f3 47 d1 57 98 c9 01, che equivale alla quadword 01c99857d147f360 quale come intero è 128.801.567,2975 miliardi

Questo è " il numero di intervalli di 100 nanosecondi che sono trascorsi dalla mezzanotte del 1 gennaio alle 12:00 1601 d.C. (C.E.) Coordinated Universal Time (UTC) "

Dopo la conversione, dà Giovedì 26 febbraio 2009 21:18:49 UTC

Codice di esempio:

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

(Grazie al post di thomasrutter, che mi ha dato l'epoca di Filetime di Windows):

La data indicata sembra essere una data-ora del file little-endian di Windows a 64 bit, 60 f3 47 d1 57 98 c9 01, che equivale alla quadword 01c99857d147f360 quale come intero è 128.801.567,2975 miliardi

Questo è " il numero di intervalli di 100 nanosecondi che sono trascorsi dalla mezzanotte del 1 gennaio alle 12:00 1601 d.C. (C.E.) Coordinated Universal Time (UTC) "

Dopo la conversione, dà Giovedì 26 febbraio 2009 21:18:49 UTC

Codice di esempio:

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

(Grazie al post di thomasrutter, che mi ha dato l'epoca di Filetime di Windows):

La data indicata sembra essere una data-ora del file little-endian di Windows a 64 bit, 60 f3 47 d1 57 98 c9 01, che equivale alla quadword 01c99857d147f360 quale come intero è 128.801.567,2975 miliardi

Questo è " il numero di intervalli di 100 nanosecondi che sono trascorsi dalla mezzanotte del 1 gennaio alle 12:00 1601 d.C. (C.E.) Coordinated Universal Time (UTC) "

Dopo la conversione, dà Giovedì 26 febbraio 2009 21:18:49 UTC

Codice di esempio:

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

Altri suggerimenti

Ho trovato un altro riferimento che potrebbe indicare alcuni più pertinenti informazione. In questo caso, una data e ora di Windows utilizzate nel registro. Apparentemente questi sono anche memorizzati come valori a 64 bit.

Questo sembra un po 'più utile, in quanto menziona che terminare in C? 01 è un indicatore di questo tipo di data. Si noti che questo è un piccolo endian (ovvero i byte più significativi a destra), quindi i byte sono nell'ordine byte errato per hexdec () senza invertirli 2 cifre esadecimali alla volta (ovvero, iniziare con l'estrema destra 2 cifre esadecimali, poi i prossimi due, ecc.)

E, secondo questo fonte ,

  

Un singolo segno di spunta rappresenta cento nanosecondi o un decimilionesimo di secondo. Il valore di questa proprietà rappresenta il numero di intervalli di 100 nanosecondi che sono trascorsi dalle 12:00:00 di mezzanotte, 1 gennaio, 0001, che rappresenta.

Ciò che potrebbe farti inciampare è che sfortunatamente PHP non può gestire numeri interi a 64 bit. Massima a 32 bit. I float aiuteranno, ma ciò non impedisce a hexdec () stesso di gestire solo gli ints. Quindi può essere complicato fare questa matematica; potresti ancora aver bisogno di dividerlo in due, quindi combinarli in un float lanciando il valore più significativo per float e moltiplicandolo per 2 ^ 32 anche lanciare come float. È possibile che PHP creato per l'hardware a 64 bit non abbia questa limitazione, ma non lo so per certo.

Credo che tu possa convertirlo in un decimale con hexdec (). Questo sarà un timestap su cui puoi lavorare con date ().

Il valore che hai dato è di 36 cifre esadecimali, vale a dire 18 byte. Questo è non un Int64 convertito in esadecimale.

Torna a chiunque ti abbia dato la spiegazione del formato e chiedi loro di dirti la verità questa volta :)

EDIT: Okay, prossimo passo: scopri cosa significa effettivamente quel numero. Zecche dal 1970? Millis dal 1 d.C. Sai cosa rappresenta la tua stringa di esempio?

Se si tratta dello stesso tipo di Timestamp NTP esadecimale a 64 bit come descritto qui , quindi dovresti dividere la stringa esadecimale equamente in due, cioè immaginare un separatore tra le prime 8 cifre esadecimali e le altre 8.

Converti la prima metà (valore dei primi 32 bit) in un numero intero con hexdec () e questo numero intero sarà il valore della data nel formato timestamp Unix (secondi dal 1 gennaio 1970 GMT) che puoi quindi utilizzare nella data () funzione, ecc.

La seconda parte è costituita da sezioni frazionarie, utili se hai bisogno di una precisione più fine di un secondo (anche se non molte applicazioni lo fanno, e le funzioni di data e ora integrate di PHP non fanno eccezione per microtime ()). Dovresti anche convertirlo in decimale con hexdec ().

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top