日付変換が期待どおりに機能しません。

日付変換が期待どおりに機能しません。

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

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日にはうまく機能します。なぜ一週間だけ働かないのかわかりません。これが出力です

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最後1の引数として渡す必要がありますmktime()

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

これはGNUバージョン4.2.0+awkで利用可能なGNU拡張です。awk

あるいは、真夜中(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の1行ずつ(自動印刷)-peフラグはおなじみの演算子で使用されますs///。数字は括弧付きの一致変数、およびにキャプチャされ、$0キャプチャマーカーは一致$1の他のすべての要素を削除するために使用されます。$2<( … )>

代わりに、Rakuは{ … }ブロック内でコードを実行します。 、およびキャプチャは適切なダッシュ()で文字列化され、文字列はメソッドを呼び出すことができるオブジェクトとして認識されます$0。 [注:一部のユーザーは、より使い慣れた構文を書くことを見つけるかもしれません。どちらの形式も有効です。]オブジェクトが7日にリセットされると、記号で表示され、戻り時にダッシュ()を削除するために使用されます。$1$2-Dateearlier(:7days)earlier(days => 7)DateStrsubst-

https://docs.raku.org/routine/Date
https://docs.raku.org/routine/Dateish
https://raku.org

関連情報