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 1
como ú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 awk
extensão GNU disponível na awk
versã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 awk
implementações GNU mais antigas e em qualquer outra awk
que 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 TZ
variável de ambiente para UTC
a execução do awk
script, 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 -pe
são usados, em conjunto com o s///
operador familiar. Os dígitos são capturados em variáveis de correspondência $0
, $1
e $2
com 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 $0
capturas $1
, e $2
são stringificadas com traços apropriados ( -
), e essa string é reconhecida como um Date
objeto, 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 Date
objeto é atrasado 7 dias, ele é Str
inificado e subst
usado para remover os traços ( -
) no retorno.
https://docs.raku.org/routine/Date
https://docs.raku.org/routine/Dateish
https://raku.org