web-dev-qa-db-fra.com

Date d'analyse dans Bash

Comment analyseriez-vous une date dans bash, avec des champs séparés (années, mois, jours, heures, minutes, secondes) dans différentes variables?

Le format de date est: YYYY-MM-DD hh:mm:ss

48
Steve

Est-ce que ça doit être bash? Vous pouvez utiliser le binaire GNU coreutils /bin/date pour de nombreuses transformations:

 $ date --date="2009-01-02 03:04:05" "+%d %B of %Y at %H:%M and %S seconds"
 02 January of 2009 at 03:04 and 05 seconds

Ceci analyse la date donnée et l'affiche dans le format choisi. Vous pouvez adapter cela à votre guise.

60
Dirk Eddelbuettel

C’est simple: convertissez simplement vos tirets et vos deux points en un espace (inutile de changer d’IFS) et utilisez le mot 'read' sur une seule ligne:

read Y M D h m s <<< ${date//[-:]/ }

Par exemple:

$ date=$(date +'%Y-%m-%d %H:%M:%S')
$ read Y M D h m s <<< ${date//[-: ]/ }
$ echo "Y=$Y, m=$m"
Y=2009, m=57
26
NVRAM

J'avais un format d'heure d'entrée différent, alors voici une solution plus flexible. 

Convertir les dates en BSD/macOS

date -jf in_format [+out_format] in_date

où les formats utilisent strftime (voir man strftime ).

Pour le format d'entrée donné YYYY-MM-DD hh:mm:ss:

$ date -jf '%Y-%m-%d %H:%M:%S' '2017-05-10 13:40:01'
Wed May 10 13:40:01 PDT 2017

Pour les lire dans des variables séparées, je reprends l'idée de NVRAM, mais vous permet d'utiliser n'importe quel format strftime:

$ date_in='2017-05-10 13:40:01'

$ format='%Y-%m-%d %H:%M:%S'

$ read -r y m d H M S <<< "$(date -jf "$format" '+%Y %m %d %H %M %S' "$date_in")"

$ for var in y m d H M S; do echo "$var=${!var}"; done
y=2017
m=05
d=10
H=13
M=40
S=01

(Dans les scripts, toujours utilisez read -r .)

Dans mon cas, je voulais convertir entre les fuseaux horaires (voir votre répertoire /usr/share/zoneinfo pour les noms de zone):

$ format=%Y-%m-%dT%H:%M:%S%z

$ TZ=UTC date -jf $format +$format 2017-05-10T02:40:01+0200
2017-05-10T00:40:01+0000

$ TZ=America/Los_Angeles date -jf $format +$format 2017-05-10T02:40:01+0200
2017-05-09T17:40:01-0700

Convertir les dates sous GNU/Linux

Sur un Mac, vous pouvez installer la version GNU de date en tant que gdate avec brew install coreutils.

date [+out_format] -d in_date

où out_format utilise strftime (voir man strftime ). 

Dans la commande date de GNU de coreutils, il n’existe aucun moyen de définir explicitement un format d’entrée, car il essaie de déterminer le format d’entrée lui-même, et tout fonctionne normalement. (Pour plus de détails, vous pouvez lire le manuel sur coreutils: formats de saisie de date .)

Par exemple:

$ date '+%Y %m %d %H %M %S' -d '2017-05-10 13:40:01'
2017 05 10 13 40 01

Pour les lire dans des variables distinctes, modifiez la commande dans la section Mac en remplaçant la commande dans la parenthèse par la version GNU.

Pour convertir des fuseaux horaires (voir votre répertoire /usr/share/zoneinfo pour les noms de zone), vous pouvez spécifier TZ="America/Los_Angeles" dans votre chaîne de saisie. Notez les caractères " littéraux autour du nom de la zone et le caractère espace avant in_date:

TZ=out_tz date [+out_format] 'TZ="in_tz" 'in_date

Par exemple:

$ format='%Y-%m-%d %H:%M:%S%z'

$ TZ=America/Los_Angeles date +"$format" -d 'TZ="UTC" 2017-05-10 02:40:01'
2017-05-09 19:40:01-0700

$ TZ=UTC date +"$format" -d 'TZ="America/Los_Angeles" 2017-05-09 19:40:01'
2017-05-10 02:40:01+0000

La date GNU comprend également les décalages horaires pour le fuseau horaire:

$ TZ=UTC date +"$format" -d '2017-05-09 19:40:01-0700'
2017-05-10 02:40:01+0000
8
$ t='2009-12-03 12:38:15'
$ a=(`echo $t | sed -e 's/[:-]/ /g'`)
$ echo ${a[*]}
2009 12 03 12 38 15
$ echo ${a[3]}
12
7
DigitalRoss

La méthode array est peut-être mieux, mais voici ce que vous demandiez spécifiquement:

IFS=" :-"
read year month day hour minute second < <(echo "YYYY-MM-DD hh:mm:ss")
4
Steve Baker

au lieu d'utiliser les scripts Shell, incorporez-les comme vous le souhaitez, comme ci-dessous, lorsque vous avez besoin

a=date +%Y 
b=date +%S
c=date +%H

a sera l'année b sera la seconde c sera l'heure. etc.

3
Vijay

Pure Bash:

date="2009-12-03 15:35:11"
saveIFS="$IFS"
IFS="- :"
date=($date)
IFS="$saveIFS"
for field in "${date[@]}"
do
    echo $field
done

2009
12
03
15
35
11
3
Dennis Williamson

Une autre solution au problème du PO:

IFS=' -:' read y m d h m s<<<'2014-03-26 16:36:41'

Conversion d'une date dans un autre format avec BSD date et GNU date:

$ LC_ALL=C date -jf '%a %b %e %H:%M:%S %Z %Y' 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T
2014-03-26 16:36:41
$ gdate -d 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T
2014-03-26 16:36:41

GNU date reconnaît Wed et Mar même dans des paramètres régionaux autres que l'anglais, mais BSD date ne le reconnaît pas.

Conversion de secondes depuis Epoch en date et heure avec la date GNU et la date BSD:

$ gdate -d @1234567890 '+%F %T'
2009-02-14 01:31:30
$ date -r 1234567890 '+%F %T'
2009-02-14 01:31:30

Conversion de secondes en heures, minutes et secondes avec un shell POSIX, POSIX awk, GNU date et BSD date:

$ s=12345;printf '%02d:%02d:%02d\n' $((s/3600)) $((s%3600/60)) $((s%60))
05:25:45
$ echo 12345|awk '{printf "%02d:%02d:%02d\n",$0/3600,$0%3600/60,$0%60}'
05:25:45
$ gdate -d @12345 +%T
05:25:45
$ date -r 12345 +%T
05:25:45

Conversion de secondes en jours, heures, minutes et secondes:

$ t=12345678
$ printf '%d:%02d:%02d:%02d\n' $((t/86400)) $((t/3600%24)) $((t/60%60)) $((t%60))
142:21:21:18
2
Lri

une autre pure bash

$ d="2009-12-03 15:35:11"
$ d=${d//[- :]/|}
$ IFS="|"
$ set -- $d
$ echo $1
2009
$ echo $2
12
$ echo $@
2009 12 03 15 35 11
1
ghostdog74

avez-vous essayé d'utiliser cut? quelque chose comme ceci: dayofweek = date|cut -d" " -f1

0
Jay