JQ – Использование поля даты, отличного от UTC, и просмотр определенного времени назад

Я пытаюсь написать однострочник BASH+jq, чтобы возвращать только записи возрастом менее 5 минут, поскольку я пишу автоматизацию, чтобы оглядываться назад только на 5 минут (BASH). Используя следующий JSON:

[
  {
    "id": 621024,
    "iid": 99999,
    "project_id": 999,
    "sha": "faf897sd98fa987afsd98f7",
    "ref": "master",
    "status": "running",
    "source": "push",
    "created_at": "2024-05-10T16:32:01.072-04:00",
    "updated_at": "2024-05-10T16:32:03.565-04:00",
    "web_url": "https://gitlab/pipelines/9999",
    "name": null
  },
  {
    "id": 621023,
    "iid": 99999,
    "project_id": 999,
    "sha": "faf897sd98fa987afsd98f7",
    "ref": "master",
    "status": "success",
    "source": "push",
    "created_at": "2024-05-10T16:31:47.951-04:00",
    "updated_at": "2024-05-10T16:35:30.362-04:00",
    "web_url": "https://gitlab/pipelines/9999",
    "name": null
  },
  {
    "id": 621020,
    "iid": 99999,
    "project_id": 999,
    "sha": "faf897sd98fa987afsd98f7",
    "ref": "master",
    "status": "waiting_for_resource",
    "source": "push",
    "created_at": "2024-05-10T15:27:00.248-04:00",
    "updated_at": "2024-05-10T15:30:14.172-04:00",
    "web_url": "https://gitlab/pipelines/9999",
    "name": null
  },
  {
    "id": 621019,
    "iid": 99999,
    "project_id": 999,
    "sha": "faf897sd98fa987afsd98f7",
    "ref": "master",
    "status": "success",
    "source": "push",
    "created_at": "2024-05-10T14:26:02.235-04:00",
    "updated_at": "2024-05-10T14:29:45.406-04:00",
    "web_url": "https://gitlab/pipelines/9999",
    "name": null
  }
]

Моя проблема заключается в том, что возвращаемая дата для created_at находится в EST.

Я пытался использовать некоторые традиционные функции/инструменты времени с jq, но не думаю, что это работает, потому что они ожидают, что дата для проверки будет в формате UTC.

Я знаю, что могу сократить миллисекунды, используя что-то вроде

jq '.[] | .created_at |= .[0:19]'

Но у меня все равно остается отметка времени в формате EST.

"created_at": "2024-05-10T15:27:00"

Во всей документации, которую я читал, говорится о том, что дата должна быть в формате ISO 8601, чтобы ее можно было анализировать с помощью некоторых функций даты и времени. Я не знаю, что добавить в свой jq, чтобы вычесть только те записи, которые старше 5 минут.

Этот запрос не работает:

jq '.[] | .created_at |= .[0:19] | select(.created_at | fromdate - 300)'

с ошибкой

jq: error (at <stdin>:55): date "2024-05-10T16:32:01" does not match format "%Y-%m-%dT%H:%M:%SZ"

Re «Моя проблема заключается в том, что дата, возвращаемая для созданного_at, находится в EST», на самом деле EDT. EST составляет -5. ЭДТ равно -4.

ikegami 13.05.2024 19:59
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
0
1
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Либо используйте реализацию jq Go, которая может правильно анализировать %z:

gojq '
  map(select(
    .created_at | sub("\\.[0-9]+"; "")
    | strptime("%FT%T%z") | now - mktime <= 300
  ))
'

Или вручную интерпретируйте (числовой) часовой пояс (как (+|-)HH[:]MM) и выполните математические вычисления:

map(select(
  .created_at | sub("\\.[0-9]+"; "")
  | ( capture(".{19}(?<d>[+-])(?<h>[0-9]{2}):?(?<m>[0-9]{2})")
      | .d += "1" | .[] |= tonumber
    ) as $tz
  | strptime("%FT%T%z") | .[3] -= $tz.d * $tz.h | .[4] -= $tz.d * $tz.m
  | now - mktime <= 300
))

УХ ТЫ! спасибо за быстрый и подробный ответ. Я не могу контролировать используемую версию jq, поэтому я выбрал второй вариант. работал.

JuanD 11.05.2024 01:33

есть ли шанс узнать, что делает каждый из этих каналов во втором варианте jq?

JuanD 13.05.2024 20:58

@JuanD capture сопоставляет входные данные с заданным шаблоном регулярного выражения (здесь: 19 символов, затем знак + или -, за которым следуют две цифры, необязательное двоеточие и еще две цифры). Результатом является объект, некоторые части которого (знак и блоки из двух цифр) извлечены в виде строк в поля с использованием меток (из угловых скобок) в качестве ключевых имен. .d += "1" затем добавляет к знаку символ 1, так что теперь все три поля можно безопасно преобразовать в фактические числа с помощью tonumber (знак сам по себе не будет работать). Позже часовая и минутная части разбитого времени обновляются с использованием этих чисел.

pmf 13.05.2024 22:07

хорошо. Я думаю, это имеет смысл. а как насчет последней трубы? now - mktime <= 300 я предполагал, что это 300 секунд (5 минут)? я играл с этим временем и не уверен, что это так?

JuanD 13.05.2024 23:12

@JuanD Да, select либо сохраняет, либо отбрасывает свой ввод (обработанный объект) в зависимости от его логического аргумента, в то время как now - mktime <= 300 оценивается как true или false в зависимости от того, составляет ли текущее время в секундах с момента эпохи, предоставленной now, не более 300 секунд. (или на 5 минут) выше, чем тот, который mktime производит исходя из ранее рассчитанного времени развала. Чтобы иметь динамические ограничения, используйте jq --argjson limit 300 '… now - mktime <= $limit …'

pmf 14.05.2024 03:06

Большое спасибо за все время, потраченное на это. Я думаю, что меня смущает то, что я пробовал этот запрос и не уверен, работает ли он так, как задумано. В 22:36 по восточному времени я запустил запрос с ограничением 60, предполагая, что не появится ничего, превышающего 60 секунд. однако он вернул запись, созданная_at которой была: "created_at": "2024-05-13T22:18:16.031-04:00", Не знаете, почему было возвращено что-то более минуты? Дополнительная информация, если я повторю $TZ в системе, это: America/New_York

JuanD 14.05.2024 04:36

@JuanD Чтобы отладить фактически обработанные временные метки, попробуйте изменить mktime на (mktime|debug), затем сравните их с текущей временной меткой (чтобы напечатать ее, снова используйте now, например map(…), now). Поскольку на данный момент мы имеем дело только с временными метками, фактическое значение переменной среды TZ не имеет значения (это будет иметь значение только в том случае, если вы все равно используете один из фильтров *local* jq). -- Чтобы проверить декодирование, вы можете просто проверить, достаточно ли мал date +%FT%T%:z | jq -R '(capture(…) | …) as $tz | strptime("%FT%T%z") | … | now - mktime' (он должен содержать только служебные данные, т. е. быть меньше секунды).

pmf 14.05.2024 10:09

я не знал о таком использовании debug. Спасибо. Во время дополнительного поиска в Google я наткнулся на это великолепное видео на YouTube , которое помогло продемонстрировать некоторые из этих фильтров даты и времени, а также имело хороший вставной контейнер для всего кода. Используя эту информацию, я попробовал 2 вещи: я изменил now на (now | todate | fromdate) в последней трубке. и теперь я использую updated_at в качестве поля, чтобы оглянуться на 5 минут назад (казалось, это имело больше смысла), пока все выглядит более точно

JuanD 14.05.2024 15:47

Другие вопросы по теме