Comment parsingr les dates ISO8601 avec la command linux date

J'essaie d'utiliser la command de date pour générer un horodatage de file que la command de date elle-même peut interpréter. Cependant, la command de date ne semble pas aimer sa propre sortie, et je ne suis pas sûr de savoir comment contourner cela. Exemple concret:

sh-4.2$ date Fri Jan 3 14:22:19 PST 2014 sh-4.2$ date +%Y%m%dT%H%M 20140103T1422 sh-4.2$ date -d "20140103T1422" Thu Jan 2 23:22:00 PST 2014 

date semble interpréter la string avec un décalage de 15 heures. Y a-t-il des solutions de contournement connues pour cela?

Edit: ceci n'est pas un problème d'affichage:

 sh-4.2$ date +%s 1388791096 sh-4.2$ date +%Y%m%dT%H%M 20140103T1518 sh-4.2$ date -d 20140103T1518 +%s 1388737080 sh-4.2$ python Python 3.3.3 (default, Nov 26 2013, 13:33:18) [GCC 4.8.2] on linux Type "help", "copyright", "credits" or "license" for more information. >>> 1388737080 - 1388791096 -54016 >>> 54016/3600 15.004444444444445 >>> 

Il est toujours éteint de 15 heures lorsqu'il est affiché sous forme d'horodatage unix.

EDIT # 1

Peut-être que je devrais poser cette question un peu différemment. Disons que j'ai une list d'horodatages de base ISO8601 du formulaire:

  • AAAAMMJJThhmm
  • AAAAMMJJThhmms

Quel est le moyen le plus simple de les convertir en horodatages Unix correspondants?

Par exemple:

 - 20140103T1422 = 1388787720 - 20140103T142233 = 1388787753 

Vous requestz des "solutions de contournement connues". Voici un simple:

 $ date -d "$(echo 20140103T1422 | sed 's/T/ /')" Fri Jan 3 14:22:00 PST 2014 

Cela utilise sed pour replace "T" par un espace. Le résultat est un format que cette date comprend.

Si nous ajoutons des secondes à la date ISO8601, la date nécessite plus de modifications:

 $ date -d "$(echo 20140103T142211 | sed -r 's/(.*)T(..)(..)(..)/\1 \2:\3:\4/')" Fri Jan 3 14:22:11 PST 2014 

Dans ce qui précède, sed remplace le "T" par un espace et sépare également HHMMSS en HH: MM: SS.

Les documents d'information coreutils indiquent que le format étendu ISO 8601 est pris en charge.

Vous aurez besoin d'append des tirets, des points-virgules et un +%z pour le faire fonctionner.

 $ date +"%Y-%m-%dT%H:%M:%S%z" 2014-01-03T16:08:23-0800 $ date -d 2014-01-03T16:08:23-0800 Fri Jan 3 16:08:23 PST 2014 

Pour répondre à votre deuxième partie de la question …

Comme le format de la date ne contient que des numbers et des symboles, vous pouvez replace chaque symbole par une lettre unique, par exemple en utilisant tr

 $ ts="$(date +"%Y-%m-%dT%H:%M:%S%z" | tr -- '-:+' 'hcp')"; echo "$ts" 2014h01h03T16c18c04h0800 $ date -d "$(echo "$ts" | tr -- 'hcp' '-:+')" Fri Jan 3 16:18:04 PST 2014 

Ou vous pouvez l'parsingr en utilisant le T et le - ou + comme séparateurs, par exemple en utilisant les extensions ${var%word} et ${var#word}

 $ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts" 20140103T162228-0800 $ date=${ts%T*}; time=${ts#*T} etc. 

ou en utilisant une correspondance d'expression régulière bash

 $ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts" 20140103T165611-0800 $ [[ "$ts" =~ (.*)(..)(..)T(..)(..)(..)(.....) ]] $ match=("${BASH_REMATCH[@]}") $ Y=${match[1]}; m=${match[2]}; d=${match[3]}; H=${match[4]}; M=${match[5]}; S=${match[6]}; z=${match[7]} $ date -d "$Y-$m-$d"T"$H:$M:$S$z" Fri Jan 3 16:56:11 PST 2014 

ou Perl, Python, etc.

Les coreutils de GNU n'ont pris en charge que les dates ISO 8601 inputs depuis la version 8.13 (publiées le 2011-09-08). Vous devez utiliser une version plus ancienne.

Sous les anciennes versions, vous devez replace le T par un espace. Sinon, il est interprété comme un timezone militaire américain .

Même sous les versions récentes, seule la forme entièrement ponctuée est reconnue, pas le format de base avec seulement des numbers et un T au milieu.

 # Given a possibly abbreviated ISO date $iso_date... date_part=${iso_date%%T*} if [ "$date_part" != "$iso_date" ]; then time_part=${abbreviated_iso_date#*T} case ${iso_date#*T} in [!0-9]*) :;; [0-9]|[0-9][0-9]) time_part=${time_part}:00;; *) hour=${time_part%${time_part#??}} minute=${time_part%${time_part#????}}; minute=${minute#??} time_part=${hour}:${minute}:${time_part#????};; esac else time_part= fi date -d "$date_part $time_part" 

J'ai remarqué cette note dans la page de manuel pour la date .

 DATE STRING The --date=STRING is a mostly free format human readable date ssortingng such as "Sun, 29 Feb 2004 16:21:42 -0800" or "2004-02-29 16:21:42" or even "next Thursday". A date ssortingng may contain items indicating calendar date, time of day, time zone, day of week, relative time, relative date, and numbers. An empty ssortingng indicates the beginning of the day. The date ssortingng format is more complex than is easily documented here but is fully described in the info documentation. 

Ce n'est pas concluant, mais il ne montre pas explicitement une string de format d'heure qui inclut le T que vous essayez, pour [ISO 8601]. Comme l'a dit @Gilles , le support de l' ISO 8601 dans GNU CoreUtils est relativement nouveau.

Reformater la string

Vous pouvez utiliser Perl pour reformuler votre string.

Exemple:

 $ date -d "$(perl -pe 's/(.*)T(\d{2})(\d{2})(\d{2})/$1 $2:$3:$4/' \ <<<"20140103T142233")" Fri Jan 3 14:22:33 EST 2014 

Vous pouvez faire cela gérer les deux strings qui incluent les secondes et celles qui ne le font pas.

20140103T1422:

 $ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \ s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T1422")" Fri Jan 3 14:22:00 EST 2014 

20140103T142233:

 $ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \ s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T142233")" Fri Jan 3 14:22:33 EST 2014 

Selon la page man de la date, le format que vous produisez n'est pas le même que ce que la date attend comme input. Voici ce que dit la page man:

 date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] 

Donc vous pouvez le faire comme ceci:

 # date +%m%d%H%M%Y 010402052014 # date 010402052014 Sat Jan 4 02:05:00 EAT 2014 

Parce que dans les variables qui sont utilisées pour définir la string de sortie, +%m%d%H%M%Y serait égal à ce qu'il attend en input.