日期轉換未如預期進行

日期轉換未如預期進行

我有一個包含以下格式記錄的文件:

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)));

這將使它能夠在較舊的 GNUawk實現和任何其他awk具有所需功能的實現中工作。

另一個選擇是讓腳本以更改的本地時區運行:

TZ=UTC awk -f script.awk inputfile

這會將TZ環境變數設定UTC為執行腳本,從而變更相關函數awk使用的時區。mktime()

答案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。[注意:有些使用者可能會發現書寫是一種更熟悉的語法—兩種形式都有效]。一旦物件被設定回 7 天,它就會被符號化並用於刪除返回中的破折號 ( )。$1$2-Dateearlier(:7days)earlier(days => 7)DateStrsubst-

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

相關內容