在 Bash 中解析日期

如何在 bash 中解析带有单独字段(年、月、天、小时、分钟、秒)的日期到不同的变量?

日期格式是: YYYY-MM-DD hh:mm:ss

115771 次浏览

它必须是 bash 吗? 您可以使用 GNU coreutils /bin/date二进制进行许多转换:

 $ 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

这将解析给定的日期并以选择的格式显示它。你可以根据自己的需要随意调整。

$ 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

你试过用削减吗? 像这样: 每周一天 = date|cut -d" " -f1

纯粹的狂欢:

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

又一次纯粹的狂欢

$ 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

Array 方法可能更好,但这正是您特别要求的:

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

这很简单,只需将破折号和冒号转换为空格(不需要更改 IFS) ,然后在一行中使用“ read”就可以了:

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

例如:

$ 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

不要使用 shell 脚本,只要您需要,可以在您的脚本中包含以下内容:

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

一年 B 就是几秒钟 C 将是小时,以此类推。

OP 问题的另一个解决方案:

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

使用 BSD date和 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

GNUdate甚至在非英语地区也能识别 WedMar,但是 BSDdate不能。

用 GNU 日期和 BSD 日期将从纪元开始的秒数转换为日期和时间:

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

使用 POSIX shell、 POSIX awk、 GNU date和 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

将秒转换为天、小时、分钟和秒:

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

我有一个不同的输入时间格式,所以这里有一个更灵活的解决方案。

在 BSD/macOS 中转换日期

date -jf in_format [+out_format] in_date

其中格式使用 strftime (参见 man strftime)。

对于给定的输入格式 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

为了把它们读成单独的变量,我采用了 NVRAM 的想法,但允许你使用任何 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

在脚本中,一直都是使用 read -r

在我的例子中,我想在时区之间进行转换(请参阅 /usr/share/zoneinfo目录中的区域名称) :

$ 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

在 GNU/Linux 中转换日期

在 Mac 上,您可以使用 brew install coreutils安装 GNU 版本的 date作为 gdate

date [+out_format] -d in_date

其中 out _ format 使用 strftime (参见 man strftime)。

在 GNU coreutils 的 date命令中,没有显式设置输入格式的方法,因为它试图自己计算输入格式,而且这种方法通常都能正常工作。(详情请参阅 Coreutils: 日期输入格式的使用手册。)

例如:

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

把它们分解成不同的变量:

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

要在时区之间进行转换(有关区域名称,请参见 /usr/share/zoneinfo目录) ,可以在输入字符串中指定 TZ="America/Los_Angeles"。注意区域名称周围的字面 "字符,以及 in _ date 之前的空格字符:

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

例如:

$ 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 date 还能理解时区的小时偏移量:

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