Altere o formato de data de MM/DD/AAAA HH:MM:SS am/pm para AAAA-MM-DD HH:MM:SS em um arquivo CSV

Altere o formato de data de MM/DD/AAAA HH:MM:SS am/pm para AAAA-MM-DD HH:MM:SS em um arquivo CSV

Estou tentando converter o formato de data deste arquivo csv que recebi do fornecedor para poder fazer upload dos dados para meu Google Bigquery. Estou usando uma VM do Google Cloud Console.

Os dados são mais ou menos assim:

Name ,Phone ,SalesDate ,Venue ,NoOfUnits ,ModifiedDatae

Victor ,5555555 ,12/6/2013 10:26:32 AM , Colosseum ,1 ,12/8/2013 1:05:45 PM

Estou tentando fazer isso no formato de:

Name ,Phone ,SalesDate ,Venue ,NoOfUnits ,ModifiedDatae

Victor ,5555555 ,2013-12-6 10:26:32 ,Colosseum,1 ,2013-12-8 13:05:45

Eu sei que posso usar sed ou awk.

Responder1

Eu escrevi um script Python e um script Bash que devem fazer o que você quiser.

Solução Python

Aqui está um script Python que converte todos os campos de tempo de um formato para outro, conforme especificado na pergunta:

#!/usr/bin/env python3
# -*- coding: ascii -*-
"""reformat_time.py

Change date format from:

    MM/DD/YYYY HH:MM:SS am/pm

to:

    YYYY-MM-DD HH:MM:SS

in a CSV file
"""

import csv
from datetime import date
from datetime import datetime
import sys

# Open the file (taken as a command-line argument)
with open(sys.argv[1], 'r') as csvfile:

    # Parse the CSV data
    csvreader = csv.reader(csvfile, delimiter=',', quotechar='"')

    # Iterate over the rows
    for row in csvreader:

        # Iterate over the columns of each row
        for index, col in enumerate(row):

            # Try to parse and convert each column
            try:
                _datetime = datetime.strptime(col, "%m/%d/%Y %H:%M:%S %p")
                newcol = _datetime.strftime("%Y-%m-%d %H:%M:%S")

            # If parsing fails, leave the column unchanged
            except ValueError:
                newcol = col

            # Update the column value
            row[index] = newcol

        # Output the updated row
        print(','.join(row))

Suponha que seu arquivo CSV seja chamado data.csve contenha a seguinte linha (retirada de sua postagem):

Victor,5555555,12/6/2013 10:26:32 AM,Colosseum,1,12/8/2013 1:05:45 PM

Então você poderia executar o script assim:

python reformat_time.py data.csv

Isso produziria a seguinte saída:

Victor,5555555,2013-12-06 10:26:32,Colosseum,1,2013-12-08 01:05:45

Solução Bash

E aqui está um script Bash usando o dateutilitário GNU que tem (quase) o mesmo efeito:

#!/bin/bash
# reformat_time.sh

# Loop over the lines of the file
while read -r line; do

    # Extract the field values for each row
    Name="$(echo ${line} | cut -d, -f1)";
    Phone="$(echo ${line} | cut -d, -f2)";
    SalesDate="$(echo ${line} | cut -d, -f3)";
    Venue="$(echo ${line} | cut -d, -f4)";
    NoOfUnits="$(echo ${line} | cut -d, -f5)";
    ModifiedDate="$(echo ${line} | cut -d, -f6)";

    # Convert the time-fields from the old format to the new format
    NewSalesDate="$(date -d "${SalesDate}" "+%Y-%m-%d %H:%M:%S")";
    NewModifiedDate="$(date -d "${ModifiedDate}" "+%Y-%m-%d %H:%M:%S")";

    # Output the updated row
    echo "${Name},${Phone},${NewSalesDate},${Venue},${NoOfUnits},${NewModifiedDate}";

done < "$1"

Você poderia executá-lo assim:

bash reformat_time.sh data.csv

E produziria a seguinte saída:

Victor ,5555555 ,2013-12-06 10:26:32, Colosseum ,1 ,2013-12-08 13:05:45

Observe que o script Bash é muito mais frágil. Não trata erros e afeta apenas o 3º e 6º campos. Ele também preserva o espaço em branco ao redor do separador de campos, o que o script Python acima não faz.

Responder2

Sou novo no Linux e estou tentando ocultar o formato da data

Tente utilizar datecom o -dswitch:

       -d, --data=STRING
              tempo de exibição descrito por STRING, não 'agora'

E então formate a saída da maneira que desejar.

Exemplo:

date -d "12/6/2013 10:26:32 AM" "+%F %H:%M:%S"
2013-12-06 10:26:32

Para obter explicação sobre formatação, consulte man date(a FORMATseção).

Responder3

Você pode tentar com isso awk

awk -F, '
function cvtdate( dat,  array) {
    split(dat,array,"/| |:")
    array[4]=array[7]=="PM"?(array[4]+12):array[4]
    return array[3]"-"array[1]"-"array[2]" "array[4]":"array[5]":"array[6]
}
{
    $3=cvtdate($3)
    $6=cvtdate($6)
}1' OFS=',' infile

Responder4

Outro possível oneliner awk:

awk -F, '{ a[3];a[6] ; for (i in a) "date -d \""$i"\" \"+%Y-%m-%d %H:%M:%S\"" |& getline $i }1' OFS=, filename

informação relacionada