如何使用 jq select 来自 JSON 字符串的日期范围?

How to select a date range from a JSON string by using jq?

我有一个像这样的 JSON 字符串 (MacOS):

[{
    "id": 3624,
    "created_at": "2016-10-21T20:51:16.000+08:00",
  },
  {
     "id": 3625,
    "created_at": "2016-10-22T08:09:16.000+08:00",
  },
 {
     "id": 3626,
    "created_at": "2016-10-23T09:19:55.000+08:00",
  }]

我想 select "created_at" 从“2016-10-21”到“2016-10-22”; 我想得到这样的结果:

[{
    "id": 3624,
    "created_at": "2016-10-21T20:51:16.000+08:00",
  },
  {
     "id": 3625,
    "created_at": "2016-10-22T08:09:16.000+08:00",
  }]

有人能给我指出正确的方向吗?

问题已解决 现在,我使用此代码 select 精确到分钟,我希望它对其他人有用:

jq --arg s '2016-10-26T18:16' --arg e '2016-10-27T20:24' '[($s, $e) | strptime("%Y-%m-%dT%H:%M") | mktime] as $r
  | map(select(
        (.updated_at[:19] | strptime("%Y-%m-%dT%H:%M:%S") | mktime) as $d
          | $d >= $r[0] and $d <= $r[1]))' <<< "$requestJson"

根据要求使用命令行 JSON 解析器 jq

注意: 演示了很多很棒的高级 jq 技术,但对于手头的具体问题,我相信 text 这个答案中基于方法的方法要简单得多,同时仍然足够灵活。

#!/usr/bin/env bash

# Create variable with sample input.
IFS= read -r -d '' json <<'EOF'
[
  {
    "id": 3624,
    "created_at": "2016-10-21T20:51:16.000+08:00"
  },
  {
     "id": 3625,
    "created_at": "2016-10-22T08:09:16.000+08:00"
  },
  {
     "id": 3626,
    "created_at": "2016-10-23T09:19:55.000+08:00"
  }
]
EOF

# Use `jq` to select the objects in the array whose .created_at
# property value falls between "2016-10-21:T20:51" and "2016-10-22T08:09"
# and return them as an array (effectively a sub-array of the input).
# (To solve the problem as originally stated, simply pass "2016-10-21" 
#  and "2016-10-22" instead.)
jq --arg s '2016-10-21T20:51' --arg e '2016-10-22T08:09' '
  map(select(.created_at | . >= $s and . <= $e + "z"))
' <<<"$json"
  • 参数--arg s '2016-10-21T20:51'--arg e '2016-10-22T08:09'定义变量$s(日期+时间范围的开始)和$e(日期+时间范围的结束) 分别在 jq 脚本中使用。

  • 函数 map() 将封闭的表达式应用于输入数组的所有元素,并将结果也作为数组输出。

  • 函数 select() 接受一个过滤表达式:每个输入对象都根据封闭的表达式求值,只有当表达式求值为 "truthy" 时才会传递输入对象值。

  • 表达式 .created_at | . >= $s and . <= $e + "z" 访问每个输入对象的 created_at 属性 并将其值发送到比较表达式,后者执行 词法 比较,由于日期+时间字符串的格式 - 相当于 时间顺序 比较。

    • 注意附加到范围端点的尾随 "z",以确保它与 JSON 字符串中的所有日期+时间字符串相匹配 prefix-匹配端点;例如,端点 2016-10-22T08:09 应匹配 2016-10-22T08:09:01 以及 2016-10-22T08:59.

    • 这种词法方法允许您根据需要从头开始指定尽可能多的组件,以缩小或扩大日期范围;例如--arg s '2016-10-01' --arg e '2016-10-31' 将匹配 2016 年 10 月整个月的所有条目。

对于更强大的解决方案,最好解析日期以获取其组件并比较这些组件。您可以获得的最接近的是使用 strptime/1 来解析 returns 其组件数组的日期。然后比较组件以检查它是否在范围内。

strptimereturns组成的数组:

year (%Y)
month (%m)
date (%d)
hours (%H)
minutes (%M)
seconds (%S)
day of week (%w)
day of year (%j)

由于您只比较日期,因此比较应该只看前 3 个组成部分。

$ jq --arg s '2016-10-21' --arg e '2016-10-22' '
[($s, $e) | strptime("%Y-%m-%d")[0:3]] as $r
  | map(select(
        (.created_at[:19] | strptime("%Y-%m-%dT%H:%M:%S")[0:3]) as $d
          | $d >= $r[0] and $d <= $r[1]
    ))
' input.json

由于您 运行 在 Mac 上,我希望这些方法可以在您的构建中使用。您可能需要调整日期格式才能使其按预期工作。正如您在评论中看到的那样,我们必须稍微修改一下才能让它发挥作用。