diff --git a/changelogs/fragments/filter-time.yml b/changelogs/fragments/filter-time.yml new file mode 100644 index 0000000000..45a46a8196 --- /dev/null +++ b/changelogs/fragments/filter-time.yml @@ -0,0 +1,2 @@ +minor_changes: +- A new filter ``to_time_unit`` with specializations ``to_milliseconds``, ``to_seconds``, ``to_minutes``, ``to_hours``, ``to_days``, ``to_weeks``, ``to_months`` and ``to_years`` has been added. For example ``'2d 4h' | community.general.to_hours`` evaluates to 52. diff --git a/plugins/filter/time.py b/plugins/filter/time.py index d1728fba27..18ae05260c 100644 --- a/plugins/filter/time.py +++ b/plugins/filter/time.py @@ -56,20 +56,23 @@ def multiply(factors): return result -def divide(divisors): - result = 1 - for divisor in divisors: - result = result / divisor - return result - - -def to_time_unit(human_time, unit='ms'): +def to_time_unit(human_time, unit='ms', **kwargs): ''' Return a time unit from a human readable string ''' unit = UNIT_TO_SHORT_FORM.get(unit, unit) if unit not in UNIT_FACTORS: available_units = sorted(list(UNIT_FACTORS.keys()) + list(UNIT_TO_SHORT_FORM.keys())) raise AnsibleFilterError("to_time_unit() can not convert to the following unit: %s. " "Available units: %s" % (unit, ', '.join(available_units))) + + unit_factors = UNIT_FACTORS + if 'year' in kwargs: + unit_factors['y'] = unit_factors['y'][:-1] + [kwargs.pop('year')] + if 'month' in kwargs: + unit_factors['mo'] = unit_factors['mo'][:-1] + [kwargs.pop('month')] + + if kwargs: + raise AnsibleFilterError('to_time_unit() got unknown keyword arguments: %s' % ', '.join(kwargs.keys())) + result = 0 for h_time_string in human_time.split(): res = re.match(r'(-?\d+)(\w+)', h_time_string) @@ -81,53 +84,53 @@ def to_time_unit(human_time, unit='ms'): h_time_unit = res.group(2) h_time_unit = UNIT_TO_SHORT_FORM.get(h_time_unit, h_time_unit) - if h_time_unit not in UNIT_FACTORS: + if h_time_unit not in unit_factors: raise AnsibleFilterError( "to_time_unit() can not interpret following string: %s" % human_time) - time_in_milliseconds = h_time_int * multiply(UNIT_FACTORS[h_time_unit]) + time_in_milliseconds = h_time_int * multiply(unit_factors[h_time_unit]) result += time_in_milliseconds - return round(result * divide(UNIT_FACTORS[unit]), 12) + return round(result / multiply(unit_factors[unit]), 12) -def to_milliseconds(human_time): +def to_milliseconds(human_time, **kwargs): ''' Return milli seconds from a human readable string ''' - return to_time_unit(human_time, 'ms') + return to_time_unit(human_time, 'ms', **kwargs) -def to_seconds(human_time): +def to_seconds(human_time, **kwargs): ''' Return seconds from a human readable string ''' - return to_time_unit(human_time, 's') + return to_time_unit(human_time, 's', **kwargs) -def to_minutes(human_time): +def to_minutes(human_time, **kwargs): ''' Return minutes from a human readable string ''' - return to_time_unit(human_time, 'm') + return to_time_unit(human_time, 'm', **kwargs) -def to_hours(human_time): +def to_hours(human_time, **kwargs): ''' Return hours from a human readable string ''' - return to_time_unit(human_time, 'h') + return to_time_unit(human_time, 'h', **kwargs) -def to_days(human_time): +def to_days(human_time, **kwargs): ''' Return days from a human readable string ''' - return to_time_unit(human_time, 'd') + return to_time_unit(human_time, 'd', **kwargs) -def to_weeks(human_time): +def to_weeks(human_time, **kwargs): ''' Return weeks from a human readable string ''' - return to_time_unit(human_time, 'w') + return to_time_unit(human_time, 'w', **kwargs) -def to_months(human_time): +def to_months(human_time, **kwargs): ''' Return months from a human readable string ''' - return to_time_unit(human_time, 'mo') + return to_time_unit(human_time, 'mo', **kwargs) -def to_years(human_time): +def to_years(human_time, **kwargs): ''' Return years from a human readable string ''' - return to_time_unit(human_time, 'y') + return to_time_unit(human_time, 'y', **kwargs) class FilterModule(object): diff --git a/tests/integration/targets/filter_to_time_unit/aliases b/tests/integration/targets/filter_time/aliases similarity index 100% rename from tests/integration/targets/filter_to_time_unit/aliases rename to tests/integration/targets/filter_time/aliases diff --git a/tests/integration/targets/filter_to_time_unit/tasks/main.yml b/tests/integration/targets/filter_time/tasks/main.yml similarity index 79% rename from tests/integration/targets/filter_to_time_unit/tasks/main.yml rename to tests/integration/targets/filter_time/tasks/main.yml index 355fc3b8e6..2efa8cc53f 100644 --- a/tests/integration/targets/filter_to_time_unit/tasks/main.yml +++ b/tests/integration/targets/filter_time/tasks/main.yml @@ -38,24 +38,29 @@ - "('1week' | community.general.to_days) == 7" - "('2weeks' | community.general.to_days) == 14" - "('1mo' | community.general.to_days) == 30" + - "('1mo' | community.general.to_days(month=28)) == 28" - name: test to_weeks filter assert: that: - "('1y' | community.general.to_weeks | int) == 52" - "('7d' | community.general.to_weeks) == 1" + - "('1mo' | community.general.to_weeks(month=28)) == 4" - name: test to_months filter assert: that: - "('30d' | community.general.to_months) == 1" - "('1year' | community.general.to_months | int) == 12" + - "('5years' | community.general.to_months(month=30, year=360)) == 60" + - "('1years' | community.general.to_months(month=2, year=34)) == 17" - name: test to_years filter assert: that: - "('365d' | community.general.to_years | int) == 1" - "('12mo' | community.general.to_years | round(0, 'ceil')) == 1" + - "('24mo' | community.general.to_years(month=30, year=360)) == 2" - name: test fail unknown unit debug: @@ -80,3 +85,15 @@ that: - res is failed - "'to_time_unit() can not interpret following string' in res.msg" + +- name: test fail unknown kwarg + debug: + msg: "{{ '1s' | community.general.to_time_unit('s', second=23) }}" + ignore_errors: yes + register: res + +- name: test fail unknown kwarg + assert: + that: + - res is failed + - "'to_time_unit() got unknown keyword arguments' in res.msg"