日付の変更が期待どおりに機能しない

日付の変更が期待どおりに機能しない

次の形式のレコードを含むファイルがあります:

D20220327,S2927,977,1

D20220328,S2927,977,1

D20220329,S2927,977,1

D20220330,S2927,977,1

D20220331,S2927,977,1

D20220401,S2927,977,1

D20220402,S2927,977,1

D20220403,S2927,977,1

D20220404,S2927,977,1

しかし、これらを7日前にシフトする変換を適用した後、3月28日から4月3日までの日付では機能しません。ただし、同じコードロジックは3月27日と4月4日には正常に機能します。なぜこれが1週間だけ機能しないのかわかりません。これが出力です。

D20220320,S2927,977,1 -- correct

D20220320,S2927,977,1 -- incorrect 

D20220321,S2927,977,1 -- incorrect

D20220322,S2927,977,1 -- incorrect

D20220323,S2927,977,1 -- incorrect

D20220324,S2927,977,1 -- incorrect

D20220325,S2927,977,1 -- incorrect

D20220326,S2927,977,1 -- incorrect

D20220328,S2927,977,1 -- correct

ここで使用されるロジックは次のとおりです:

    BEGIN {
        OFS = FS = ","
}

{
        t = mktime(sprintf("%4d %.2d %.2d 00 00 00",
                substr($1,2,4),
                substr($1,6,2),
                substr($1,8,2)));

        $1 = substr($1,1,1) strftime("%Y%m%d", t - 7*24*60*60)

        print
}

答え1

計算は現地時間で行われ、3 月 27 日の夏時間への切り替えの影響を受けます。

代わりに UTC 時間で計算を行うには (Unix タイムスタンプはローカル時間ではありません)、GNU の最新リリースを使用して、最後の引数として をawk必ず渡してください。1mktime()

t = mktime(sprintf("%4d %.2d %.2d 00 00 00",
        substr($1,2,4),
        substr($1,6,2),
        substr($1,8,2)), 1);

awkこれは、GNUawkリリース 4.2.0 以降で利用可能なGNU 拡張機能です。

代わりに、午前 0 時 (UTC) 付近の時刻を参照時刻として使用しないようにすることもできます。

t = mktime(sprintf("%4d %.2d %.2d 12 00 00",
        substr($1,2,4),
        substr($1,6,2),
        substr($1,8,2)));

これにより、古い GNU 実装や、必要な機能を備えたawkその他の実装でも動作するようになります。awk

さらに別の方法としては、変更されたローカル タイム ゾーンでスクリプトを実行することです。

TZ=UTC awk -f script.awk inputfile

これにより、スクリプトの実行用にTZ環境変数が に設定され、および関連関数で使用されるタイムゾーンが変更されます。UTCawkmktime()

答え2

Raku (旧称 Perl_6) の使用

raku -pe 's/^ D <( (\d**4)(\d**2)(\d**2) )> \, /{ "$0-$1-$2".Date.earlier(:7days).Str.subst("-", :g); }/;'

サンプル入力(空白行は削除されています):

D20220327,S2927,977,1
D20220328,S2927,977,1
D20220329,S2927,977,1
D20220330,S2927,977,1
D20220331,S2927,977,1
D20220401,S2927,977,1
D20220402,S2927,977,1
D20220403,S2927,977,1
D20220404,S2927,977,1

サンプル出力:

D20220320,S2927,977,1
D20220321,S2927,977,1
D20220322,S2927,977,1
D20220323,S2927,977,1
D20220324,S2927,977,1
D20220325,S2927,977,1
D20220326,S2927,977,1
D20220327,S2927,977,1
D20220328,S2927,977,1

簡単に言うと、Raku の行単位 (自動印刷)-peフラグが、使い慣れた演算子と組み合わせて使用​​されますs///。数字は、括弧で囲まれた一致変数$0$1$2にキャプチャされ、キャプチャ マーカーを<( … )>使用して一致のその他のすべての要素が削除されます。

置換では、Raku は{ … }ブロック内のコードを実行します。$0、、$1および$2キャプチャは適切なダッシュ ( -) で文字列化され、この文字列はDateオブジェクトとして認識され、メソッドを呼び出すことができます。[注: ユーザーによっては、 の記述の方が馴染みのある構文であると感じるかもしれません。どちらの形式でもearlier(:7days)機能します]。オブジェクトが 7 日間戻されると、オブジェクトは-ing 化され、戻り値のダッシュ ( ) を削除するために使用されます。earlier(days => 7)DateStrsubst-

https://docs.raku.org/routine/日付
https://docs.raku.org/routine/Dateish
https://raku.org

関連情報