Perl:在二进制文件中解码时间戳

Perl:在二进制文件中解码时间戳,perl,datetime,decode,binaryfiles,Perl,Datetime,Decode,Binaryfiles,我正在解码一个固定宽度的二进制文件。其中一个字段是时间戳。它有5个字节长,格式为SS-MS。前四个字节表示距离数据2000/01/01 00:00:00的秒数,MS字节通过表示秒内10ms间隔倍数的数量(值范围为0到99),提供了更高的精度 此字段的编码类型为二进制。例如:回答时间是2008-4-2814:42:51.15,字段中填充了0F A8 9E EB 0F 如何在Perl中解析二进制数据并将其转换为时间戳格式?使用CPAN模块: use Time::Moment; my $data

我正在解码一个固定宽度的二进制文件。其中一个字段是时间戳。它有5个字节长,格式为
SS-MS
。前四个字节表示距离数据2000/01/01 00:00:00的秒数,
MS
字节通过表示秒内10ms间隔倍数的数量(值范围为0到99),提供了更高的精度

此字段的编码类型为二进制。例如:回答时间是
2008-4-2814:42:51.15
,字段中填充了
0F A8 9E EB 0F

如何在Perl中解析二进制数据并将其转换为时间戳格式?

使用CPAN模块:

use Time::Moment;

my $data    = 0x0FA89EEB0F;
my $seconds = $data >> 8;     # Right shift to remove fractional second.
my $milliseconds = 10 * ( $data & 0xff );    # Hundredths to Milli

my $tm = Time::Moment->new( year => 2000, month => 1, day => 1 );  #base datetime
my $tm2 = $tm->plus_seconds($seconds)->plus_milliseconds($milliseconds);
print $tm2, "\n";    #<-- prints: 2008-04-28T14:42:51.150Z
使用时间::瞬间;
my$data=0x0FA89EEB0F;
我的$seconds=$data>>8;#右移以删除分数秒。
我的$millizes=10*($data&0xff);#百分之一到百万
my$tm=时间::时刻->新(年=>2000年,月=>1,日=>1)#基准日期时间
我的$tm2=$tm->plus_seconds($seconds)->plus_毫秒($ms);
打印$tm2,“\n”# 该模块适合于此目的,并且自Perl5的版本10以来一直是一个核心模块,因此不需要安装

另外,是从字符串中提取数据字段的最方便的方法

看起来是这样的。我使用了
pack
来创建您描述的文件内容,并且我必须将分数秒分别附加到结果中,因为
Time::Piece
不支持部分秒

use strict;
use warnings;

use Time::Piece;

my $data = pack 'H*', '0FA89EEB0F';

print decode_timestamp($data), "\n";

sub decode_timestamp {
   my ($seconds, $ms) = unpack 'N C', shift;
   my $base = Time::Piece->strptime('2000-01-01', '%Y-%m-%d');
   ($base + $seconds)->strftime('%Y-%m-%d %H:%M:%S') . sprintf '.%02d', $ms;
}   
输出

2008-04-28 14:42:51.15

Miguel Prz,
day=>21
可能应该是
day=>1
。您的掩码中的Fs太少了。它应该是
0xFFFFFF00
-您很幸运数据中的顶部字节小于
0x10
!此外,在右移之前根本不需要屏蔽该值:不需要的字节只是从末尾脱落,您不需要先将其设置为零。基准日期应该是
2000年1月1日
,而不是
2000年1月21日
,因此您的结果会晚20天。最后,底部字节的单位是10毫秒,或100分之一秒,因此小数部分应该是
.15
,而不是
.015
。谢谢!尤其是核心模块的使用。