3

次のようなタイムスタンプを持つログ ファイルがあります。

Fri Nov 30 10:19:35:152.92 PST 2012
Fri Nov 30 10:19:35:228.8 PST 2012
or even:
Thu Nov 29 14:20:58:3.44 PST 2012
Fri Nov 30 10:27:50:742 PST 2012

私は Perl に非常に慣れていませんが、ここにいる全員が Perl を使用しているので、すぐに習得しようとしています (この仕事を始めたばかりです)。タイムスタンプを比較できるようにする必要があります (時間が重複する可能性があり、結果のファイルですべてのタイムスタンプが連続している必要があるログファイルをマージしています)。これは、時間を抽出して比較可能な文字列にフォーマットするサブルーチンです。

my %months = ( 'Jan'=>1, 'Feb'=>2, 'Mar'=>3, 'Apr'=>4, 'May'=>5, 'Jun'=>6, 'Jul'=>7,
'Aug'=>8, 'Sep'=>9, 'Oct'=>10, 'Nov'=>11, 'Dec'=>12);

sub to_comparable {
    my $date = shift;
    my ($mmm, $d, $H, $M, $S, $mils, $fra, $tz, $Y) = $date =~ 
        m{^<\w{3} (\w{3}) (\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2}):(\d{1,3})[.]{0,1}(\d{0,2}) (\w{3}) (\d{4})>}
            or return undef;
    if ($mils eq "") { $mils = 0; }
    if ($fra eq "") { $fra = 0; }
    my $m = $months{$mmm};
    return sprintf('%04d%02d%02d%02d%02d%02d%03d%02d',$Y,$m,$d,$H,$M,$S,$mils,$fra);
}

タイムスタンプがすべて同じタイムゾーンから来ている限り、これは問題なく機能します。ただし、標準時と夏時間からの変更と重複するログ (または他のタイムゾーンからのログを取得する場合) に対しては、それらが正常に機能することを確認したいと考えています。おそらく DateTime パッケージでうまくいくと思いましたが、タイムゾーンを使用して同等の時間を取得する方法について混乱しています。タイムゾーンに使用するものを除いて、日付/時刻オブジェクトを作成できます。私のテストでは、月をマッピングした後に次を追加しました。

    my $ns = sprintf('%03d.%02d',$mils,$fra);
    $ns *= 1000;

    my $dt = DateTime->new(
      year       => $Y,
      month      => $m,
      day        => $d,
      hour       => $H,
      minute     => $M,
      second     => $S,
      nanosecond => $ns,
      time_zone  => "$tz",
  );

これにより、「無効なオフセット: PST」というエラーが発生します。「表示以外の目的でこれらの名前に依存しないことを強くお勧めします。これらの名前は公式のものではなく、それらの多くは Olson データベース管理者の発明です。さらに、これらの名前はたとえば、-0500 と +1000/+1100 の両方に「EST」があります。「タイムゾーンの短い名前は一意ではないため、そのような名前から実際のタイムゾーンを特定しようとすると、推測が必要になります。代わりに長い名前を使用してください。」

与えられたタイムゾーンの表示を制御できないため、今何をすべきかわかりません。「PST8PDT」または「America/Los_Angeles」を使用する場合、指定された時間が標準時間か夏時間かをどのように示しますか? また、米国のタイムゾーンから DateTime が受け入れるタイムゾーンへの変換はありますか? 誰かがこれを理解するのを手伝ってくれますか? ログ ファイルをマージするという一見ささいなプロジェクトに時間がかかってしまい、上司は私がばかだと思っています。:-(

4

1 に答える 1

7

非常に多くのログ ファイルでタイムスタンプ形式の選択が不十分なのが残念です。RFC 3339 (これもISO 8601形式の 1 つです)をお勧めします。

とにかく、質問に進みます。

time_zoneソース システムの識別子の定義を、コンストラクタの引数で受け入れられる標準名またはオフセットに変換するためのマッピングを作成します。

my %time_zones = (
   EST => '-0500',
   PST => '-0800',
   PDT => '-0700',
   ...
);

time_zone次に、引数を使用してオフセットを渡します。

$ perl -MDateTime -E'say
   DateTime->new(
      year => 2012, month => 11, day => 4,
      hour => 1, minute => 16, second => 0,
      time_zone => "-0800",
   )->epoch;
'
1352020560

$ perl -MDateTime -E'say
   DateTime->new(
      year => 2012, month => 11, day => 4,
      hour => 1, minute => 16, second => 0,
      time_zone => "-0700",
   )->epoch;
'
1352016960

$ perl -E'say 1352020560 - 1352016960'
3600
于 2012-12-11T00:47:11.893 に答える