Я пытаюсь написать однострочник 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"

Либо используйте реализацию 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, поэтому я выбрал второй вариант. работал.
есть ли шанс узнать, что делает каждый из этих каналов во втором варианте jq?
@JuanD capture сопоставляет входные данные с заданным шаблоном регулярного выражения (здесь: 19 символов, затем знак + или -, за которым следуют две цифры, необязательное двоеточие и еще две цифры). Результатом является объект, некоторые части которого (знак и блоки из двух цифр) извлечены в виде строк в поля с использованием меток (из угловых скобок) в качестве ключевых имен. .d += "1" затем добавляет к знаку символ 1, так что теперь все три поля можно безопасно преобразовать в фактические числа с помощью tonumber (знак сам по себе не будет работать). Позже часовая и минутная части разбитого времени обновляются с использованием этих чисел.
хорошо. Я думаю, это имеет смысл. а как насчет последней трубы? now - mktime <= 300 я предполагал, что это 300 секунд (5 минут)? я играл с этим временем и не уверен, что это так?
@JuanD Да, select либо сохраняет, либо отбрасывает свой ввод (обработанный объект) в зависимости от его логического аргумента, в то время как now - mktime <= 300 оценивается как true или false в зависимости от того, составляет ли текущее время в секундах с момента эпохи, предоставленной now, не более 300 секунд. (или на 5 минут) выше, чем тот, который mktime производит исходя из ранее рассчитанного времени развала. Чтобы иметь динамические ограничения, используйте jq --argjson limit 300 '… now - mktime <= $limit …'
Большое спасибо за все время, потраченное на это. Я думаю, что меня смущает то, что я пробовал этот запрос и не уверен, работает ли он так, как задумано. В 22:36 по восточному времени я запустил запрос с ограничением 60, предполагая, что не появится ничего, превышающего 60 секунд. однако он вернул запись, созданная_at которой была: "created_at": "2024-05-13T22:18:16.031-04:00", Не знаете, почему было возвращено что-то более минуты? Дополнительная информация, если я повторю $TZ в системе, это: America/New_York
@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' (он должен содержать только служебные данные, т. е. быть меньше секунды).
я не знал о таком использовании debug. Спасибо. Во время дополнительного поиска в Google я наткнулся на это великолепное видео на YouTube , которое помогло продемонстрировать некоторые из этих фильтров даты и времени, а также имело хороший вставной контейнер для всего кода. Используя эту информацию, я попробовал 2 вещи: я изменил now на (now | todate | fromdate) в последней трубке. и теперь я использую updated_at в качестве поля, чтобы оглянуться на 5 минут назад (казалось, это имело больше смысла), пока все выглядит более точно
Re «Моя проблема заключается в том, что дата, возвращаемая для созданного_at, находится в EST», на самом деле EDT. EST составляет -5. ЭДТ равно -4.