Вы не можете использовать pack , потому что он всегда хочет начать с границы байта.Некоторые из этих значений также выходят за границы байтов, поэтому вы не хотите иметь дело с отдельными байтами (хотя слова будут работать).Проще всего замаскировать и сдвинуть.
В этом примере я настроил маски, чтобы мне не пришлось слишком задумываться об этом, а затем использую их для извлечения значений из строки.Я действительно ничего не знаю о формате времени DOS, но из того, что я прочитал, вы должны умножить секунды на 2 (обратите внимание, что это только пять бит):
use 5.010;
use strict;
use warnings;
use Data::Dumper;
# seconds minutes hours day month years from 1980
# 5 bits 6 5 5 4 7
my $datetime = 0b11011_000011_11111_01100_1011_0001000;
my $parsed = parse( $datetime );
print Dumper( $parsed );
sub parse {
my( $datetime ) = @_;
state $masks = make_masks();
my %this = map {
$_, ( $datetime & $masks->{$_}[0] ) >> $masks->{$_}[1]
} keys %$masks;
$this{seconds} *= 2;
$this{years} += 1980;
return \%this;
}
sub make_masks {
my %masks = (
seconds => [ 0b11111, 27 ],
minutes => [ 0b111111, 21 ],
hours => [ 0b11111, 16 ],
day => [ 0b11111, 11 ],
month => [ 0b1111, 7 ],
years => [ 0b1111111, 0 ],
);
foreach my $key ( sort { $masks{$a}[1] <=> $masks{$b}[1] } keys %masks ) {
$masks{$key}[0] <<= $masks{$key}[1];
}
return \%masks;
}
Мой вывод простохеш:
$VAR1 = {
'seconds' => 54,
'hours' => 31,
'years' => 1988,
'month' => 11,
'minutes' => 3,
'day' => 12
};