A mudança de datas não funciona conforme o esperado

A mudança de datas não funciona conforme o esperado

Eu tenho um arquivo com registros neste formato:

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

No entanto, depois de aplicar a transformação para mudar para 7 dias no passado, ela não funciona para datas de 28 de março a 3 de abril. No entanto, a mesma lógica de código está funcionando bem em 27 de março e 4 de abril. Não consigo entender por que isso não funciona por apenas uma semana. Esta é a saída

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

A lógica usada aqui é:

    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
}

Responder1

Seus cálculos são feitos no horário local e você será afetado pela mudança para o horário de verão no dia 27 de março.

Para fazer o cálculo no horário UTC (os carimbos de data e hora do Unix não estão no horário local), usando uma versão recente do GNU awk, certifique-se de passar um extra 1como último argumento para mktime():

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

Esta é uma awkextensão GNU disponível na awkversão GNU 4.2.0+.

Como alternativa, você pode evitar usar um horário próximo à meia-noite (UTC) como horário de referência do dia:

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

Isso faria com que funcionasse em awkimplementações GNU mais antigas e em qualquer outra awkque tivesse as funções necessárias.

Outra alternativa é fazer o script ser executado com um fuso horário local alterado:

TZ=UTC awk -f script.awk inputfile

Isso define a TZvariável de ambiente para UTCa execução do awkscript, o que altera o fuso horário usado pelas mktime()funções relacionadas.

Responder2

Usando Raku (anteriormente conhecido como Perl_6)

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

Exemplo de entrada (linhas em branco removidas):

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

Saída de amostra:

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

Resumidamente, os sinalizadores linewise (impressão automática) do Raku -pesão usados, em conjunto com o s///operador familiar. Os dígitos são capturados em variáveis ​​de correspondência $0, $1e $2com parênteses, e marcadores de captura <( … )>são empregados para eliminar todos os outros elementos da correspondência.

Na substituição, Raku executa código dentro de um { … }bloco. As $0capturas $1, e $2são stringificadas com traços apropriados ( -), e essa string é reconhecida como um Dateobjeto, no qual o earlier(:7days)método pode ser chamado. [Nota: alguns usuários podem achar que a escrita earlier(days => 7)é uma sintaxe mais familiar - qualquer uma das formas funciona]. Uma vez que o Dateobjeto é atrasado 7 dias, ele é Strinificado e substusado para remover os traços ( -) no retorno.

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

informação relacionada