Como faço para analisar apenas a data de 2017-03-08T19: 41: 26Z?

5

Estou tentando analisar apenas a data de 2017-03-08T19:41:26Z .

A saída desejada é 2017-03-08.

    
por dhaval 08.03.2017 / 22:26

9 respostas

28

Para extrair a parte antes de T , com shells POSIX:

time=2017-03-08T19:41:26Z
utc_date=${time%T*} # as already said

Ou para ser compatível com Bourne ou para shells não POSIX:

expr "$time" : '\(.*\)T'

Agora, observe que 2017-03-08T19:41:26Z é o tempo zulu (outro nome para UTC), uma especificação inequívoca de um instante preciso no tempo.

Naquela época, a data era de 2017-03-08 em Londres, mas de 2017-03-09 (no início da manhã) em Bangkok.

Se você quisesse saber a data local (em oposição à data UTC) para essa especificação de horário, isto é, para um usuário de Bangkok obter 2017-03-09 e o usuário de Londres obter 2017-03-08, existem algumas opções.

Com o GNU date :

time=2017-03-08T19:41:26Z

date -d "$time" +%F

(fácil como data GNU reconhece esse formato zulu pronto)

Mesmo com ksh93 :

printf '%(%F)T\n' "$time"

com zsh internos:

zmodload zsh/datetime
TZ=UTC0 strftime -rs unix_time %Y-%m-%dT%TZ $time &&
strftime %Y-%m-%d $unix_time

(você pode substituir %Y-%m-%d por %F em sistemas como o GNU, em que strftime() / strptime() o suporta).

Semelhante a busybox date :

unix_time=$(date -u -D %Y-%m-%dT%TZ -d "$time" +%s)
date -d "@$unix_time" +%Y-%m-%d
    
por 08.03.2017 / 23:09
12

Usando cut :

cut - remove sections from each line of files

-d, --delimiter=DELIM use DELIM instead of TAB for field delimiter

-f, --fields=LIST select only these fields; also print any line that contains no delimiter character, unless the -s option is specified

echo "2017-03-08T19:41:26Z" | cut -d T -f 1
    
por 08.03.2017 / 22:33
10

No Bash, você pode usar várias operações na expansão de parâmetro de uma variável:

timestamp='2017-03-08T19:41:26Z'
date=${timestamp:0:10}          # pick 10 characters starting at position 0
date=${timestamp%T*}            # remove everything starting at the 'T'

( ${variable%pattern} é, na verdade, parte da linguagem de shell padrão e também é suportado por shells mais simples, como dash .)

Estas são, obviamente, apenas operações simples de substring. Se você quiser na verdade, analise a data, você terá que fazer outra coisa. A expansão da substring, é claro, se ajustará bem aqui, já que o formato é de largura fixa. Mas você pode querer verificar se os valores são válidos, etc.

    
por 08.03.2017 / 22:38
6

A substituição de variáveis do Bash pode cobrir isso.

OLD="2017-03-08T19:41:26Z"
NEW=${OLD%T*}
echo $NEW
2017-03-08

$ {string% substring} - Exclui a menor correspondência de $ substring da parte de trás de $ string. Mais detalhes em Manipulando Strings

    
por 08.03.2017 / 22:36
5

Então, basta encontrar todos os números-traço-números-traço-números? Isso funcionaria com strings / linhas mais longas, mesmo sem nenhum "T" imediatamente após a data.

grep -o "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"

Ou de forma equivalente, mas ligeiramente mais curta usando o texto "repetições / múltiplos"

grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}'

Ex:

$ echo 2017-03-08T19:41:26Z | grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}'
2017-03-08

Se não houver muitos outros traços na entrada, você poderá procurar por 4 caracteres, um traço, dois caracteres, um traço e mais dois caracteres:

$ echo 2017-03-08T19:41:26Z | grep -o '....-..-..'
2017-03-08
    
por 08.03.2017 / 22:36
4

data

Se você pudesse usar a data do GNU, isso faria o que você queria:

$ d='2017-03-08T19:41:26Z'
$ date +'%F' -ud "$d"
2017-03-08

Use a opção -u para evitar alguns problemas com o valor de TZ (ou localidade).

Se você precisar de um valor de data em algum outro local, o valor do TZ local funcionará com esta opção:

$ date +'%F' -d "$d"
2017-03-08               # May change in some locales.

Ou você pode optar por usar algum valor específico para TZ:

$ TZ=Asia/Kolkata date +'%F' -d "$d"
2017-03-09               # next day in India.

Note que Kolkata é o nome atual do antigo Calcuta.

shell

  1. poderia fazer isso apenas se o valor fosse um inteiro (em segundos):

    $ printf '%(%F)T\n' $(date +'%s' -d "$d")
    2017-03-08
    

    No entanto, o bash é afetado pelo valor de TZ (ou localidade):

    $ TZ=GGG+3 bash -c 'printf "%(%FT%T)T\n" $(date +"%s" -ud "$1")' sh "$d"
    2017-03-08T16:41:26Z
    

    Observe o T16: acima (não 19).

  2. pode fazer as duas conversões (para segundos e o formato):

    ksh$ printf '%(%F)T\n' "$d"
    2017-03-08
    

    Mas é igualmente afetado por TZ (ou localidade):

    $ TZ=GGG-7 ksh93 -c 'printf "%(%FT%T)T\n" "$1"' sh "$d"
    2017-03-09T02:41:26
    

    Observe o 09T02 (não 08T19 )

  3. só precisa de uma descrição do formato ( -D ) da entrada ( -d ).

    $ busybox date -u -D '%Y-%m-%dT%TZ' -d "$d" +'%F'
    2017-03-08
    

    O uso do -u evita qualquer efeito de TZ na saída. No entanto, a versão atual do busybox date ainda não implementou a análise de um valor de fuso horário ( -0400 ). Mas, no futuro, -z é uma proteção para o futuro.

string

Se o valor sempre tiver um T para indicar a hora e estiver sempre em Z (hora do zulu), essa operação de cadeia de caracteres será suficiente (para obter uma data baseada no zulu).

$ echo " ${d%%T*}"
2017-03-08
    
por 09.03.2017 / 04:45
2

Outra maneira de analisar a string com awk :

echo 2017-03-08T19:41:26Z | awk -F"T" '{print $1}'

Ou com sed :

echo "2017-03-08T19:41:26Z" | sed -e "s/T.*$//g"
    
por 09.03.2017 / 09:26
1

Você pode grep até o 'T'

echo 2017-03-08T19:41:26Z | grep -Eo "[^T]+" | head -1
    
por 08.03.2017 / 23:16
0

Eu usaria perl parse a string de data inteira e formate-a de acordo com o seu desejo:

#!/usr/#bin/env perl
use strict;
use warnings;

use Time::Piece;

while ( <DATA> ) { 
    chomp; 
    print Time::Piece -> strptime ( $_, "%Y-%m-%dT%H:%M:%SZ")->strftime("%Y-%m-%d");
}

__DATA__
2017-03-08T19:41:26Z

E como um forro:

perl -MTime::Piece -lne 'print Time::Piece->strptime($_,"%Y-%m-%dT%H:%M:%SZ")->strftime("%Y-%m-%d")'
    
por 10.03.2017 / 10:13