Add datetimeparse Jinja2 template helper filter function (#4312)
# What this PR does Jinja2 filter to parse strings into datetime objects. Previously, only a limited set of strings could be parsed into datetime objects ([datetime_re](https://docs.djangoproject.com/en/2.2/_modules/django/utils/dateparse/)). The addition of this filter allows for strings of any format to be converted into datetime. ## Which issue(s) this PR closes <!-- *Note*: if you have more than one GitHub issue that this PR closes, be sure to preface each issue link with a [closing keyword](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue). This ensures that the issue(s) are auto-closed once the PR has been merged. --> ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] Added the relevant release notes label (see labels prefixed w/ `release:`). These labels dictate how your PR will show up in the autogenerated release notes. Co-authored-by: Joey Orlando <joey.orlando@grafana.com>
This commit is contained in:
parent
bd8c078347
commit
dba6748efd
5 changed files with 56 additions and 2 deletions
|
|
@ -219,9 +219,10 @@ Built-in functions:
|
|||
- `tojson` - dumps a structure to JSON
|
||||
- `tojson_pretty` - same as tojson, but prettified
|
||||
- `iso8601_to_time` - converts time from iso8601 (`2015-02-17T18:30:20.000Z`) to datetime
|
||||
- `datetimeformat` - converts time from datetime to the given format (`%H:%M / %d-%m-%Y` by default)
|
||||
- `datetimeformat` - converts datetime to string according to strftime format codes (`%H:%M / %d-%m-%Y` by default)
|
||||
- `datetimeformat_as_timezone` - same as `datetimeformat`, with the inclusion of timezone conversion (`UTC` by default)
|
||||
- Usage example: `{{ payload.alerts.startsAt | iso8601_to_time | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', 'America/Chicago') }}`
|
||||
- `datetimeparse` - converts string to datetime according to strftime format codes (`%H:%M / %d-%m-%Y` by default)
|
||||
- `regex_replace` - performs a regex find and replace
|
||||
- `regex_match` - performs a regex match, returns `True` or `False`
|
||||
- Usage example: `{{ payload.ruleName | regex_match(".*") }}`
|
||||
|
|
|
|||
|
|
@ -1,11 +1,19 @@
|
|||
import base64
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
from django.utils.dateparse import parse_datetime
|
||||
from pytz import timezone
|
||||
|
||||
|
||||
def datetimeparse(value, format="%H:%M / %d-%m-%Y"):
|
||||
try:
|
||||
return datetime.strptime(value, format)
|
||||
except (ValueError, AttributeError, TypeError):
|
||||
return None
|
||||
|
||||
|
||||
def datetimeformat(value, format="%H:%M / %d-%m-%Y"):
|
||||
try:
|
||||
return value.strftime(format)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from .filters import (
|
|||
b64decode,
|
||||
datetimeformat,
|
||||
datetimeformat_as_timezone,
|
||||
datetimeparse,
|
||||
iso8601_to_time,
|
||||
json_dumps,
|
||||
parse_json,
|
||||
|
|
@ -25,6 +26,7 @@ jinja_template_env = SandboxedEnvironment(loader=BaseLoader())
|
|||
|
||||
jinja_template_env.filters["datetimeformat"] = datetimeformat
|
||||
jinja_template_env.filters["datetimeformat_as_timezone"] = datetimeformat_as_timezone
|
||||
jinja_template_env.filters["datetimeparse"] = datetimeparse
|
||||
jinja_template_env.filters["iso8601_to_time"] = iso8601_to_time
|
||||
jinja_template_env.filters["tojson_pretty"] = to_pretty_json
|
||||
jinja_template_env.globals["time"] = timezone.now
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import base64
|
||||
import json
|
||||
from datetime import datetime
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
|
@ -44,6 +45,14 @@ def test_apply_jinja_template_datetimeformat():
|
|||
"{{ payload.naive | iso8601_to_time | datetimeformat('%Y-%m-%dT%H:%M:%S%z') }}",
|
||||
payload,
|
||||
) == parse_datetime(payload["naive"]).strftime("%Y-%m-%dT%H:%M:%S%z")
|
||||
assert apply_jinja_template(
|
||||
"{{ payload.aware | datetimeparse('%Y-%m-%d %H:%M:%S%z') | datetimeformat('%Y-%m-%dT%H:%M:%S%z') }}",
|
||||
payload,
|
||||
) == datetime.strptime(payload["aware"], "%Y-%m-%d %H:%M:%S%z").strftime("%Y-%m-%dT%H:%M:%S%z")
|
||||
assert apply_jinja_template(
|
||||
"{{ payload.naive | datetimeparse('%Y-%m-%d %H:%M:%S') | datetimeformat('%Y-%m-%dT%H:%M:%S%z') }}",
|
||||
payload,
|
||||
) == datetime.strptime(payload["naive"], "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%dT%H:%M:%S%z")
|
||||
|
||||
|
||||
def test_apply_jinja_template_datetimeformat_as_timezone():
|
||||
|
|
@ -57,12 +66,46 @@ def test_apply_jinja_template_datetimeformat_as_timezone():
|
|||
"{{ payload.naive | iso8601_to_time | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', 'America/Chicago') }}",
|
||||
payload,
|
||||
) == parse_datetime(payload["naive"]).astimezone(timezone("America/Chicago")).strftime("%Y-%m-%dT%H:%M:%S%z")
|
||||
assert (
|
||||
apply_jinja_template(
|
||||
"""{{ payload.aware | datetimeparse('%Y-%m-%d %H:%M:%S%z') | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z',
|
||||
'America/Chicago') }}""",
|
||||
payload,
|
||||
)
|
||||
== parse_datetime(payload["aware"]).astimezone(timezone("America/Chicago")).strftime("%Y-%m-%dT%H:%M:%S%z")
|
||||
)
|
||||
assert (
|
||||
apply_jinja_template(
|
||||
"""{{ payload.naive | datetimeparse('%Y-%m-%d %H:%M:%S') | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z',
|
||||
'America/Chicago') }}""",
|
||||
payload,
|
||||
)
|
||||
== parse_datetime(payload["naive"]).astimezone(timezone("America/Chicago")).strftime("%Y-%m-%dT%H:%M:%S%z")
|
||||
)
|
||||
|
||||
with pytest.raises(JinjaTemplateWarning):
|
||||
apply_jinja_template(
|
||||
"{{ payload.aware | iso8601_to_time | datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', 'potato') }}",
|
||||
payload,
|
||||
)
|
||||
apply_jinja_template(
|
||||
"""{{ payload.aware | datetimeparse('%Y-%m-%d %H:%M:%S%z') |
|
||||
datetimeformat_as_timezone('%Y-%m-%dT%H:%M:%S%z', 'potato') }}""",
|
||||
payload,
|
||||
)
|
||||
|
||||
|
||||
def test_apply_jinja_template_datetimeparse():
|
||||
payload = {"aware": "15 05 2024 07:52:11 -0600", "naive": "2024-05-15T07:52:11"}
|
||||
|
||||
assert apply_jinja_template(
|
||||
"{{ payload.aware | datetimeparse('%d %m %Y %H:%M:%S %z') }}",
|
||||
payload,
|
||||
) == str(datetime.strptime(payload["aware"], "%d %m %Y %H:%M:%S %z"))
|
||||
assert apply_jinja_template(
|
||||
"{{ payload.naive | datetimeparse('%Y-%m-%dT%H:%M:%S') }}",
|
||||
payload,
|
||||
) == str(datetime.strptime(payload["naive"], "%Y-%m-%dT%H:%M:%S"))
|
||||
|
||||
|
||||
def test_apply_jinja_template_b64decode():
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ export const genericTemplateCheatSheet: CheatSheetInterface = {
|
|||
{ listItemName: 'labels - labels assigned to the last alert in the group' },
|
||||
{ listItemName: 'web_title, web_mesage, web_image_url - templates from Web' },
|
||||
{ listItemName: 'payload, grafana_oncall_link, grafana_oncall_incident_id, integration_name, source_link' },
|
||||
{ listItemName: 'time(), datetimeformat, datetimeformat_as_timezone, iso8601_to_time' },
|
||||
{ listItemName: 'time(), datetimeformat, datetimeformat_as_timezone, datetimeparse, iso8601_to_time' },
|
||||
{ listItemName: 'to_pretty_json' },
|
||||
{ listItemName: 'regex_replace, regex_match' },
|
||||
{ listItemName: 'b64decode' },
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue