timedelta formatter

This commit is contained in:
Daniel Tsvetkov 2020-02-11 12:37:35 +01:00
parent abbba47bb5
commit ddd352865a

View File

@ -1,12 +1,13 @@
import json import json
import re import re
import sys
from datetime import datetime from datetime import datetime
from pygments import highlight, lexers, formatters from pygments import highlight, lexers, formatters
from tww import ISO_FORMAT, time_to_emoji from tww import ISO_FORMAT, time_to_emoji, time_ago
from tww import resolve_timezone, dateparser_parse_dt, get_utcnow, get_s_since_epoch, get_ms_since_epoch, \ from tww import resolve_timezone, dateparser_parse_dt, get_utcnow, get_s_since_epoch, get_ms_since_epoch, \
dt_tz_translation, DEFAULT_FORMAT, get_local_now, query_to_format_result dt_tz_translation, get_local_now, query_to_format_result
r_generic = re.compile('(.*)', flags=re.IGNORECASE) r_generic = re.compile('(.*)', flags=re.IGNORECASE)
r_time_in_epoch_s_now = re.compile('(?:time since epoch|seconds since epoch)', flags=re.IGNORECASE) r_time_in_epoch_s_now = re.compile('(?:time since epoch|seconds since epoch)', flags=re.IGNORECASE)
@ -48,32 +49,28 @@ def handler_time_ms_now_utc() -> int:
return get_ms_since_epoch(get_utcnow()) return get_ms_since_epoch(get_utcnow())
def handler_time_diff(start_dt: str, end_dt: str) -> dict: def handler_time_diff(start_dt: datetime, end_dt: datetime) -> dict:
start, end = dateparser_parse_dt(start_dt), dateparser_parse_dt(end_dt) diff = end_dt - start_dt
return dict(start=start.strftime(DEFAULT_FORMAT), return dict(start=dt_pretty(start_dt),
end=end.strftime(DEFAULT_FORMAT), end=dt_pretty(end_dt),
diff=end - start) diff=td_pretty(diff))
def handler_time_since(start_dt_s: str) -> dict: def handler_time_since_until(start_dt_s: str) -> dict:
return handler_time_diff(start_dt_s, str(get_utcnow())) return handler_time_diff(dateparser_parse_dt(start_dt_s), get_local_now())
def handler_time_until(end_dt_s: str) -> dict:
return handler_time_diff(str(get_utcnow()), end_dt_s)
def handler_timezone_translation(dt_s: str, timezone_like_s: str) -> dict: def handler_timezone_translation(dt_s: str, timezone_like_s: str) -> dict:
dt = dateparser_parse_dt(dt_s) src_dt = dateparser_parse_dt(dt_s)
tz = resolve_timezone(timezone_like_s) tz = resolve_timezone(timezone_like_s)
if not tz: if not tz:
tz, offset, the_time = '', '', dt tz, dst_dt = {}, src_dt
else: else:
offset = tz.get('tz_offset') offset = tz.get('tz_offset')
translation = dt_tz_translation(dt, offset) dst_dt = dt_tz_translation(src_dt, offset)
the_time = translation.strftime(DEFAULT_FORMAT) return dict(
return dict(dt=the_time, src_dt=dt_pretty(src_dt),
offset=offset, dst_dt=dt_pretty(dst_dt),
tz=tz, tz=tz,
) )
@ -109,8 +106,8 @@ regex_handlers = [
(r_time_in_epoch_ms2, handler_time_ms, QUERY_TYPE_DT), (r_time_in_epoch_ms2, handler_time_ms, QUERY_TYPE_DT),
(r_time_in_epoch_ms3, handler_time_ms, QUERY_TYPE_DT), (r_time_in_epoch_ms3, handler_time_ms, QUERY_TYPE_DT),
(r_timezone_translation, handler_timezone_translation, QUERY_TYPE_DT_TR), (r_timezone_translation, handler_timezone_translation, QUERY_TYPE_DT_TR),
(r_time_since, handler_time_since, QUERY_TYPE_TD), (r_time_since, handler_time_since_until, QUERY_TYPE_TD),
(r_time_until, handler_time_until, QUERY_TYPE_TD), (r_time_until, handler_time_since_until, QUERY_TYPE_TD),
(r_time_between, handler_time_diff, QUERY_TYPE_TD), (r_time_between, handler_time_diff, QUERY_TYPE_TD),
(r_time_in, handler_time_in_parser, QUERY_TYPE_DT), (r_time_in, handler_time_in_parser, QUERY_TYPE_DT),
(r_timezone, handler_timezone, QUERY_TYPE_TZ), (r_timezone, handler_timezone, QUERY_TYPE_TZ),
@ -140,7 +137,7 @@ def tokenize(s):
except Exception as e: except Exception as e:
continue continue
if result is not None: if result is not None:
solutions.append((h.__name__, (result, ), t)) solutions.append((h.__name__, (result,), t))
return solutions return solutions
@ -197,6 +194,74 @@ def dt_pretty(dt):
return rv return rv
def td_remainders(td):
# split seconds to larger units
seconds = td.total_seconds()
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
days, hours = divmod(hours, 24)
months, days = divmod(days, 30.42)
years, months = divmod(months, 12)
years, months, days, hours, minutes, seconds = map(int, (years, months, days, hours, minutes, seconds))
years, months, days, hours, minutes, seconds = map(abs, (years, months, days, hours, minutes, seconds))
return dict(
seconds=seconds,
minutes=minutes,
hours=hours,
days=days,
months=months,
years=years,
)
def td_totals(td):
seconds = td.total_seconds()
minutes = seconds // 60
hours = seconds // (60 * 60)
days = seconds // (24 * 60 * 60)
weeks = seconds // (7 * 24 * 60 * 60)
months = seconds // (30 * 24 * 60 * 60)
years = seconds // (365 * 24 * 60 * 60)
years, months, weeks, days, hours, minutes, seconds = map(abs, (years, months, weeks, days, hours, minutes, seconds))
return dict(
seconds=seconds,
minutes=minutes,
hours=hours,
days=days,
weeks=weeks,
months=months,
years=years,
)
def td_iso8601(td):
"""P[n]Y[n]M[n]DT[n]H[n]M[n]S"""
rem = td_remainders(td)
fmt = "P"
for short, timeframe in [("Y", "years"), ("M", "months"), ("D", "days")]:
if rem[timeframe]:
fmt += "{}{}".format(rem[timeframe], short)
hms = [("H", "hours"), ("M", "minutes"), ("S", "seconds")]
if any([rem[t[1]] for t in hms]):
fmt += "T"
for short, timeframe in hms:
if rem[timeframe]:
fmt += "{}{}".format(rem[timeframe], short)
return fmt
def td_pretty(td):
rv = {
"sign": '-' if td.days < 0 else '+',
"in_the": 'future' if td.days < 0 else 'past',
"time_ago": time_ago(td),
"duration_iso8601": td_iso8601(td),
"totals": td_totals(td),
"remainders": td_remainders(td),
}
return rv
def resolve_query_type(query): def resolve_query_type(query):
solutions = tokenize(query) solutions = tokenize(query)
if not solutions: if not solutions:
@ -230,7 +295,7 @@ def resolve_query(query):
if __name__ == "__main__": if __name__ == "__main__":
query = "now in sofia" # query = "time since 27 January 1992"
# query = ' '.join(sys.argv[1:]) query = ' '.join(sys.argv[1:])
result = resolve_query(query) result = resolve_query(query)
pretty_print_dict(result) pretty_print_dict(result)