# -*- coding: utf-8 -*- # Copyright (c) 2020, René Moser # 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 from __future__ import (absolute_import, division, print_function) __metaclass__ = type import re from ansible.errors import AnsibleFilterError UNIT_FACTORS = { 'ms': [], 's': [1000], 'm': [1000, 60], 'h': [1000, 60, 60], 'd': [1000, 60, 60, 24], 'w': [1000, 60, 60, 24, 7], 'mo': [1000, 60, 60, 24, 30], 'y': [1000, 60, 60, 24, 365], } UNIT_TO_SHORT_FORM = { 'millisecond': 'ms', 'msec': 'ms', 'msecond': 'ms', 'sec': 's', 'second': 's', 'hour': 'h', 'min': 'm', 'minute': 'm', 'day': 'd', 'week': 'w', 'month': 'mo', 'year': 'y', } def multiply(factors): result = 1 for factor in factors: result = result * factor return result def to_time_unit(human_time, unit='ms', **kwargs): ''' Return a time unit from a human readable string ''' # No need to handle 0 if human_time == "0": return 0 unit_to_short_form = UNIT_TO_SHORT_FORM unit_factors = UNIT_FACTORS unit = unit_to_short_form.get(unit.rstrip('s'), unit) if unit not in unit_factors: raise AnsibleFilterError("to_time_unit() can not convert to the following unit: %s. " "Available units (singular or plural): %s. " "Available short units: %s" % (unit, ', '.join(unit_to_short_form.keys()), ', '.join(unit_factors.keys()))) 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) if not res: raise AnsibleFilterError( "to_time_unit() can not interpret following string: %s" % human_time) h_time_int = int(res.group(1)) h_time_unit = res.group(2) h_time_unit = unit_to_short_form.get(h_time_unit.rstrip('s'), h_time_unit) 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]) result += time_in_milliseconds return round(result / multiply(unit_factors[unit]), 12) def to_milliseconds(human_time, **kwargs): ''' Return milli seconds from a human readable string ''' return to_time_unit(human_time, 'ms', **kwargs) def to_seconds(human_time, **kwargs): ''' Return seconds from a human readable string ''' return to_time_unit(human_time, 's', **kwargs) def to_minutes(human_time, **kwargs): ''' Return minutes from a human readable string ''' return to_time_unit(human_time, 'm', **kwargs) def to_hours(human_time, **kwargs): ''' Return hours from a human readable string ''' return to_time_unit(human_time, 'h', **kwargs) def to_days(human_time, **kwargs): ''' Return days from a human readable string ''' return to_time_unit(human_time, 'd', **kwargs) def to_weeks(human_time, **kwargs): ''' Return weeks from a human readable string ''' return to_time_unit(human_time, 'w', **kwargs) def to_months(human_time, **kwargs): ''' Return months from a human readable string ''' return to_time_unit(human_time, 'mo', **kwargs) def to_years(human_time, **kwargs): ''' Return years from a human readable string ''' return to_time_unit(human_time, 'y', **kwargs) class FilterModule(object): ''' Ansible time jinja2 filters ''' def filters(self): filters = { 'to_time_unit': to_time_unit, 'to_milliseconds': to_milliseconds, 'to_seconds': to_seconds, 'to_minutes': to_minutes, 'to_hours': to_hours, 'to_days': to_days, 'to_weeks': to_weeks, 'to_months': to_months, 'to_years': to_years, } return filters