in reply to Practical Example of Converting Packed Value

I'd probably use just bitwise math, but as you've asked for pack, here's one way:

$s = chr( 0xa8 ) . chr( 0x38 );; print unpack 'b*', $s;; 0001010100011100 print unpack 'A5A4A7', unpack 'b*', $s;; 00010 1010 0011100 print map{ unpack 'C', pack 'b*', $_ } unpack 'A5A4A7', unpack 'b*', $ +s;; 8 5 28 ( $day, $month, $year ) = map{ unpack 'C', pack 'b*', $_ } unpack 'A5A4A7', unpack 'b*', $ printf "%4d-%02d-%02d\n", 1980+$year, $month, $day;; 2008-05-08

Updated: Or using bitwise math:

$s = chr( 0xa8 ) . chr( 0x38 );; $n = unpack 's', $s;; ( $day, $month, $year ) = ( $n & 0x1f, ( $n & 0x1e0 ) >> 5, ( $n & 0xfe00 ) >> 9 );; printf "%4d-%02d-%02d\n", 1980+$year, $month, $day;; 2008-05-08

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^2: Practical Example of Converting Packed Value
by Jim (Curate) on Dec 01, 2008 at 00:30 UTC
    Thank you, ++BrowserUk!

    I actually didn't ask for solutions using pack/unpack; I only described the representation format as "packed". Please feel free to show me how you would do it using bitwise math.

    Jim

      Please feel free to show me how you would do it using bitwise math.

      That's what the second snippet does. First, unpack 's' is used to convert the bytes representing a number into something Perl understands to be a number. Then bit math is performed to extract each of the fields.

        Yeah, BrowserUk was adding that last bit while I was too hastily replying to his very helpful post.

        I understand the bitmask and the right-shift operations much better now. This example had the concreteness and immediacy I needed. It helps me a lot to display the bitmask AND operation in binary.

        my $day = ( $short_int & 0b0000000_0000_11111 ) ; my $month = ( $short_int & 0b0000000_1111_00000 ) >> 5 ; my $year = ( $short_int & 0b1111111_0000_00000 ) >> 9 ; my $date = sprintf "%04d-%02d-%02d", 1980 + $year, $month, $day;
        Is there any reason not to use these binary constants instead of hexadecimal constants in the real program?

        I suppose in a real program, the binary/hexadecimal constants and the year 1980 would be symbolic constants; e.g., DAY_MASK and EPOCH_YEAR. Or not.