Help me translate long value, expressed in hex, back in to a date/time

后端 未结 5 856
再見小時候
再見小時候 2021-01-26 02:08

I have a date value, which I\'m told is 8 bytes, a single \"long\" (aka int64) value, and converted to hex:

60f347d15798c901

How can I convert

5条回答
  •  再見小時候
    2021-01-26 02:39

    (Thanks to thomasrutter's post, which gave me the Windows filetime epoch):

    The given date appears to be a Windows 64-bit little-endian file date-time, 60 f3 47 d1 57 98 c9 01, which is equivalent to the quadword 01c99857d147f360 which as an integer is 128801567297500000

    This is "the number of 100-nanosecond intervals that have elapsed since 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC)"

    After conversion, it gives Thu, 26 February 2009 21:18:49 UTC

    Sample code:

    '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);
    
    ?>
    
    
    Windows datetime test code
    
    
        

    Result: Quad:
    Int:
    Unix timestamp:
    Date:

提交回复
热议问题