update documentation, fix some cases
This commit is contained in:
parent
6681f7dfd5
commit
8c68d50964
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
|||||||
venv
|
venv
|
||||||
src/tww/data/.cache.csv
|
tww/data/.cache.csv
|
||||||
__pycache__
|
__pycache__
|
||||||
.idea
|
.idea
|
||||||
tww.egg-info
|
tww.egg-info
|
39
README.md
39
README.md
@ -3,15 +3,40 @@ Find time now, in the past or future in any timezone or location.
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
```
|
```
|
||||||
python tz.py QUERY [--format="%Y-%m-%d %H:%M:%S%z"] [--debug]
|
python tww QUERY [--debug] [--full]
|
||||||
```
|
```
|
||||||
|
|
||||||
* `QUERY` - is of the form `<datetime-like> to <timezone or location>`
|
* Supported `QUERY` types:
|
||||||
|
- Timezone translation `<datetime-like> in <timezone/location> to <destination timezone/location>` or `<datetime-like> to <timezone/location>` (assumes datetime is `local`)
|
||||||
|
- `04:26 in japan to local`
|
||||||
|
- `03:14 in local to IST`
|
||||||
|
- `15:20 to America/New_York`
|
||||||
|
- `2021-12-25 12:00 in Brazil`
|
||||||
|
- Time difference: `(time) between <datetime-like> and <datetime-like>` or `(time) since <datetime-like` or `(time) until <datetime-like>`
|
||||||
|
- `time between 2012-03-14 and 2012-04-26`
|
||||||
|
- `time since 09:00`
|
||||||
|
- `time until end of workday`
|
||||||
|
- (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/seconds) since epoch`
|
||||||
|
- Datetime to epoch: `<datetime-like> to epoch` or `(milli)seconds since <datetime-like>/epoch`
|
||||||
|
- `2021-01:01 to epoch`
|
||||||
|
- `milliseconds since epoch`
|
||||||
|
|
||||||
`<datetime-like>` is any time or time-like string - or example `2019-04-26 3:14`, `06:42`, timezones `15:10 cet` but also some human readable like `now`, `in 3 hours`, `7 minutes ago` and many others. See [dateparser](https://pypi.org/project/dateparser/) for more.
|
|
||||||
|
|
||||||
`to <timezone or location>` is optional. It has to have the word `to` which specifies that timezone or location follows. It is either:
|
Few more notes:
|
||||||
- timezone (tried first) to which the date should be translated or
|
- `<datetime-like>` is any time or time-like string - or example:
|
||||||
|
- `2019-04-26 3:14`, `06:42` `27 January 1992`,
|
||||||
|
- some human readable like `now`, `in 3 hours`, `7 minutes ago` and many others.
|
||||||
|
- See [dateparser](https://pypi.org/project/dateparser/) for more.
|
||||||
|
- custom date-times (like `christmas`, `new years`, `end of workday`) defined in `data/custom_dt.csv`
|
||||||
|
|
||||||
|
- `<timezone/location>` is either:
|
||||||
|
- timezone (tried first) - it can be:
|
||||||
|
- [tz database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (like `Europe/Sofia`),
|
||||||
|
- [UTC time offset](https://en.wikipedia.org/wiki/List_of_UTC_time_offsets) (with colon `:` or not like `+02:00` or `+0530`), or
|
||||||
|
- [abbreviation](https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations) (like `UTC`, `CET`, `PST` - however please note that these are not unique and resolution might wrong)
|
||||||
- a location. Uses a local database of files of countries and cities. It then tries to fuzzymatch the query using [fuzzywuzzy](https://github.com/seatgeek/fuzzywuzzy). In case it can't find the country or city, it uses [geopy](https://geopy.readthedocs.io/en/stable/) for location resolution. Finally it uses [timezonefinder](https://pypi.org/project/timezonefinder/) for timezone resolution.
|
- a location. Uses a local database of files of countries and cities. It then tries to fuzzymatch the query using [fuzzywuzzy](https://github.com/seatgeek/fuzzywuzzy). In case it can't find the country or city, it uses [geopy](https://geopy.readthedocs.io/en/stable/) for location resolution. Finally it uses [timezonefinder](https://pypi.org/project/timezonefinder/) for timezone resolution.
|
||||||
|
|
||||||
* `--format` is the format of the time to be displayed. See supported [datetime formats](https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior)
|
* `--format` is the format of the time to be displayed. See supported [datetime formats](https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior)
|
||||||
@ -27,10 +52,10 @@ pip install -r requirements.txt
|
|||||||
You could alias the whole command to `tww` for faster typing, e.g. in your `.bashrc`:
|
You could alias the whole command to `tww` for faster typing, e.g. in your `.bashrc`:
|
||||||
|
|
||||||
```
|
```
|
||||||
alias tww="~/workspace/tz/venv/bin/python ~/workspace/tz/tz.py"
|
alias tww="~/workspace/tww/venv/bin/python ~/workspace/tww/main.py"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Examples
|
## More Examples
|
||||||
|
|
||||||
Time now (in this timezone):
|
Time now (in this timezone):
|
||||||
|
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
sofia,42.6975135,23.3241463
|
|
||||||
india,20.0,77.0
|
|
||||||
is,64.9841821,-18.1059013
|
|
||||||
u,42.6384261,12.674297
|
|
||||||
i,22.3511148,78.6677428
|
|
||||||
ut,39.4225192,-111.7143584
|
|
||||||
so,8.3676771,49.083416
|
|
||||||
sofi,42.6975135,23.3241463
|
|
||||||
z,-48.5693327,-70.1606767
|
|
||||||
zu,47.1666667,8.5166664
|
|
||||||
zur,47.1666667,8.5166664
|
|
||||||
zuri,47.1666667,8.5166664
|
|
||||||
zuric,47.3666667,8.5500002
|
|
||||||
zurich,47.3666667,8.5500002
|
|
||||||
gl,77.6192349,-42.8125967
|
|
||||||
gla,37.08034,14.2306747
|
|
||||||
glas,37.08034,14.2306747
|
|
||||||
glasg,37.08034,14.2306747
|
|
||||||
glasgow,55.8333333,-4.25
|
|
||||||
L,33.7680065,66.2385139
|
|
||||||
lo,-17.6394444,-71.3375015
|
|
||||||
L,33.7680065,66.2385139
|
|
||||||
lond,31.9513889,34.8952789
|
|
||||||
londo,51.5084153,-0.1255327
|
|
||||||
london,51.5084153,-0.1255327
|
|
||||||
london ,51.5084153,-0.1255327
|
|
||||||
ne,6.9833333,171.6999969
|
|
||||||
n,64.5731537,11.52803643954819
|
|
||||||
new,6.9833333,171.6999969
|
|
||||||
new ,6.9833333,171.6999969
|
|
||||||
new yo,6.9833333,171.6999969
|
|
||||||
new yor,6.9833333,171.6999969
|
|
||||||
new york,6.9833333,171.6999969
|
|
||||||
new york ,6.9833333,171.6999969
|
|
||||||
mo,14.1194444,15.3133335
|
|
||||||
M,-13.2687204,33.9301963
|
|
||||||
mou,14.1194444,15.3133335
|
|
||||||
mount,14.1194444,15.3133335
|
|
||||||
M,-13.2687204,33.9301963
|
|
||||||
mounta,14.1194444,15.3133335
|
|
||||||
mountai,14.1194444,15.3133335
|
|
||||||
mountain ,14.1194444,15.3133335
|
|
||||||
mountain vi,14.1194444,15.3133335
|
|
||||||
mountain view,14.1194444,15.3133335
|
|
||||||
in,6.9833333,171.6999969
|
|
||||||
ind,20.0,77.0
|
|
||||||
indi,20.0,77.0
|
|
||||||
local,37.6666667,-1.7
|
|
||||||
+02:,49.453285449999996,3.606899003594057
|
|
||||||
it,33.6366667,42.8224983
|
|
||||||
G,32.3293809,-83.1137366
|
|
||||||
D,10.0,-67.166667
|
|
||||||
dub,-32.25,148.6166687
|
|
||||||
D,10.0,-67.166667
|
|
||||||
dubli,53.3330556,-6.248889
|
|
||||||
dublin,53.3330556,-6.248889
|
|
||||||
Du,25.0750095,55.18876088183319
|
|
||||||
dublin ,53.3330556,-6.248889
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
sof,42.6975135,23.3241463
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
sofia ,42.6975135,23.3241463
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
du,-32.25,148.6166687
|
|
||||||
D,10.0,-67.166667
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
D,10.0,-67.166667
|
|
||||||
D,10.0,-67.166667
|
|
||||||
new y,6.9833333,171.6999969
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
S,35.7724185,127.79654346305617
|
|
||||||
D,10.0,-67.166667
|
|
||||||
dubl,53.3330556,-6.248889
|
|
||||||
D,10.0,-67.166667
|
|
|
47
tww/lib.py
47
tww/lib.py
@ -206,7 +206,6 @@ def resolve_location_local(query):
|
|||||||
return ""
|
return ""
|
||||||
ratio, location = result
|
ratio, location = result
|
||||||
logger.debug("Location result ({}): {}".format(-ratio, location))
|
logger.debug("Location result ({}): {}".format(-ratio, location))
|
||||||
write_to_cache(query, location)
|
|
||||||
return location
|
return location
|
||||||
|
|
||||||
|
|
||||||
@ -757,20 +756,60 @@ def td_remainders(td):
|
|||||||
minutes, seconds = divmod(abs(int(seconds)), 60)
|
minutes, seconds = divmod(abs(int(seconds)), 60)
|
||||||
hours, minutes = divmod(abs(int(minutes)), 60)
|
hours, minutes = divmod(abs(int(minutes)), 60)
|
||||||
days, hours = divmod(abs(int(hours)), 24)
|
days, hours = divmod(abs(int(hours)), 24)
|
||||||
months, days = divmod(abs(int(days)), 30.42)
|
total_days = days
|
||||||
|
months, days = divmod(abs(int(days)), 30)
|
||||||
years, months = divmod(abs(int(months)), 12)
|
years, months = divmod(abs(int(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))
|
total_weeks, _ = divmod(abs(int(total_days)), 7)
|
||||||
|
total_months, _ = divmod(abs(int(total_days)), 30)
|
||||||
|
|
||||||
|
days_years = total_days - 365 * years
|
||||||
|
days_weeks = total_days - 7 * total_weeks
|
||||||
|
days_months = total_days - 30 * total_months
|
||||||
|
weeks_months, _ = divmod(abs(int(total_days - 30 * total_months)), 7)
|
||||||
|
days_weeks_months = total_days - 30 * total_months - 7 * weeks_months
|
||||||
|
|
||||||
|
years, months, days, year_days, hours, minutes, seconds = map(int, (years, months, days, days_years, hours, minutes, seconds))
|
||||||
|
years, months, days, year_days, hours, minutes, seconds = map(abs, (years, months, days, year_days, hours, minutes, seconds))
|
||||||
return dict(
|
return dict(
|
||||||
seconds=seconds,
|
seconds=seconds,
|
||||||
minutes=minutes,
|
minutes=minutes,
|
||||||
hours=hours,
|
hours=hours,
|
||||||
days=days,
|
days=days,
|
||||||
|
weeks_months=weeks_months, # how many weeks in addition to "months"
|
||||||
|
days_years=days_years, # how many days in addition to "years"
|
||||||
|
days_months=days_months, # how many days in addition to "months"
|
||||||
|
days_weeks=days_weeks, # how many days in addition to "weeks"
|
||||||
|
days_weeks_months=days_weeks_months, # how many days in addition to "months" and "weeks"
|
||||||
months=months,
|
months=months,
|
||||||
years=years,
|
years=years,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def td_machine(remainders):
|
||||||
|
years, days_years, hours, minutes, seconds = map(lambda x: remainders[x],
|
||||||
|
["years", "days_years", "hours", "minutes", "seconds"])
|
||||||
|
return "{} years, {} days, {:02d}:{:02d}:{:02d}".format(years, days_years, hours, minutes, seconds)
|
||||||
|
|
||||||
|
|
||||||
|
def td_human(remainders):
|
||||||
|
rv = ""
|
||||||
|
for x in ["years", "months", "days", "hours", "minutes", "seconds"]:
|
||||||
|
period = remainders[x]
|
||||||
|
if period > 0:
|
||||||
|
rv += "{} {}, ".format(period, x[:-1] if period == 1 else x)
|
||||||
|
return rv[:-2]
|
||||||
|
|
||||||
|
|
||||||
|
def td_human_months_weeks(remainders):
|
||||||
|
rv = ""
|
||||||
|
for x in ["years", "months", "weeks_months", "days_weeks_months", "hours", "minutes", "seconds"]:
|
||||||
|
period = remainders[x]
|
||||||
|
if period > 0:
|
||||||
|
rv += "{} {}, ".format(period, x.split('_')[0][:-1] if period == 1 else x.split('_')[0])
|
||||||
|
return rv[:-2]
|
||||||
|
|
||||||
|
|
||||||
def td_totals(td):
|
def td_totals(td):
|
||||||
seconds = td.total_seconds()
|
seconds = td.total_seconds()
|
||||||
minutes = seconds / 60
|
minutes = seconds / 60
|
||||||
|
@ -3,7 +3,7 @@ import unittest
|
|||||||
|
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from tww import query_to_format_result, setup_logging_level
|
from tww.tokenizer import main, setup_logging_level
|
||||||
|
|
||||||
|
|
||||||
def get_local_hours_offset():
|
def get_local_hours_offset():
|
||||||
@ -22,7 +22,7 @@ UTC = -get_local_hours_offset()
|
|||||||
|
|
||||||
# LocalTimezone, Query, Result
|
# LocalTimezone, Query, Result
|
||||||
INTEGRATION_TESTS = [
|
INTEGRATION_TESTS = [
|
||||||
(UTC, "now", "2015-03-14 09:26:53"),
|
(UTC, "now", ["2015-03-14 09:26:53"]),
|
||||||
# in two hours -> 11:26 | to tokyo +9 -> 20:26
|
# in two hours -> 11:26 | to tokyo +9 -> 20:26
|
||||||
(0, "in two hours to asia/tokyo", "2015-03-14 20:26:53"),
|
(0, "in two hours to asia/tokyo", "2015-03-14 20:26:53"),
|
||||||
# now in UTC +2hrs -> 11:26
|
# now in UTC +2hrs -> 11:26
|
||||||
@ -38,12 +38,13 @@ class IntegrationTests(unittest.TestCase):
|
|||||||
for test in INTEGRATION_TESTS:
|
for test in INTEGRATION_TESTS:
|
||||||
local_tz = test[0]
|
local_tz = test[0]
|
||||||
query = test[1].split(" ")
|
query = test[1].split(" ")
|
||||||
|
args = type("false_args", (), {"query": query, "locale": None, "full": False, "handlers": False})
|
||||||
result = test[2]
|
result = test[2]
|
||||||
|
|
||||||
freezer = freeze_time(FROZEN_TIME, tz_offset=local_tz)
|
freezer = freeze_time(FROZEN_TIME, tz_offset=local_tz)
|
||||||
|
|
||||||
freezer.start()
|
freezer.start()
|
||||||
self.assertEqual(query_to_format_result(query), result)
|
self.assertEqual(main(args), result)
|
||||||
freezer.stop()
|
freezer.stop()
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ from scalpl import Cut
|
|||||||
|
|
||||||
from tww.localization import setlocale, resolve_locale
|
from tww.localization import setlocale, resolve_locale
|
||||||
from tww.lib import ISO_FORMAT, time_to_emoji, time_ago, workday_diff, workhours_diff, td_remainders, td_totals, \
|
from tww.lib import ISO_FORMAT, time_to_emoji, time_ago, workday_diff, workhours_diff, td_remainders, td_totals, \
|
||||||
td_iso8601, ISO_Z_FORMAT
|
td_iso8601, ISO_Z_FORMAT, td_human, td_machine, tzinfo_from_offset, td_human_months_weeks
|
||||||
from tww.lib import resolve_timezone, dateparser_parse_dt, get_utcnow, get_s_since_epoch, get_ms_since_epoch, \
|
from tww.lib import resolve_timezone, dateparser_parse_dt, get_utcnow, get_s_since_epoch, get_ms_since_epoch, \
|
||||||
dt_tz_translation, get_local_now, query_to_format_result
|
dt_tz_translation, get_local_now, query_to_format_result
|
||||||
from tww.common import logger
|
from tww.common import logger
|
||||||
@ -35,6 +35,8 @@ r_workhours_since = re.compile('(?:workhours|work hours)\s*since\s*(.*)', flags=
|
|||||||
r_workhours_until = re.compile('(?:workhours|work hours)\s*until\s*(.*)', flags=re.IGNORECASE)
|
r_workhours_until = re.compile('(?:workhours|work hours)\s*until\s*(.*)', flags=re.IGNORECASE)
|
||||||
r_workhours_between = re.compile('(?:workhours|work hours)\s*between\s*(.*)\s*and\s*(.*)', flags=re.IGNORECASE)
|
r_workhours_between = re.compile('(?:workhours|work hours)\s*between\s*(.*)\s*and\s*(.*)', flags=re.IGNORECASE)
|
||||||
r_timezone_translation = re.compile('(.*)?\s(?:in|to)\s(.*)', flags=re.IGNORECASE)
|
r_timezone_translation = re.compile('(.*)?\s(?:in|to)\s(.*)', flags=re.IGNORECASE)
|
||||||
|
r_timezone_translation_in_to = re.compile('(.*)(?:in)\s(.*)\s(?:to)\s(.*)', flags=re.IGNORECASE)
|
||||||
|
r_hour_minute_timezone = re.compile('((?:[0[0-9]|1[0-9]|2[0-3]):[0-5][0-9])?\s(.*)', flags=re.IGNORECASE)
|
||||||
r_timezone = re.compile('(.*)\s(?:timezone|timezones|tz)', flags=re.IGNORECASE)
|
r_timezone = re.compile('(.*)\s(?:timezone|timezones|tz)', flags=re.IGNORECASE)
|
||||||
r_timezone_2 = re.compile('(?:timezone in|timezones in|tz in|timezone|timezones|tz)\s(.*)?', flags=re.IGNORECASE)
|
r_timezone_2 = re.compile('(?:timezone in|timezones in|tz in|timezone|timezones|tz)\s(.*)?', flags=re.IGNORECASE)
|
||||||
|
|
||||||
@ -91,23 +93,45 @@ def handler_workhours_diff(start_dt, end_dt) -> dict:
|
|||||||
diff=td_pretty(diff))
|
diff=td_pretty(diff))
|
||||||
|
|
||||||
|
|
||||||
def handler_workhours_since_until(start_dt_s: str) -> dict:
|
def handler_workhours_since_until(start_dt_s: str):
|
||||||
return handler_workhours_diff(dateparser_parse_dt(start_dt_s), get_local_now())
|
return handler_workhours_diff(dateparser_parse_dt(start_dt_s), get_local_now())
|
||||||
|
|
||||||
|
|
||||||
def handler_timezone_translation(dt_s: str, timezone_like_s: str) -> dict:
|
def timezone_mangle(dt_s: str, timezone_like_s: str) -> dict:
|
||||||
|
logger.debug("Timezone translation between {} | {}".format(dt_s, timezone_like_s))
|
||||||
if dt_s.lower().strip() == "time":
|
if dt_s.lower().strip() == "time":
|
||||||
dt_s = "now"
|
dt_s = "now"
|
||||||
src_dt = dateparser_parse_dt(dt_s)
|
src_dt = dateparser_parse_dt(dt_s)
|
||||||
|
logger.debug("Source time: {}".format(src_dt))
|
||||||
tz = resolve_timezone(timezone_like_s)
|
tz = resolve_timezone(timezone_like_s)
|
||||||
|
logger.debug("Destination timezone: {}".format(tz))
|
||||||
if not tz:
|
if not tz:
|
||||||
tz, dst_dt = {}, src_dt
|
tz, dst_dt = {}, src_dt
|
||||||
else:
|
else:
|
||||||
offset = tz.get('tz_offset')
|
offset = tz.get('tz_offset')
|
||||||
|
return src_dt, offset, tz
|
||||||
|
|
||||||
|
|
||||||
|
def handler_timezone_creation(dt_s: str, timezone_like_s: str):
|
||||||
|
src_dt, offset, tz = timezone_mangle(dt_s, timezone_like_s)
|
||||||
|
tzinfo = tzinfo_from_offset(offset)
|
||||||
|
dst_dt = tzinfo[0].localize(src_dt.replace(tzinfo=None))
|
||||||
|
return src_dt, dst_dt, tz
|
||||||
|
|
||||||
|
|
||||||
|
def handler_timezone_translation(dt_s: str, timezone_like_s: str):
|
||||||
|
src_dt, offset, tz = timezone_mangle(dt_s, timezone_like_s)
|
||||||
dst_dt = dt_tz_translation(src_dt, offset)
|
dst_dt = dt_tz_translation(src_dt, offset)
|
||||||
return src_dt, dst_dt, tz
|
return src_dt, dst_dt, tz
|
||||||
|
|
||||||
|
|
||||||
|
def handler_timezone_translation_in_to(dt_s: str, timezone_like_s: str, timezone_like_d: str):
|
||||||
|
_, src_dt, _ = handler_timezone_creation(dt_s, timezone_like_s)
|
||||||
|
_, dst_offset, dst_tz = timezone_mangle(dt_s, timezone_like_d)
|
||||||
|
dst_dt = dt_tz_translation(src_dt, dst_offset)
|
||||||
|
return src_dt, dst_dt, dst_tz
|
||||||
|
|
||||||
|
|
||||||
def handler_generic_parser(dt_s: str) -> datetime:
|
def handler_generic_parser(dt_s: str) -> datetime:
|
||||||
return dateparser_parse_dt(dt_s)
|
return dateparser_parse_dt(dt_s)
|
||||||
|
|
||||||
@ -132,7 +156,7 @@ h_tz_offset = 'tz->tz_offset'
|
|||||||
h_time_in = 'dt->hh:mm'
|
h_time_in = 'dt->hh:mm'
|
||||||
h_translation = 'dt->iso8601_full'
|
h_translation = 'dt->iso8601_full'
|
||||||
h_default_dt = 'dt->iso8601_full'
|
h_default_dt = 'dt->iso8601_full'
|
||||||
h_default_td = 'timedelta->diff->duration_iso8601'
|
h_default_td = 'timedelta->diff->duration_human'
|
||||||
|
|
||||||
regex_handlers = [
|
regex_handlers = [
|
||||||
(r_time_in_epoch_s_now, handler_time_now_local, QUERY_TYPE_DT, h_unix_s),
|
(r_time_in_epoch_s_now, handler_time_now_local, QUERY_TYPE_DT, h_unix_s),
|
||||||
@ -144,6 +168,7 @@ regex_handlers = [
|
|||||||
(r_time_in_epoch_ms2, handler_time, QUERY_TYPE_DT, h_unix_ms),
|
(r_time_in_epoch_ms2, handler_time, QUERY_TYPE_DT, h_unix_ms),
|
||||||
(r_time_in_epoch_ms3, handler_time, QUERY_TYPE_DT, h_unix_ms),
|
(r_time_in_epoch_ms3, handler_time, QUERY_TYPE_DT, h_unix_ms),
|
||||||
(r_timezone_translation, handler_timezone_translation, QUERY_TYPE_DT_TR, h_translation),
|
(r_timezone_translation, handler_timezone_translation, QUERY_TYPE_DT_TR, h_translation),
|
||||||
|
(r_timezone_translation_in_to, handler_timezone_translation_in_to, QUERY_TYPE_DT_TR, h_translation),
|
||||||
(r_time_since, handler_time_since_until, QUERY_TYPE_TD, h_default_td),
|
(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_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_between, handler_time_diff, QUERY_TYPE_TD, h_default_td),
|
||||||
@ -156,6 +181,7 @@ regex_handlers = [
|
|||||||
(r_time_in, handler_time_in_parser, QUERY_TYPE_DT, h_time_in),
|
(r_time_in, handler_time_in_parser, QUERY_TYPE_DT, h_time_in),
|
||||||
(r_timezone, handler_timezone, QUERY_TYPE_TZ, h_tz_offset),
|
(r_timezone, handler_timezone, QUERY_TYPE_TZ, h_tz_offset),
|
||||||
(r_timezone_2, handler_timezone, QUERY_TYPE_TZ, h_tz_offset),
|
(r_timezone_2, handler_timezone, QUERY_TYPE_TZ, h_tz_offset),
|
||||||
|
(r_hour_minute_timezone, handler_timezone_creation, QUERY_TYPE_DT_TR, h_translation),
|
||||||
(r_generic, handler_generic_parser, QUERY_TYPE_DT, h_default_dt),
|
(r_generic, handler_generic_parser, QUERY_TYPE_DT, h_default_dt),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -173,13 +199,18 @@ def try_regex(r, s):
|
|||||||
def tokenize(s):
|
def tokenize(s):
|
||||||
solutions = []
|
solutions = []
|
||||||
for r, h, t, hi in regex_handlers:
|
for r, h, t, hi in regex_handlers:
|
||||||
|
logger.debug("Trying regex: {}".format(r))
|
||||||
g = try_regex(r, s)
|
g = try_regex(r, s)
|
||||||
if g is not None:
|
if g is not None:
|
||||||
try:
|
try:
|
||||||
|
logger.debug("Matched regex: {}".format(r))
|
||||||
|
logger.debug("Running handler: {} | query_type: {} | output_type: {}".format(h.__name__, t, hi))
|
||||||
result = h(*g)
|
result = h(*g)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
logger.debug("Exception from handler: {} -> {}".format(h.__name__, e))
|
||||||
continue
|
continue
|
||||||
if result is not None:
|
if result is not None:
|
||||||
|
logger.debug("Matched regex: {}".format(r))
|
||||||
solutions.append((h.__name__, result, t, hi))
|
solutions.append((h.__name__, result, t, hi))
|
||||||
return solutions
|
return solutions
|
||||||
|
|
||||||
@ -191,6 +222,7 @@ def pretty_print_dict(obj):
|
|||||||
|
|
||||||
|
|
||||||
def show_magic_results(obj, args):
|
def show_magic_results(obj, args):
|
||||||
|
rv = []
|
||||||
for solution in obj['solutions']:
|
for solution in obj['solutions']:
|
||||||
entry_proxy = Cut(solution, sep='->')
|
entry_proxy = Cut(solution, sep='->')
|
||||||
highlight_entry = solution["highlight"]
|
highlight_entry = solution["highlight"]
|
||||||
@ -199,10 +231,12 @@ def show_magic_results(obj, args):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
continue
|
continue
|
||||||
if args.handlers:
|
if args.handlers:
|
||||||
print("{} -> {}".format(solution['handler'], highlight_result))
|
to_print = "{} -> {}".format(solution['handler'], highlight_result)
|
||||||
else:
|
else:
|
||||||
print(highlight_result)
|
to_print = highlight_result
|
||||||
|
rv.append(to_print)
|
||||||
|
print(to_print)
|
||||||
|
return rv
|
||||||
|
|
||||||
def dt_pretty(dt):
|
def dt_pretty(dt):
|
||||||
rv = {}
|
rv = {}
|
||||||
@ -212,7 +246,6 @@ def dt_pretty(dt):
|
|||||||
from_tz_offset=dt.strftime('%z')).strftime(ISO_Z_FORMAT)
|
from_tz_offset=dt.strftime('%z')).strftime(ISO_Z_FORMAT)
|
||||||
rv["iso8601_date"] = dt.strftime('%Y-%m-%d')
|
rv["iso8601_date"] = dt.strftime('%Y-%m-%d')
|
||||||
rv["iso8601_time"] = dt.strftime('%H:%M:%S')
|
rv["iso8601_time"] = dt.strftime('%H:%M:%S')
|
||||||
rv["locale_dt"] = dt.strftime("%c")
|
|
||||||
rv["day_of_week_number"] = dt.strftime("%w")
|
rv["day_of_week_number"] = dt.strftime("%w")
|
||||||
rv["locale"] = custom_locale
|
rv["locale"] = custom_locale
|
||||||
with setlocale(locale.LC_TIME, custom_locale.get("lc_time")):
|
with setlocale(locale.LC_TIME, custom_locale.get("lc_time")):
|
||||||
@ -222,6 +255,7 @@ def dt_pretty(dt):
|
|||||||
rv["locale_day_of_week"] = dt.strftime("%A")
|
rv["locale_day_of_week"] = dt.strftime("%A")
|
||||||
rv["locale_date"] = dt.strftime("%x")
|
rv["locale_date"] = dt.strftime("%x")
|
||||||
rv["locale_time"] = dt.strftime("%X")
|
rv["locale_time"] = dt.strftime("%X")
|
||||||
|
rv["locale_dt"] = dt.strftime("%c")
|
||||||
rv["tz_offset"] = dt.strftime("%z")
|
rv["tz_offset"] = dt.strftime("%z")
|
||||||
rv["hh:mm"] = dt.strftime("%H:%M")
|
rv["hh:mm"] = dt.strftime("%H:%M")
|
||||||
rv["emoji_time"] = time_to_emoji(dt)
|
rv["emoji_time"] = time_to_emoji(dt)
|
||||||
@ -231,13 +265,17 @@ def dt_pretty(dt):
|
|||||||
|
|
||||||
|
|
||||||
def td_pretty(td):
|
def td_pretty(td):
|
||||||
|
remainders = td_remainders(td)
|
||||||
rv = {
|
rv = {
|
||||||
"sign": '-' if td.days > 0 else '+',
|
"sign": '-' if td.days > 0 else '+',
|
||||||
"in_the": 'future' if td.days < 0 else 'past',
|
"in_the": 'future' if td.days < 0 else 'past',
|
||||||
"time_ago": time_ago(td),
|
"time_ago": time_ago(td),
|
||||||
"duration_iso8601": td_iso8601(td),
|
"duration_iso8601": td_iso8601(td),
|
||||||
|
"duration_machine": td_machine(remainders),
|
||||||
|
"duration_human": td_human(remainders),
|
||||||
|
"duration_human_months_weeks": td_human_months_weeks(remainders),
|
||||||
"totals": td_totals(td),
|
"totals": td_totals(td),
|
||||||
"remainders": td_remainders(td),
|
"remainders": remainders,
|
||||||
}
|
}
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
@ -331,9 +369,11 @@ def setup_logging_level(debug=False):
|
|||||||
def main(args):
|
def main(args):
|
||||||
global custom_locale
|
global custom_locale
|
||||||
custom_locale = resolve_locale(args.locale)
|
custom_locale = resolve_locale(args.locale)
|
||||||
|
if custom_locale:
|
||||||
|
logger.debug("Locale understood as: {}".format(custom_locale))
|
||||||
query = ' '.join(args.query)
|
query = ' '.join(args.query)
|
||||||
# query = "tz in sofia"
|
|
||||||
result = resolve_query(query)
|
result = resolve_query(query)
|
||||||
if args.full:
|
if args.full:
|
||||||
pretty_print_dict(result)
|
pretty_print_dict(result)
|
||||||
show_magic_results(result, args)
|
return show_magic_results(result, args)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user