calendar printing
This commit is contained in:
parent
b897831827
commit
9523ad480f
@ -28,6 +28,8 @@ python tww QUERY [--debug] [--full] [--show=<param>]
|
|||||||
- `time between 2012-03-14 and 2012-04-26`
|
- `time between 2012-03-14 and 2012-04-26`
|
||||||
- `time since 09:00`
|
- `time since 09:00`
|
||||||
- `time until end of workday`
|
- `time until end of workday`
|
||||||
|
- Timezone difference: `timezone difference between <tz-like> and <tz-like>` or `tz diff between <tz-like> and <tz-like>`
|
||||||
|
- `timezone difference between sofia and portugal`
|
||||||
- Calculate time differences: `<dt-like> (?\+|\-|plus|minus) <timedelta>` or `<timedelta> (before|from) <dt>`
|
- Calculate time differences: `<dt-like> (?\+|\-|plus|minus) <timedelta>` or `<timedelta> (before|from) <dt>`
|
||||||
- `12-12-2019 + 2 weeks`
|
- `12-12-2019 + 2 weeks`
|
||||||
- `05:23 - 150 minutes`
|
- `05:23 - 150 minutes`
|
||||||
@ -44,6 +46,9 @@ python tww QUERY [--debug] [--full] [--show=<param>]
|
|||||||
- `2021-05-10 day of week`
|
- `2021-05-10 day of week`
|
||||||
- Find timezones
|
- Find timezones
|
||||||
- `timezone in Brazil`
|
- `timezone in Brazil`
|
||||||
|
- Print calendar `cal(endar) (month) <dt-like>` or `cal year <dt-like>` (for whole year)
|
||||||
|
- `cal year 2021`
|
||||||
|
- `calendar january 2018`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
18
tww/lib.py
18
tww/lib.py
@ -290,6 +290,7 @@ def find_from_offset(query):
|
|||||||
def resolve_timezone(query, dt=None):
|
def resolve_timezone(query, dt=None):
|
||||||
if not query:
|
if not query:
|
||||||
query = "utc"
|
query = "utc"
|
||||||
|
dt = dt or datetime.now()
|
||||||
# if the human_tz_loc contains /, assume it's a timezone which could be
|
# if the human_tz_loc contains /, assume it's a timezone which could be
|
||||||
# incorrectly written with small letters - need Continent/City
|
# incorrectly written with small letters - need Continent/City
|
||||||
normal_query = query.lower().strip()
|
normal_query = query.lower().strip()
|
||||||
@ -301,6 +302,7 @@ def resolve_timezone(query, dt=None):
|
|||||||
"normal_query": normal_query,
|
"normal_query": normal_query,
|
||||||
"tz_offset": local_offset,
|
"tz_offset": local_offset,
|
||||||
"tz_name": local_iana,
|
"tz_name": local_iana,
|
||||||
|
'is_local': True,
|
||||||
}
|
}
|
||||||
found_from_iana_tz = NORMALIZED_TZ_DICT.get(normal_query, "")
|
found_from_iana_tz = NORMALIZED_TZ_DICT.get(normal_query, "")
|
||||||
found_from_abbr_tzs = list(NORMALIZED_TZ_ABBR.get(normal_query, set()))
|
found_from_abbr_tzs = list(NORMALIZED_TZ_ABBR.get(normal_query, set()))
|
||||||
@ -343,10 +345,11 @@ def resolve_timezone(query, dt=None):
|
|||||||
except UnknownTimeZoneError:
|
except UnknownTimeZoneError:
|
||||||
pytz_result = type('pytz', (), {"zone": ""})
|
pytz_result = type('pytz', (), {"zone": ""})
|
||||||
tz_name = pytz_result.zone
|
tz_name = pytz_result.zone
|
||||||
tz_dst_seconds = pytz_result.dst(dt.replace(tzinfo=None) or datetime.now()).seconds
|
tz_dst_seconds = pytz_result.dst(dt.replace(tzinfo=None)).seconds
|
||||||
pytz_localized = pytz_result.localize(dt.replace(tzinfo=None) or datetime.now())
|
pytz_localized = pytz_result.localize(dt.replace(tzinfo=None))
|
||||||
tz_abbr = pytz_localized.strftime('%Z') if tz_name else ""
|
tz_abbr = pytz_localized.strftime('%Z') if tz_name else ""
|
||||||
tz_offset = pytz_localized.strftime('%z') if tz_name else ""
|
tz_offset = pytz_localized.strftime('%z') if tz_name else ""
|
||||||
|
tz_offset_seconds = offset_to_seconds(tz_offset)
|
||||||
return {
|
return {
|
||||||
"query": query,
|
"query": query,
|
||||||
"normal_query": normal_query,
|
"normal_query": normal_query,
|
||||||
@ -361,8 +364,10 @@ def resolve_timezone(query, dt=None):
|
|||||||
"tz_name": tz_name,
|
"tz_name": tz_name,
|
||||||
"tz_abbr": tz_abbr,
|
"tz_abbr": tz_abbr,
|
||||||
"tz_offset": tz_offset,
|
"tz_offset": tz_offset,
|
||||||
|
"tz_offset_seconds": tz_offset_seconds,
|
||||||
"tz_dst_seconds": tz_dst_seconds,
|
"tz_dst_seconds": tz_dst_seconds,
|
||||||
"tz_is_dst": tz_dst_seconds != 0,
|
"tz_is_dst": tz_dst_seconds != 0,
|
||||||
|
"is_local": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -623,6 +628,11 @@ def split_offset(offset):
|
|||||||
return int(to_shh), int(to_mm)
|
return int(to_shh), int(to_mm)
|
||||||
|
|
||||||
|
|
||||||
|
def offset_to_seconds(offset):
|
||||||
|
h, m = split_offset(offset)
|
||||||
|
return h * 3600 + m * 60
|
||||||
|
|
||||||
|
|
||||||
def dt_tz_translation(dt: datetime, to_tz_offset: str, from_tz_offset: str = "+00:00") -> datetime:
|
def dt_tz_translation(dt: datetime, to_tz_offset: str, from_tz_offset: str = "+00:00") -> datetime:
|
||||||
to_shh, to_mm = split_offset(to_tz_offset)
|
to_shh, to_mm = split_offset(to_tz_offset)
|
||||||
from_shh, from_mm = split_offset(from_tz_offset)
|
from_shh, from_mm = split_offset(from_tz_offset)
|
||||||
@ -647,6 +657,10 @@ def get_local_tzname_iana():
|
|||||||
|
|
||||||
|
|
||||||
def get_local_tz_offset():
|
def get_local_tz_offset():
|
||||||
|
from tww.tokenizer import custom_tz
|
||||||
|
global custom_tz
|
||||||
|
if custom_tz and not custom_tz.get('is_local'):
|
||||||
|
return custom_tz.get('tz_offset')
|
||||||
now = datetime.now(tzlocal())
|
now = datetime.now(tzlocal())
|
||||||
if now.tzinfo._isdst(now):
|
if now.tzinfo._isdst(now):
|
||||||
return format_offset_from_timedelta(now.tzinfo._dst_offset)
|
return format_offset_from_timedelta(now.tzinfo._dst_offset)
|
||||||
|
@ -3,7 +3,8 @@ import json
|
|||||||
import locale
|
import locale
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
|
import calendar
|
||||||
|
|
||||||
from pygments import highlight, lexers, formatters
|
from pygments import highlight, lexers, formatters
|
||||||
from scalpl import Cut
|
from scalpl import Cut
|
||||||
@ -16,6 +17,7 @@ from tww.lib import resolve_timezone, dateparser_parse_dt, get_utcnow, get_s_sin
|
|||||||
from tww.common import logger
|
from tww.common import logger
|
||||||
|
|
||||||
custom_locale = resolve_locale()
|
custom_locale = resolve_locale()
|
||||||
|
custom_tz = None
|
||||||
|
|
||||||
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)
|
||||||
@ -28,6 +30,7 @@ r_time_in = re.compile('(?:time)?\s*in\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_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_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_between = re.compile('(?:time|year|month|week|day|hour|minute|second)?(?:s)?\s*between\s*(.*)\s*and\s*(.*)', flags=re.IGNORECASE)
|
||||||
|
r_tz_between = re.compile('(?:time difference|tz diff|time diff|time zone difference|timezone difference|timezone diff|time zone diff)?(?: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_plus = re.compile('(.*)\s*(?:plus|\+|after|from)\s*(.*)', flags=re.IGNORECASE)
|
||||||
r_time_minus = re.compile('(.*)\s*(?:minus|\-)\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_time_before = re.compile('(.*)\s*(?:before|\-)\s*(.*)', flags=re.IGNORECASE)
|
||||||
@ -43,13 +46,11 @@ r_timezone_translation = re.compile('(.*)?\s(?:in|to)\s(.*)', flags=re.IGNORECAS
|
|||||||
r_timezone_translation_in_to = re.compile('(.*)(?:in)\s(.*)\s(?: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_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_calendar_year = re.compile('(?:cal year|calendar year)?\s*(.*)', flags=re.IGNORECASE)
|
||||||
|
r_calendar_month = re.compile('(?:calendar|cal|month|cal month|calendar month)?\s*(.*)', 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)
|
||||||
|
|
||||||
|
|
||||||
def handler_time(dt_s):
|
|
||||||
return dateparser_parse_dt(dt_s)
|
|
||||||
|
|
||||||
|
|
||||||
def handler_time_now_local():
|
def handler_time_now_local():
|
||||||
return get_local_now()
|
return get_local_now()
|
||||||
|
|
||||||
@ -68,6 +69,15 @@ def dt_normalize(start_dt, end_dt) -> (datetime, datetime):
|
|||||||
return start_dt, end_dt
|
return start_dt, end_dt
|
||||||
|
|
||||||
|
|
||||||
|
def handler_tz_diff(start_tz_s: str, end_tz_s: str) -> dict:
|
||||||
|
start_tz = resolve_timezone(start_tz_s)
|
||||||
|
end_tz = resolve_timezone(end_tz_s)
|
||||||
|
diff = timedelta(seconds=start_tz["tz_offset_seconds"] - end_tz["tz_offset_seconds"])
|
||||||
|
return dict(start=start_tz,
|
||||||
|
end=end_tz,
|
||||||
|
diff=td_pretty(diff))
|
||||||
|
|
||||||
|
|
||||||
def handler_time_diff(start_dt, end_dt) -> dict:
|
def handler_time_diff(start_dt, end_dt) -> dict:
|
||||||
start_dt, end_dt = dt_normalize(start_dt, end_dt)
|
start_dt, end_dt = dt_normalize(start_dt, end_dt)
|
||||||
diff = start_dt - end_dt
|
diff = start_dt - end_dt
|
||||||
@ -182,10 +192,19 @@ def handler_time_before(td: str, dt_s: str):
|
|||||||
return dt - td
|
return dt - td
|
||||||
|
|
||||||
|
|
||||||
|
def handler_calendar(dt_s: str):
|
||||||
|
dt = dateparser_parse_dt(dt_s)
|
||||||
|
return {
|
||||||
|
"month": calendar.month(int(dt.strftime("%Y")), int(dt.strftime("%m"))),
|
||||||
|
"year": calendar.calendar(int(dt.strftime("%Y"))),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QUERY_TYPE_DT_TR = "datetime_translation"
|
QUERY_TYPE_DT_TR = "datetime_translation"
|
||||||
QUERY_TYPE_DT = "datetime_details"
|
QUERY_TYPE_DT = "datetime_details"
|
||||||
QUERY_TYPE_TZ = "timezone"
|
QUERY_TYPE_TZ = "timezone"
|
||||||
QUERY_TYPE_TD = "timedelta"
|
QUERY_TYPE_TD = "timedelta"
|
||||||
|
QUERY_TYPE_CAL = "calendar"
|
||||||
|
|
||||||
h_default = ''
|
h_default = ''
|
||||||
h_unix_s = 'dt->unix_s'
|
h_unix_s = 'dt->unix_s'
|
||||||
@ -196,21 +215,24 @@ h_translation = 'dt->iso8601_full'
|
|||||||
h_default_dt = 'dt->iso8601_full'
|
h_default_dt = 'dt->iso8601_full'
|
||||||
h_default_td = 'timedelta->diff->duration_human'
|
h_default_td = 'timedelta->diff->duration_human'
|
||||||
h_day_of_week = 'dt->locale_day_of_week'
|
h_day_of_week = 'dt->locale_day_of_week'
|
||||||
|
h_cal_year = 'cal->year'
|
||||||
|
h_cal_month = 'cal->month'
|
||||||
|
|
||||||
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),
|
||||||
(r_time_in_epoch_s_now, handler_time_now_utc, QUERY_TYPE_DT, h_unix_s),
|
(r_time_in_epoch_s_now, handler_time_now_utc, QUERY_TYPE_DT, h_unix_s),
|
||||||
(r_time_in_epoch_s2, handler_time, QUERY_TYPE_DT, h_unix_s),
|
(r_time_in_epoch_s2, handler_generic_parser, QUERY_TYPE_DT, h_unix_s),
|
||||||
(r_time_in_epoch_s3, handler_time, QUERY_TYPE_DT, h_unix_s),
|
(r_time_in_epoch_s3, handler_generic_parser, QUERY_TYPE_DT, h_unix_s),
|
||||||
(r_time_in_epoch_ms_now, handler_time_now_local, QUERY_TYPE_DT, h_unix_ms),
|
(r_time_in_epoch_ms_now, handler_time_now_local, QUERY_TYPE_DT, h_unix_ms),
|
||||||
(r_time_in_epoch_ms_now, handler_time_now_utc, QUERY_TYPE_DT, h_unix_ms),
|
(r_time_in_epoch_ms_now, handler_time_now_utc, QUERY_TYPE_DT, h_unix_ms),
|
||||||
(r_time_in_epoch_ms2, handler_time, QUERY_TYPE_DT, h_unix_ms),
|
(r_time_in_epoch_ms2, handler_generic_parser, 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_generic_parser, 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_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),
|
||||||
|
(r_tz_between, handler_tz_diff, QUERY_TYPE_TD, h_default_td),
|
||||||
(r_time_plus, handler_time_plus, QUERY_TYPE_DT, h_default_dt),
|
(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_minus, handler_time_minus, QUERY_TYPE_DT, h_default_dt),
|
||||||
(r_time_before, handler_time_before, QUERY_TYPE_DT, h_default_dt),
|
(r_time_before, handler_time_before, QUERY_TYPE_DT, h_default_dt),
|
||||||
@ -226,6 +248,8 @@ regex_handlers = [
|
|||||||
(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_hour_minute_timezone, handler_timezone_creation, QUERY_TYPE_DT_TR, h_translation),
|
||||||
|
(r_calendar_year, handler_calendar, QUERY_TYPE_CAL, h_cal_year),
|
||||||
|
(r_calendar_month, handler_calendar, QUERY_TYPE_CAL, h_cal_month),
|
||||||
(r_generic, handler_generic_parser, QUERY_TYPE_DT, h_default_dt),
|
(r_generic, handler_generic_parser, QUERY_TYPE_DT, h_default_dt),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -351,7 +375,7 @@ def resolve_query(query, allowed_queries=None):
|
|||||||
}
|
}
|
||||||
solutions = resolve_query_type(query)
|
solutions = resolve_query_type(query)
|
||||||
if not allowed_queries:
|
if not allowed_queries:
|
||||||
allowed_queries = [QUERY_TYPE_DT, QUERY_TYPE_DT_TR, QUERY_TYPE_TD, QUERY_TYPE_TZ]
|
allowed_queries = [QUERY_TYPE_DT, QUERY_TYPE_DT_TR, QUERY_TYPE_TD, QUERY_TYPE_TZ, QUERY_TYPE_CAL]
|
||||||
for sol_id, solution in enumerate(solutions):
|
for sol_id, solution in enumerate(solutions):
|
||||||
element = {}
|
element = {}
|
||||||
handler, results, query_type, hi = solution
|
handler, results, query_type, hi = solution
|
||||||
@ -372,6 +396,8 @@ def resolve_query(query, allowed_queries=None):
|
|||||||
element["tz"] = results
|
element["tz"] = results
|
||||||
elif query_type == QUERY_TYPE_TD:
|
elif query_type == QUERY_TYPE_TD:
|
||||||
element["timedelta"] = results
|
element["timedelta"] = results
|
||||||
|
elif query_type == QUERY_TYPE_CAL:
|
||||||
|
element["cal"] = results
|
||||||
rv["solutions"].append(element)
|
rv["solutions"].append(element)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
continue
|
continue
|
||||||
@ -409,6 +435,7 @@ def parse_args():
|
|||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('query', nargs='*', default="", help="freeform")
|
parser.add_argument('query', nargs='*', default="", help="freeform")
|
||||||
parser.add_argument('--locale', dest='locale')
|
parser.add_argument('--locale', dest='locale')
|
||||||
|
parser.add_argument('--tz', dest='tz', default='local')
|
||||||
parser.add_argument('--handlers', dest='handlers')
|
parser.add_argument('--handlers', dest='handlers')
|
||||||
parser.add_argument('--show', dest='show')
|
parser.add_argument('--show', dest='show')
|
||||||
parser.add_argument('--full', dest='full', action='store_true')
|
parser.add_argument('--full', dest='full', action='store_true')
|
||||||
@ -425,7 +452,9 @@ def setup_logging_level(debug=False):
|
|||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
global custom_locale
|
global custom_locale
|
||||||
|
global custom_tz
|
||||||
custom_locale = resolve_locale(args.locale)
|
custom_locale = resolve_locale(args.locale)
|
||||||
|
custom_tz = resolve_timezone(args.tz)
|
||||||
if custom_locale:
|
if custom_locale:
|
||||||
logger.debug("Locale understood as: {}".format(custom_locale))
|
logger.debug("Locale understood as: {}".format(custom_locale))
|
||||||
query = ' '.join(args.query)
|
query = ' '.join(args.query)
|
||||||
|
Loading…
Reference in New Issue
Block a user