diff --git a/README.md b/README.md index 4b2d22a..b5d7e39 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Other optional fields are: |`parts`|integer|`1`|`3`|The number of time fractions which should be used| |`month`|boolean|`true`|`false`|Set to `false` to not split in months, but add those to the amount of weeks/days| |`week`|boolean|`true`|`false`|Set to `false` to not split in weeks, but add those to the amount of days| +|`millisecond`|boolean|`false`|`true`|Set to `true` to include milliseconds in the output| |`time`|boolean|`true`|`false`|Set to `false` to ignore time and only compare on date| |`abbr`|boolean|`false`|`true`|Set to `true` to use the abbreviated phrases| |`language`|string|`"en"`|`"nl"`|The country code (eg `dk` for Denmark) for the language to be used for the output| diff --git a/relative_time_plus.jinja b/relative_time_plus.jinja index 34e93d2..254c885 100644 --- a/relative_time_plus.jinja +++ b/relative_time_plus.jinja @@ -15,6 +15,7 @@ 'hour': ['hour', 'hours', 'hr'], 'minute': ['minute', 'minutes', 'min'], 'second': ['second', 'seconds', 'sec'], + 'millisecond': ['millisecond', 'milliseconds', 'ms'], 'combine': 'and', 'error': 'Invalid date' } @@ -30,6 +31,7 @@ 'hour': ['godzina', 'godzin', 'godz'], 'minute': ['minuta', 'minut', 'min'], 'second': ['sekunda', 'sekund', 'sek'], + 'millisecond': ['milisekunda', 'milisekund', 'ms'], 'combine': 'i', 'error': 'Niepoprawna data' } @@ -45,6 +47,7 @@ 'hour': ['heure', 'heures', 'h'], 'minute': ['minute', 'minutes', 'min'], 'second': ['seconde', 'secondes', 'sec'], + 'millisecond': ['milliseconde', 'millisecondes', 'ms'], 'combine': 'et', 'error': 'Date non valide' } @@ -60,6 +63,7 @@ 'hour': ['ora', 'ore', 'h'], 'minute': ['minuto', 'minuti', 'min'], 'second': ['secondo', 'secondi', 'sec'], + 'millisecond': ['millisecondo', 'millisecondi', 'ms'], 'combine': 'e', 'error': 'Data non valida' } @@ -75,6 +79,7 @@ 'hour': ['uur', 'uur', 'u'], 'minute': ['minuut', 'minuten', 'min'], 'second': ['seconde', 'seconden', 'sec'], + 'millisecond': ['milliseconde', 'milliseconden', 'ms'], 'combine': 'en', 'error': 'Ongeldige datum' } @@ -90,6 +95,7 @@ 'hour': ['Stunde', 'Stunden', 'Std.'], 'minute': ['Minute', 'Minuten', 'Min.'], 'second': ['Sekunde', 'Sekunden', 'Sek.'], + 'millisecond': ['Milliseconde', 'Milliseconden', 'ms'], 'combine': 'und', 'error': 'Falsches Datum' } @@ -105,6 +111,7 @@ 'hour': ['hora', 'horas', 'h'], 'minute': ['minuto', 'minutos', 'min'], 'second': ['segundo', 'segundos', 'seg'], + 'millisecond': ['millissegundo', 'millissegundos', 'ms'], 'combine': 'e', 'error': 'Data Inválida' } @@ -120,6 +127,7 @@ 'hour': ['time', 'timer', 't.'], 'minute': ['minut', 'minuter', 'min.'], 'second': ['sekund', 'sekunder', 'sek.'], + 'millisecond': ['millisekund', 'millisekunder', 'ms.'], 'combine': 'og', 'error': 'Ugyldig dato' } @@ -131,46 +139,47 @@ macro to split a timedelta in years, months, weeks, days, hours, minutes, seconds used by the relative time plus macro, set up as a seperate macro so it can be reused #} -{%- macro time_split(date, compare_date=now(), month=true, week=true, time=true) -%} +{%- macro time_split(date, compare_date=now(), month=true, week=true, millisecond=false, time=true) -%} {# set defaults for variables #} {%- set date = date | as_local if time else date.date()-%} {%- set time = time | bool(true) -%} - {%- set n = compare_date -%} - {%- set n = n if time else n.date() -%} - {%- set a = [n, date] | max -%} - {%- set b = [n, date] | min -%} + {%- set comp_date = compare_date if time else compare_date.date() -%} + {%- set date_max = [comp_date, date] | max -%} + {%- set date_min = [comp_date, date] | min -%} {#- set time periods in seconds #} {%- set m, h, d, w = 60, 3600, 86400, 604800 -%} {#- set numer of years, and set lowest date using this number of years #} - {%- set yrs = a.year - b.year - (1 if a.replace(year=b.year) < b else 0) -%} - {%- set a = a.replace(year=a.year - yrs) -%} + {%- set yrs = date_max.year - date_min.year - (1 if date_min.replace(year=date_max.year) < date_min else 0) -%} + {%- set date_max = date_max.replace(year=date_max.year - yrs) -%} {#- set numer of months, and set lowest date using this number of months #} {%- if month -%} - {%- set mth = (a.month - b.month - (1 if a.day < b.day else 0) + 12) % 12 -%} - {%- set month_new = (((a.month - mth) + 12) % 12) | default(12, true) -%} - {%- set day_max = ((a.replace(day=1, month=month_new) + timedelta(days=31)).replace(day=1) - timedelta(days=1)).day -%} - {%- set a_temp = a.replace(month=month_new, day=[a.day, day_max]|min) -%} - {%- set a = a_temp if a_temp <= a else a_temp.replace(year=a.year-1) -%} + {%- set mth = (date_max.month - date_min.month - (1 if date_max.day < date_min.day else 0) + 12) % 12 -%} + {%- set month_new = (((date_max.month - mth) + 12) % 12) | default(12, true) -%} + {%- set day_max = ((date_max.replace(day=1, month=month_new) + timedelta(days=31)).replace(day=1) - timedelta(days=1)).day -%} + {%- set date_temp = date_max.replace(month=month_new, day=[date_max.day, day_max]|min) -%} + {%- set date_max = date_temp if date_temp <= date_max else date_temp.replace(year=a.year-1) -%} {%- endif -%} {#- set other time period variables #} - {%- set s = (a - b).total_seconds() -%} + {%- set s = (date_max - date_min).total_seconds() -%} {%- set wks = 0 if not week else (s // w) | int -%} {%- set day = ((s - wks * w) // d) | int -%} {%- set hrs = ((s - wks * w - day * d) // h) | int -%} {%- set min = ((s - wks * w - day * d - hrs * h) // m) | int -%} {%- set sec = (s - wks * w - day * d - hrs * h - min * m) | int -%} + {%- set ms = (s % 1 * 1000) | round | int -%} {# output result #} - {%- set output = dict(year=yrs, month=mth | default(0), week=wks, day=day, hour=hrs, minute=min, second=sec) %} + {%- set output = dict(year=yrs, month=mth | default(0), week=wks, day=day, hour=hrs, minute=min, second=sec, millisecond=ms) %} {{- dict(output.items() | rejectattr('0', 'eq', 'month' if not month) | rejectattr('0', 'eq', 'week' if not week) + | rejectattr('0', 'eq', 'millisecond' if not millisecond) | rejectattr('0', 'in', ['hour', 'minute', 'second'] if not time else []) ) | to_json -}} {%- endmacro -%} {# macro to output a timedelta in a readable format #} -{%- macro relative_time_plus(date, parts=1, abbr=false, verbose=false, language='en', compare_date=now(), month=true, week=true, time=true) -%} +{%- macro relative_time_plus(date, parts=1, abbr=false, verbose=false, language='en', compare_date=now(), month=true, week=true, millisecond=false, time=true) -%} {#- set defaults for input if not entered #} {%- set date = date if date is datetime else date | as_datetime -%} {%- set compare_date = compare_date if compare_date is datetime else compare_date | as_datetime -%} @@ -180,33 +189,30 @@ {%- set language = iif(language in languages, language, 'en') -%} {%- set phr = phrases | selectattr('language', 'eq', language) | map(attribute='phrases') | list | first -%} {#- perform smart stuff #} - {%- if date is datetime -%} - {%- set date = date | as_local -%} + {%- if date is datetime and compare_date is datetime -%} + {%- set date, compare_date = date | as_local, compare_date | as_local -%} {%- set parts = parts | int(1) -%} {%- set week = week | bool(true) -%} {%- set time = time | bool(true) -%} {%- set abbr = abbr | bool(false) or verbose | bool(false) -%} {%- set date = date if time else date.date() -%} - {%- set tp = time_split(date, compare_date, month, week, time) | from_json -%} + {%- set time_parts = time_split(date, compare_date, month, week, time) | from_json -%} {#- find first non zero time period #} - {%- set first = tp.items() | selectattr('1') | map(attribute='0') | first | default('second' if time else 'day') -%} + {%- set always_return = 'millisecond' if millisecond else 'second' if time else 'day' -%} + {%- set first = time_parts.items() | selectattr('1') | map(attribute='0') | first | default(always_return) -%} {#-select non zero items based on input #} - {%- set index_first = (tp.keys() | list).index(first) -%} - {%- set items = (tp.keys() | list)[index_first:index_first + parts] -%} + {%- set index_first = (time_parts.keys() | list).index(first) -%} + {%- set items = (time_parts.keys() | list)[index_first:index_first + parts] -%} {# convert to phrases #} - {#- macro to create the phrases for each time period -#} - {%- macro set_phrase(value, time_period, abbr) -%} - {%- set phr_abbr = phr[time_period][2] -%} - {%- set phr_verb = phr[time_period][1] if value != 1 else phr[time_period][0] -%} - {{- '{} {}'.format(value, phr_abbr if abbr else phr_verb) -}} - {%- endmacro -%} - {# perform conversion #} - {%- set ns = namespace(text=[]) -%} - {%- for i in items -%} - {%- set ns.text = ns.text + [set_phrase(tp[i], i, abbr)] -%} - {%- endfor -%} - {#- join texts in a string, using phr.combine for the last item #} - {{- '{} {} {}'.format(ns.text[:-1] | join(', '), phr.combine, ns.text[-1]) if ns.text | count > 1 else ns.text | first -}} + {%- set ns = namespace(phrases=[]) -%} + {%- for i in items if time_parts[i] or i == first -%} + {%- set phr_abbr = phr[i][2] -%} + {%- set phr_verb = phr[i][1] if time_parts[i] != 1 else phr[i][0] -%} + {%- set phrase = '{} {}'.format(time_parts[i], phr_abbr if abbr else phr_verb) -%} + {%- set ns.phrases = ns.phrases + [phrase] -%} + {%- endfor -%} + {#- join phrases in a string, using phr.combine for the last item #} + {{- '{} {} {}'.format(ns.phrases[:-1] | join(', '), phr.combine, ns.phrases[-1]) if ns.phrases | count > 1 else ns.phrases | first -}} {%- else -%} {{- phr.error -}} {%- endif -%}