Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filter: add new time_delta filter #9831

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/BOTMETA.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ files:
maintainers: resmo
$filters/to_years.yml:
maintainers: resmo
$filters/time_delta.yml:
maintainers: Akasurde
$filters/unicode_normalize.py:
maintainers: Ajpantuso
$filters/version_sort.py:
Expand Down
32 changes: 31 additions & 1 deletion plugins/filter/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
__metaclass__ = type

import re

from datetime import timedelta, datetime

from ansible.errors import AnsibleFilterError


Expand Down Expand Up @@ -130,7 +133,33 @@ def to_years(human_time, **kwargs):
return to_time_unit(human_time, 'y', **kwargs)


class FilterModule(object):
def time_delta(date_time, **kwargs):
''' Return datetime after calculating time delta '''
if not isinstance(date_time, str):
raise AnsibleFilterError('time_delta accepts datetime in string format')
date_format = "%Y-%m-%d %H:%M:%S"
if 'date_format' in kwargs:
date_format = kwargs.get('date_format')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be validated to be a string.


delta = {
'days': kwargs.get('days', 0),
'microseconds': kwargs.get('microseconds', 0),
'milliseconds': kwargs.get('milliseconds', 0),
'minutes': kwargs.get('minutes', 0),
'hours': kwargs.get('hours', 0),
'weeks': kwargs.get('weeks', 0),
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to validate the above to be integers if supplied as options. Also you should check whether kwargs has more arguments than the ones we use (and fail if there are more).

try:
source_date = datetime.strptime(date_time, date_format)
except ValueError:
raise AnsibleFilterError(
f'Failed to parse provided string into datetime format "{date_format}" provided.'
)

return str(source_date + timedelta(**delta))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't date_format be used to format the timestamp?



class FilterModule:
''' Ansible time jinja2 filters '''

def filters(self):
Expand All @@ -144,6 +173,7 @@ def filters(self):
'to_weeks': to_weeks,
'to_months': to_months,
'to_years': to_years,
'time_delta': time_delta,
}

return filters
75 changes: 75 additions & 0 deletions plugins/filter/time_delta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

DOCUMENTATION:
name: time_delta
short_description: Calculate datetime based upon the user given timedelta
version_added: 10.6.0
description:
- Calculate a new date/time by applying a time delta to a given datetime string.
options:
_input:
description:
- The time string to calculate timedelta from.
- The format should match the O(date_format) unless specified otherwise.
type: string
required: true
date_format:
description:
- The format to parse the given input.
- Defaults to "%Y-%m-%d %H:%M:%S".
- You can specify your own format if the datetime string is in a different format.
- See Python 3 datetime format codes for more information.
type: string
days:
type: integer
description:
- The number of days to add or subtract.
- Default is 0.
microseconds:
type: integer
description:
- The number of microseconds to add or subtract.
- Default is 0.
milliseconds:
type: integer
description:
- The number of milliseconds to add or subtract.
- Default is 0.
minutes:
type: integer
description:
- The number of minutes to add or subtract.
- Default is 0.
hours:
type: integer
description:
- The number of hours to add or subtract.
- Default is 0.
weeks:
type: integer
description:
- The number of weeks to add or subtract.
- Default is 0.
author:
- Abhijeet Kasurde (@Akasurde)

EXAMPLES: |

tomorrow: "{{ '2025-03-12 18:00:00' | community.general.time_delta(days=1, date_format='%Y-%m-%d %H:%M:%S') }}"
# => "2025-03-13T18:00:00"

yesterday: "{{ '2025-03-12 18:00:00' | community.general.time_delta(days=-1) }}"
# => "2025-03-11T18:00:00"

a_month_ago: "{{ '2025/03/12' | community.general.time_delta(days=-30, date_format='%Y/%m/%d') }}"
# => "2025-02-10T00:00:00"

RETURN:
_value:
description:
- Date string after applying the delta in ISO 8601 format.
- Raises AnsibleFilterError on failing to parse the datetime string.
type: string
9 changes: 9 additions & 0 deletions tests/integration/targets/filter_time/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,12 @@
that:
- res is failed
- "'to_time_unit() got unknown keyword arguments' in res.msg"

- name: test time_delta filter
assert:
that:
- "('2025-03-12 18:00:00' | community.general.time_delta(days=-1)) == '2025-03-11 18:00:00'"
- "('2025-03-12 18:00:00' | community.general.time_delta(minutes=-60)) == '2025-03-12 17:00:00'"
- "('2025-03-12 18:00:00' | community.general.time_delta(hours=-1)) == '2025-03-12 17:00:00'"
- "('2025-03-12 18:00:00' | community.general.time_delta(weeks=-1)) == '2025-03-05 18:00:00'"
- "('2025/03/12' | community.general.time_delta(days=-30, date_format='%Y/%m/%d')) == '2025-02-10 00:00:00'"