Datum ontleden in bash

Hoe zou je een datum in bash, met afzonderlijke velden (jaren, maanden, dagen, uren, minuten, seconden) in verschillende variabelen ontleden?

Het datumformaat is: YYYY-MM-DD hh:mm:ss


Antwoord 1, autoriteit 100%

Moet het bash zijn? U kunt het binaire bestand GNU coreutils /bin/dategebruiken voor veel transformaties:

$ 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

Hiermee wordt de opgegeven datum geparseerd en weergegeven in het gekozen formaat. U kunt dat naar believen aanpassen aan uw behoeften.


Antwoord 2, autoriteit 39%

Dit is eenvoudig, converteer gewoon uw streepjes en dubbele punten naar een spatie (u hoeft IFS niet te wijzigen) en gebruik ‘lees’ alles op één regel:

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

Bijvoorbeeld:

$ 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

Antwoord 3, autoriteit 32%

Ik had een ander invoertijdformaat, dus hier is een flexibelere oplossing.

Datums converteren in BSD/macOS

date -jf in_format [+out_format] in_date

waar de indelingen strftime gebruiken (zie man strftime).

Voor het opgegeven invoerformaat 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

Om ze in afzonderlijke variabelen te lezen, neem ik het idee van NVRAM over, maar laat je elk strftime-formaat gebruiken:

$ 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

In scripts altijdgebruik je read -r.

In mijn geval wilde ik converteren tussen tijdzones (zie uw /usr/share/zoneinfodirectory voor zonenamen):

$ 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

Datums converteren in GNU/Linux

Op een Mac kun je de GNU-versie van dateinstalleren als gdatemet brew install coreutils.

date [+out_format] -d in_date

waar het out_format strftime gebruikt (zie man strftime).

In het date-commando van GNU coreutils is er geen manier om expliciet een invoerformaat in te stellen, aangezien het het invoerformaat zelf probeert te achterhalen, en dingen werken meestal gewoon. (Voor details kunt u de handleiding lezen op coreutils: Invoerformaten voor datum.)

Bijvoorbeeld:

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

Om ze in afzonderlijke variabelen te lezen:

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

Om tussen tijdzones te converteren (zie uw /usr/share/zoneinfodirectory voor zonenamen), kunt u TZ="America/Los_Angeles"direct in uw invoer specificeren snaar. Let op de letterlijke tekens "rond de zonenaam en het spatieteken vóór in_date:

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

Bijvoorbeeld:

$ 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

GNU-datum begrijpt ook uurverschuivingen voor de tijdzone:

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

Antwoord 4, autoriteit 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

Antwoord 5, autoriteit 7%

De array-methode is misschien beter, maar dit is waar je specifiek om vroeg:

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

Antwoord 6, autoriteit 3%

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

Antwoord 7, autoriteit 2%

in plaats van de shell-scripting te gebruiken, neem je in je scripting zelf op zoals hieronder wat je maar wilt:

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

een jaar wordt
b zal seconden zijn
c zal uren zijn. enzovoort.


Antwoord 8, autoriteit 2%

Een andere oplossing voor het probleem van de OP:

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

Een datum converteren naar een ander formaat met BSD dateen 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 dateherkent Weden Marzelfs in niet-Engelse talen, maar BSD dateniet.

Seconden sinds epoche converteren naar een datum en tijd met GNU-datum en BSD-datum:

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

Seconden omrekenen naar uren, minuten en seconden met een POSIX-shell, POSIX awk, GNU dateen 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

Seconden omzetten in dagen, uren, minuten en seconden:

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

Antwoord 9

nog een 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

Antwoord 10

Heb je al geprobeerd om knippen te gebruiken?
iets zoals dit:
dayofweek=date|cut -d" " -f1

Other episodes