time diff calculation
This commit is contained in:
parent
000d0ca81f
commit
e4c1b7991e
25
README.md
25
README.md
@ -22,12 +22,22 @@ python tww QUERY [--debug] [--full]
|
||||
- `time between 2012-03-14 and 2012-04-26`
|
||||
- `time since 09:00`
|
||||
- `time until end of workday`
|
||||
- Calculate time differences: `<dt-like> (?\+|\-|plus|minus) <timedelta>` or `<timedelta> (before|from) <dt>`
|
||||
- `12-12-2019 + 2 weeks`
|
||||
- `05:23 - 150 minutes`
|
||||
- `3 days from next Friday`
|
||||
- `2 hours before 15:00`
|
||||
- (Approximate) workdays calculation (assumes monday-friday are work days - ignores public/local holidays (for now)): `work days/hours since/until <datetime-like>` or `
|
||||
- `workdays since 2021-01-05`
|
||||
- `work hours until Friday`
|
||||
- Milliseconds since epoch: `(time/(milli)seconds) since epoch` or datetime to epoch: `<datetime-like> to epoch` or `(milli)seconds since <datetime-like>/epoch`
|
||||
- `2021-01:01 to epoch`
|
||||
- `milliseconds since epoch`
|
||||
- Day of the week
|
||||
- `what day is today`
|
||||
- `2021-05-10 day of week`
|
||||
- Find timezones
|
||||
- `timezone in Brazil`
|
||||
|
||||
|
||||
Few more notes:
|
||||
@ -101,20 +111,7 @@ $ tww 3/14 15 9:26:53 PST to sofia
|
||||
|
||||
|
||||
## TODO
|
||||
* Calculate time differences:
|
||||
- parse `timedelta`:
|
||||
- `(%d) (?year|month|week|day|hour|minute|second)[s]?`
|
||||
- calculate:
|
||||
- `<dt-like> (?\+|\-|plus|minus) <timedelta>`
|
||||
- `12-12-2019 + 2 weeks`
|
||||
- `05:23 - 150 minutes`
|
||||
- `<timedelta> (before|from) <dt>`
|
||||
- `3 days from next Friday`
|
||||
- `2 hours before 15:00`
|
||||
* Day of the week
|
||||
- `what day is <dt>`
|
||||
* Return Time range
|
||||
- parse relative to now:
|
||||
- `(previous|last|this|next) (year|month|week|day|hour|minute|second|Monday|Tuesday|...|Sunday)`
|
||||
|
||||
|
||||
* [Countries names in their own languages](https://www.worldatlas.com/articles/names-of-countries-in-their-own-languages.html), [list of countries in various languages](https://en.wikipedia.org/wiki/List_of_country_names_in_various_languages_(A%E2%80%93C))
|
@ -25,9 +25,14 @@ r_time_in_epoch_ms_now = re.compile('(?:milliseconds since epoch)', flags=re.IGN
|
||||
r_time_in_epoch_ms2 = re.compile('(.*)?\s*(?:in|to)\s*(?:ms|milliseconds|miliseconds)', flags=re.IGNORECASE)
|
||||
r_time_in_epoch_ms3 = re.compile('(?:ms|milliseconds|miliseconds)?\s*since\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_in = re.compile('(?:time)?\s*in\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_since = re.compile('(?:time)?\s*since\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_until = re.compile('(?:time)?\s*until\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_between = re.compile('(?:time)?\s*between\s*(.*)\s*and\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_since = re.compile('(?:time|year|month|week|day|hour|minute|second)?(?:s)?\s*since\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_until = re.compile('(?:time|year|month|week|day|hour|minute|second)?(?:s)?\s*until\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_between = re.compile('(?:time|year|month|week|day|hour|minute|second)?(?:s)?\s*between\s*(.*)\s*and\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_plus = re.compile('(.*)\s*(?:plus|\+|after|from)\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_minus = re.compile('(.*)\s*(?:minus|\-)\s*(.*)', flags=re.IGNORECASE)
|
||||
r_time_before = re.compile('(.*)\s*(?:before|\-)\s*(.*)', flags=re.IGNORECASE)
|
||||
r_weekday_pre = re.compile('(?:day of week|weekday|week day|what day is|what day of week is)\s*(.*)', flags=re.IGNORECASE)
|
||||
r_weekday_post = re.compile('(.*)\s*(?:day of week|weekday|week day|what day|what day of week)', flags=re.IGNORECASE)
|
||||
r_workdays_since = re.compile('(?:workdays|work days)\s*since\s*(.*)', flags=re.IGNORECASE)
|
||||
r_workdays_until = re.compile('(?:workdays|work days)\s*until\s*(.*)', flags=re.IGNORECASE)
|
||||
r_workdays_between = re.compile('(?:workdays|work days)\s*between\s*(.*)\s*and\s*(.*)', flags=re.IGNORECASE)
|
||||
@ -99,7 +104,7 @@ def handler_workhours_since_until(start_dt_s: str):
|
||||
return handler_workhours_diff(dateparser_parse_dt(start_dt_s), get_local_now())
|
||||
|
||||
|
||||
def timezone_mangle(dt_s: str, timezone_like_s: str) -> dict:
|
||||
def timezone_mangle(dt_s: str, timezone_like_s: str):
|
||||
logger.debug("Timezone translation between {} | {}".format(dt_s, timezone_like_s))
|
||||
if dt_s.lower().strip() == "time":
|
||||
dt_s = "now"
|
||||
@ -108,7 +113,7 @@ def timezone_mangle(dt_s: str, timezone_like_s: str) -> dict:
|
||||
tz = resolve_timezone(timezone_like_s)
|
||||
logger.debug("Destination timezone: {}".format(tz))
|
||||
if not tz:
|
||||
tz, dst_dt = {}, src_dt
|
||||
tz, dst_dt, offset = {}, src_dt, {}
|
||||
else:
|
||||
offset = tz.get('tz_offset')
|
||||
return src_dt, offset, tz
|
||||
@ -146,6 +151,37 @@ def handler_timezone(timezone_s: str):
|
||||
return resolve_timezone(timezone_s)
|
||||
|
||||
|
||||
def get_timedelta(td: str, direction='future'):
|
||||
if direction in ['future']:
|
||||
prefix = 'in {}'
|
||||
else:
|
||||
prefix = '{} ago'
|
||||
other_dt = dateparser_parse_dt(prefix.format(td))
|
||||
now = get_local_now()
|
||||
if direction in ['future']:
|
||||
return other_dt - now
|
||||
else:
|
||||
return now - other_dt
|
||||
|
||||
|
||||
def handler_time_plus(dt_s: str, td: str):
|
||||
dt = dateparser_parse_dt(dt_s)
|
||||
td = get_timedelta(td)
|
||||
return dt + td
|
||||
|
||||
|
||||
def handler_time_minus(dt_s: str, td: str):
|
||||
dt = dateparser_parse_dt(dt_s)
|
||||
td = get_timedelta(td, direction='past')
|
||||
return dt - td
|
||||
|
||||
|
||||
def handler_time_before(td: str, dt_s: str):
|
||||
dt = dateparser_parse_dt(dt_s)
|
||||
td = get_timedelta(td, direction='past')
|
||||
return dt - td
|
||||
|
||||
|
||||
QUERY_TYPE_DT_TR = "datetime_translation"
|
||||
QUERY_TYPE_DT = "datetime_details"
|
||||
QUERY_TYPE_TZ = "timezone"
|
||||
@ -159,6 +195,7 @@ h_time_in = 'dt->hh:mm'
|
||||
h_translation = 'dt->iso8601_full'
|
||||
h_default_dt = 'dt->iso8601_full'
|
||||
h_default_td = 'timedelta->diff->duration_human'
|
||||
h_day_of_week = 'dt->locale_day_of_week'
|
||||
|
||||
regex_handlers = [
|
||||
(r_time_in_epoch_s_now, handler_time_now_local, QUERY_TYPE_DT, h_unix_s),
|
||||
@ -174,6 +211,11 @@ regex_handlers = [
|
||||
(r_time_since, handler_time_since_until, QUERY_TYPE_TD, h_default_td),
|
||||
(r_time_until, handler_time_since_until, QUERY_TYPE_TD, h_default_td),
|
||||
(r_time_between, handler_time_diff, QUERY_TYPE_TD, h_default_td),
|
||||
(r_time_plus, handler_time_plus, QUERY_TYPE_DT, h_default_dt),
|
||||
(r_time_minus, handler_time_minus, QUERY_TYPE_DT, h_default_dt),
|
||||
(r_time_before, handler_time_before, QUERY_TYPE_DT, h_default_dt),
|
||||
(r_weekday_pre, handler_generic_parser, QUERY_TYPE_DT, h_day_of_week),
|
||||
(r_weekday_post, handler_generic_parser, QUERY_TYPE_DT, h_day_of_week),
|
||||
(r_workdays_since, handler_workdays_since_until, QUERY_TYPE_TD, h_default_td),
|
||||
(r_workdays_until, handler_workdays_since_until, QUERY_TYPE_TD, h_default_td),
|
||||
(r_workdays_between, handler_workdays_diff, QUERY_TYPE_TD, h_default_td),
|
||||
@ -224,7 +266,7 @@ def pretty_print_dict(obj):
|
||||
return colorful_json
|
||||
|
||||
|
||||
def show_magic_results(obj, args):
|
||||
def show_magic_results(obj, args, results=1):
|
||||
rv = []
|
||||
for solution in obj['solutions']:
|
||||
entry_proxy = Cut(solution, sep='->')
|
||||
@ -232,6 +274,7 @@ def show_magic_results(obj, args):
|
||||
try:
|
||||
highlight_result = entry_proxy[highlight_entry]
|
||||
except Exception as e:
|
||||
logger.debug("Exception from magic result: {} -> {}".format(highlight_entry, e))
|
||||
continue
|
||||
if args.handlers:
|
||||
to_print = "{} -> {}".format(solution['handler'], highlight_result)
|
||||
@ -239,8 +282,11 @@ def show_magic_results(obj, args):
|
||||
to_print = highlight_result
|
||||
rv.append(to_print)
|
||||
print(to_print)
|
||||
if len(rv) >= results:
|
||||
break
|
||||
return rv
|
||||
|
||||
|
||||
def dt_pretty(dt):
|
||||
rv = {}
|
||||
global custom_locale
|
||||
|
72
tww/web.py
72
tww/web.py
@ -5,9 +5,6 @@ from tokenizer import resolve_query, QUERY_TYPE_DT, QUERY_TYPE_DT_TR, QUERY_TYPE
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
import dateparser
|
||||
from tww.lib import resolve_timezone
|
||||
|
||||
IN_KW = " in "
|
||||
TO_KW = " to "
|
||||
NO_TZ_FORMAT = '%Y-%m-%dT%H:%M:%S'
|
||||
@ -17,75 +14,6 @@ TIME_FORMAT = '%H:%M:%S'
|
||||
TZ_OFFSET_FORMAT = '%z'
|
||||
|
||||
|
||||
def parse_query(q):
|
||||
fmt = NO_TZ_FORMAT
|
||||
to_split = q.split(TO_KW)
|
||||
in_dt_resolve_fmt, to_dt_resolve_fmt = {}, {}
|
||||
in_tz_resolve, to_tz_resolve = {}, {}
|
||||
error = ""
|
||||
if len(to_split) >= 2:
|
||||
# 18:00 to Zurich
|
||||
in_q, to_tz = to_split[0], TO_KW.join(to_split[1:])
|
||||
else:
|
||||
# 18:00
|
||||
in_q = q
|
||||
to_tz = ""
|
||||
in_split = in_q.split(IN_KW)
|
||||
if len(in_split) >= 2:
|
||||
# 18:00 in Zurich
|
||||
in_dt, in_tz = in_split[0], IN_KW.join(in_split[1:])
|
||||
else:
|
||||
# in 2 hours / 19:00 CET
|
||||
in_dt = in_q
|
||||
in_tz = ""
|
||||
try:
|
||||
in_dt_resolve = dateparser.parse(in_dt, settings={
|
||||
'RETURN_AS_TIMEZONE_AWARE': True})
|
||||
if not in_tz:
|
||||
in_tz = in_dt_resolve.strftime("%Z")
|
||||
if in_tz:
|
||||
isofmt = in_dt_resolve.isoformat()
|
||||
in_tz_resolve = resolve_timezone(in_tz)
|
||||
in_dt_resolve = dateparser.parse(isofmt, settings={
|
||||
'TO_TIMEZONE': in_tz_resolve})
|
||||
to_dt_resolve, to_tz_resolve = in_dt_resolve, in_tz_resolve
|
||||
if in_dt_resolve:
|
||||
in_dt_resolve_fmt = {
|
||||
'iso': in_dt_resolve.strftime(ISO_FORMAT),
|
||||
'fmt': in_dt_resolve.strftime(fmt),
|
||||
'date': in_dt_resolve.strftime(DATE_FORMAT),
|
||||
'time': in_dt_resolve.strftime(TIME_FORMAT),
|
||||
'tz_offset': in_dt_resolve.strftime(TZ_OFFSET_FORMAT),
|
||||
}
|
||||
if to_tz:
|
||||
isofmt = in_dt_resolve.isoformat()
|
||||
to_tz_resolve = resolve_timezone(to_tz)
|
||||
to_dt_resolve = dateparser.parse(isofmt, settings={
|
||||
'TO_TIMEZONE': to_tz_resolve})
|
||||
if to_dt_resolve:
|
||||
to_dt_resolve_fmt = {
|
||||
'iso': to_dt_resolve.strftime(ISO_FORMAT),
|
||||
'fmt': to_dt_resolve.strftime(fmt),
|
||||
'date': to_dt_resolve.strftime(DATE_FORMAT),
|
||||
'time': to_dt_resolve.strftime(TIME_FORMAT),
|
||||
'tz_offset': to_dt_resolve.strftime(TZ_OFFSET_FORMAT),
|
||||
}
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
return {
|
||||
'error': error,
|
||||
'query': q,
|
||||
'fmt': fmt,
|
||||
'in_dt': in_dt,
|
||||
'in_tz_resolve': in_tz_resolve,
|
||||
'in_dt_resolve': in_dt_resolve_fmt,
|
||||
'to_dt_resolve': to_dt_resolve_fmt,
|
||||
'in_tz': in_tz,
|
||||
'to_tz': to_tz,
|
||||
'to_tz_resolve': to_tz_resolve,
|
||||
}
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def home():
|
||||
ctx = dict(all_tz=pytz.all_timezones)
|
||||
|
Loading…
Reference in New Issue
Block a user