Tengo un archivo con registros en este 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
Sin embargo, después de aplicar la transformación para cambiarlos a 7 días atrás, no funciona para las fechas del 28 de marzo al 3 de abril. Sin embargo, la misma lógica de código funciona bien el 27 de marzo y el 4 de abril. No puedo entender por qué esto no funciona solo durante una semana. Esta es la salida
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
La lógica utilizada aquí es:
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
}
Respuesta1
Sus cálculos se realizan en hora local y le afecta el cambio al horario de verano el 27 de marzo.
Para hacer el cálculo en hora UTC (las marcas de tiempo de Unix no están en hora local), usando una versión reciente de GNU awk
, asegúrese de pasar un extra 1
como último argumento a mktime()
:
t = mktime(sprintf("%4d %.2d %.2d 00 00 00",
substr($1,2,4),
substr($1,6,2),
substr($1,8,2)), 1);
Esta es una awk
extensión de GNU disponible en la awk
versión GNU 4.2.0+.
Como alternativa, podrías evitar utilizar una hora cercana a la medianoche (UTC) como hora del día de referencia:
t = mktime(sprintf("%4d %.2d %.2d 12 00 00",
substr($1,2,4),
substr($1,6,2),
substr($1,8,2)));
Esto haría que funcione en awk
implementaciones GNU más antiguas y en cualquier otra awk
que tenga las funciones requeridas.
Otra alternativa más es hacer que el script se ejecute con una zona horaria local alterada:
TZ=UTC awk -f script.awk inputfile
Esto establece la TZ
variable de entorno UTC
para la ejecución del awk
script, lo que altera la zona horaria utilizada por las mktime()
funciones relacionadas.
Respuesta2
Usando Raku (anteriormente conocido como Perl_6)
raku -pe 's/^ D <( (\d**4)(\d**2)(\d**2) )> \, /{ "$0-$1-$2".Date.earlier(:7days).Str.subst("-", :g); }/;'
Entrada de muestra (se eliminaron las líneas en blanco):
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
Salida de muestra:
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
Brevemente, se utilizan los indicadores lineales (impresión automática) de Raku -pe
, junto con el s///
operador familiar. Los dígitos se capturan en variables de coincidencia $0
, $1
y $2
con pares, y <( … )>
se emplean marcadores de captura para descartar todos los demás elementos de la coincidencia.
En el reemplazo, Raku ejecuta código dentro de un { … }
bloque. Las $0
capturas $1
, y $2
se encadenan con guiones apropiados ( -
), y esta cadena se reconoce como un Date
objeto sobre el cual earlier(:7days)
se puede invocar el método. [Nota: algunos usuarios pueden encontrar que escribir earlier(days => 7)
es una sintaxis más familiar; cualquiera de las dos formas funciona]. Una vez que el Date
objeto se retrasa 7 días, se Str
-ingifica y subst
se utiliza para eliminar los guiones ( -
) en la devolución.
https://docs.raku.org/routine/Fecha
https://docs.raku.org/routine/Dateish
https://raku.org