El cambio de fechas no funciona como se esperaba

El cambio de fechas no funciona como se esperaba

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 1como ú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 awkextensión de GNU disponible en la awkversió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 awkimplementaciones GNU más antiguas y en cualquier otra awkque 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 TZvariable de entorno UTCpara la ejecución del awkscript, 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, $1y $2con 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 $0capturas $1, y $2se encadenan con guiones apropiados ( -), y esta cadena se reconoce como un Dateobjeto 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 Dateobjeto se retrasa 7 días, se Str-ingifica y substse utiliza para eliminar los guiones ( -) en la devolución.

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

información relacionada