我有json格式的数据,该数据记录带有事件(输入/输出)的时间戳记(24小时格式的hh:mm)。我的目标是合计“入”事件和下一个“出”事件之间的所有时间差。
为简单起见,我假设没有不一致的地方(第一个元素始终是一个“ IN”,每个“ IN”之后都是一个“ OUT”)。例外:如果最后一个元素是“ IN”,则必须在当前时间和最后一个“ IN”事件的时间戳之间进行计算。
到目前为止,这是我的脚本,可以计算所有时间跨度,也可以计算OUT和IN事件之间的时间跨度。但是我只需要那些介于IN和OUT事件之间的对象。
欢迎任何提示,在这里可能更有用!
#!/bin/bash
JSON='{ "times": [ [ "7:43", "IN" ], [ "8:26", "OUT" ], [ "8:27", "IN" ], [ "9:12", "OUT" ], [ "9:14", "IN" ], [ "9:22", "OUT" ], [ "9:23", "IN " ], [ "12:12", "OUT" ], [ "13:12", "IN" ] ]}'
IN_TIMES=$(jq '.times | to_entries | .[] | select(.value[1]| tostring | contains("IN")) | .value[0]' <<< "$JSON")
OUT_TIMES=$(jq '.times | to_entries | .[] | select(.value[1]| tostring | contains("OUT")) | .value[0]' <<< "$JSON")
ALL_TIMES=$(jq -r '.times| to_entries | .[] | .value[0]' <<< "$JSON")
prevtime=0
count=0
for i in $(echo $ALL_TIMES | sed "s/ / /g")
do
if [[ "$count" -eq 0 ]]; then
(( count++ ))
prevtime=$i
continue
else
(( count++ ))
fi
time1=`date +%s -d ${prevtime}`
time2=`date +%s -d ${i}`
diffsec=`expr ${time2} - ${time1}`
echo From $prevtime to $i: `date +%H:%M -ud @${diffsec}`
prevtime=$i
done
答案 0 :(得分:2)
这是仅调用jq一次的only-jq解决方案。 但是请注意,它可能需要进行调整,以考虑时区因素,错误处理以及其他可能的复杂性:
def mins: split(":") | map(tonumber) | .[0] * 60 + .[1];
def diff: (.[1] - .[0]) | if . >= 0 then . else 24*60 + . end;
def now_mins: now | gmtime | .[3] * 60 + .[4];
def pairs:
range(0; length; 2) as $i | [.[$i], .[$i+1] ];
def sigma(s): reduce s as $s (0; . + $s);
.times
| map( .[0] |= mins )
| if .[-1][1] == "IN" then . + [ [now_mins, "OUT"] ] else . end
| sigma(pairs | map(.[0]) | diff)
答案 1 :(得分:1)
由于您可以测量分钟以内的时间,因此足以计算分钟而不会弄乱命令date
。我有一个awk
解决方案:
awk -F: -vIRS=" " -vfmt="From %5s to %5s: %4u minutes\n" \
'{this=$1*60+$2}a{printf(fmt,at,$0,this-a);a=0;next}{a=this;at=$0}\
END{if(a){$0=strftime("%H:%M");printf(fmt,at,$0,$1*60+$2-a)}}' <<<"$ALL_TIMES"
通过将冒号定义为字段分隔符并将空格定义为记录分隔符来工作。这样,我们每次都获得一个包含两个字段的单独记录。然后
{this=$1*60+$2}
:我们计算当前记录中有多少分钟,并将它们放入变量this
中。a{printf(fmt,at,$0,this-a);a=0;next}
:如果(最初为空)变量a
不为null也不为零,则我们正在读取OUT
条目,因此我们打印所需内容,设置{{1} }设为零,因为下一个字段将是a
条目,我们继续下一个记录。IN
:否则,我们正在读取一个{a=this;at=$0}
条目,并将IN
设置为其分钟,并将a
设置为其字符串表示(需要将其打印为之前的情况)。at
:最后,如果我们还有一些悬而未决的END{if(a){$0=strftime("%H:%M");printf(fmt,at,$0,$1*60+$2-a)}}
数据,则可以将IN
设置为正确的当前时间,并打印我们想要的内容。全部完成。
答案 2 :(得分:0)
有了Xidel和一点XQuery魔术,这很简单:
#!/bin/bash
JSON='{"times": [["7:43", "IN"], ["8:26", "OUT"], ["8:27", "IN"], ["9:12", "OUT"], ["9:14", "IN"], ["9:22", "OUT"], ["9:23", "IN "], ["12:12", "OUT"], ["13:12", "IN"]]}'
xidel -s - --xquery '
let $in:=$json/(times)()[contains(.,"IN")](1) ! time(
substring(
"00:00:00",
1,
8-string-length(.)
)||.
),
$out:=$json/(times)()[contains(.,"OUT")](1) ! time(
substring(
"00:00:00",
1,
8-string-length(.)
)||.
)
for $x at $i in $out return
concat(
"From ",
$in[$i],
" to ",
$x,
": ",
$x - $in[$i] + time("00:00:00")
)
' <<< "$JSON"
$in
:
00:07:43
00:08:27
00:09:14
00:09:23
00:13:12
$out
:
00:08:26
00:09:12
00:09:22
00:12:12
输出:
From 00:07:43 to 00:08:26: 00:00:43
From 00:08:27 to 00:09:12: 00:00:45
From 00:09:14 to 00:09:22: 00:00:08
From 00:09:23 to 00:12:12: 00:02:49