Adicionando zeros à esquerda na data e hora

3

Eu tenho um csv contendo a seguinte estrutura de dados:

1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-1-5 1:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

Eu quero exibir as datas mês e dia como sempre com 2 dígitos. Eu também quero que o campo Horas hora seja sempre de 2 dígitos.

Essencialmente, adicione zeros à esquerda se os campos mês / dia / hora forem apenas um único dígito, como na linha de exemplo acima.

Usando o awk, como eu poderia conseguir o seguinte resultado:

1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
    
por GustavMahler 01.03.2018 / 14:47

5 respostas

8

Uma ótima ferramenta para processamento de texto é awk . O exemplo a seguir está usando o awk padrão no FreeBSD 11.1. @RomanPerekhrest tem uma solução elegante em outra resposta se você preferir o GNU awk.

Sua entrada é separada por vírgulas. Por isso, invocamos awk com o parâmetro -F, .

Podemos imprimir colunas usando a instrução print . $1 é a primeira coluna. $2 é a segunda coluna.

$ awk -F, '{ print $8 }' inputfile.csv
2017-1-5 1:07:09
2017-11-25 19:57:17

Isso nos dá a 8ª coluna para cada linha.

Este é o campo de data que você deseja manipular. Em vez de definir o delimitador usando o parâmetro da linha de comando, podemos fazê-lo como parte do script. FS para o delimitador de entrada e OFS para o delimitador de saída.

$ awk 'BEGIN { FS = "," } ; { print $8 }' inputfile.csv
2017-1-5 1:07:09
2017-11-25 19:57:17

Ao trabalhar com datas, geralmente prefiro usar o date util para garantir que eu os manipule corretamente. E eu não preciso me preocupar se estou usando o regular ou o GNU awk. Além disso, fico com uma grande falha de gordura se a data não for analisada corretamente.

O parâmetro interessante é:

-j     Specify we do not want to set the date at all
-f     The format string we use for input
+      The format string we use for output

Então, se executarmos isso por uma data:

$ date -j -f "%Y-%m-%d %H:%M:%S" +"%Y-%m-%d %H:%M:%S" "2017-1-5 1:07:09"
2017-01-05 01:07:09

Podemos então combinar isso com o awk. Observe como as aspas são escapadas . Este é provavelmente o maior obstáculo para um iniciante.

$ awk -F, '{ system("date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"")}' inputfile.csv
2017-01-05 01:07:09
2017-11-25 19:57:17

A chamada do sistema parece correta - mas infelizmente só nos permite capturar o código de retorno e imprime diretamente na saída. Para evitar isso, usamos o padrão cmd | getline . O exemplo simples a seguir irá ler a data atual no mydate:

$ awk 'BEGIN { cmd = "date"; cmd | getline mydate; close(cmd); print mydate }'
Thu Mar  1 16:26:15 CET 2018

Usamos a palavra-chave BEGIN , pois não temos dados para esse exemplo simples.

Então, vamos expandir isso:

awk 'BEGIN { FS=","; OFS=FS };
     { 
         cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"";
         cmd | getline firstdate;
         close(cmd);
         cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$9"\"";
         cmd | getline seconddate;
         close(cmd);
         print $1,$2,$3,$4,$5,$6,$7,firstdate,seconddate
     }' inputfile.csv

E podemos colapsá-lo para um verso:

awk 'BEGIN {FS=",";OFS=FS};{cmd="date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"";cmd | getline firstdate;close(cmd);cmd="date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$9"\"";cmd | getline seconddate;close(cmd);print $1,$2,$3,$4,$5,$6,$7,firstdate,seconddate}' inputfile.csv

O que me dá a saída:

1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

Adendo

Como o objetivo aqui é aprender bons hábitos, é melhor atualizar essa resposta. É um mau hábito repetir o código. Quando você começa a fazer isso, você deve dividir as coisas em uma função. Como você perceberá, o código abaixo se torna mais legível imediatamente.

awk 'function convertdate(the_date) {
         cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""the_date"\"";
         cmd | getline formatted_date;
         close(cmd);
         return formatted_date
     }
     BEGIN { FS=","; OFS=FS };
     { 
         print $1,$2,$3,$4,$5,$6,$7,convertdate($8),convertdate($9)
     }' inputfile.csv

Faça disso um hábito e você perceberá como será mais fácil introduzir o tratamento de erros mais tarde.

    
por 01.03.2018 / 17:22
5

Se você tem o GNU awk, você pode converter o campo final em uma string dataspec separada por espaço em branco e então reformatá-lo como desejado usando strftime :

awk 'BEGIN{OFS=FS=","} {gsub(/[-:]/," ",$NF); $NF = strftime("%Y-%m-%d %H:%M:%S", mktime($NF))} 1' file
1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

Veja o Guia do Usuário do GNU awk: Funções de Tempo

    
por 01.03.2018 / 15:01
5

Solução simples do GNU awk :

awk 'BEGIN{ FS=OFS="," }{ gsub(/\<[0-9]\>/, "0&", $8); gsub(/\<[0-9]\>/, "0&", $9) }1' file
  • gsub(/\<[0-9]\>/, "0&", <field>) - substituir / complementar apenas dígitos únicos independentes dentro da string datetime :
    • \< e \> - são limites de palavras
    • & - representa a substring precisa que foi correspondida pelo padrão regexp

A saída:

1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
    
por 01.03.2018 / 15:15
1
sed -r 's/([-: ])([0-9]\b)//g' input.txt

Ele substitui todos os dígitos isolados, precedidos por [-: ] caracteres e seguidos por qualquer caractere não pertencente à palavra.

Esta solução é curta e simples, mas propensa a erros, porque não verifica o padrão de datas e apenas adiciona zero à digitação, o que está de acordo com o padrão [-: ][0-9]\b ( \b - corresponde a um limite de palavra) . Mas como variante.

Entrada

1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-1-5 1:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

Resultado

1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
    
por 03.03.2018 / 00:14
0

O pacote dateutils possui códigos para lidar com os detalhes de dados formatados por hora / data.

# Utility functions: print-as-echo, print-line-with-visual-space.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }

pl " Input data file $FILE:"
head $FILE

pl " Expected output:"
cat $E

pl " Results, to standard format:"
dateutils.dconv -S <$FILE

pl " Results, to standard format, omitting the \"T\":"
dateutils.dconv -S -f '%F %T' <$FILE

produzindo:

-----
 Input data file data1:
1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-1-5 1:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

-----
 Expected output:
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

-----
 Results, to standard format:
1111,2222,3333,4444,5555,6666,7777,2017-01-05T01:07:09,2017-01-05T01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25T19:57:17,2017-11-25T19:58:54

-----
 Results, to standard format, omitting the "T":
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

Em um sistema como:

OS, ker|rel, machine: Linux, 3.16.0-4-amd64, x86_64
Distribution        : Debian 8.9 (jessie) 
bash GNU bash 4.3.30
dateutils.dconv dconv 0.3.1

Alguns detalhes para o dconv:

dateutils.dconv Convert DATE/TIMEs between calendrical systems. (man)
Path    : /usr/bin/dateutils.dconv
Package : dateutils
Home    : http://www.fresse.org/dateutils
Version : 0.3.1
Type    : ELF 64-bit LSB shared object, x86-64, version 1 ( ...)
Help    : probably available with -h,--help
Home    : https://github.com/hroptatyr/dateutils (doc)

Felicidades ... felicidades, drl

    
por 03.03.2018 / 16:44