calendar printing

This commit is contained in:
Daniel Tsvetkov 2021-05-13 14:39:49 +02:00
parent b897831827
commit 9523ad480f
3 changed files with 60 additions and 12 deletions

View File

@ -28,6 +28,8 @@ python tww QUERY [--debug] [--full] [--show=<param>]
- `time between 2012-03-14 and 2012-04-26`
- `time since 09:00`
- `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>`
- `12-12-2019 + 2 weeks`
- `05:23 - 150 minutes`
@ -44,6 +46,9 @@ python tww QUERY [--debug] [--full] [--show=<param>]
- `2021-05-10 day of week`
- Find timezones
- `timezone in Brazil`
- Print calendar `cal(endar) (month) <dt-like>` or `cal year <dt-like>` (for whole year)
- `cal year 2021`
- `calendar january 2018`

View File

@ -290,6 +290,7 @@ def find_from_offset(query):
def resolve_timezone(query, dt=None):
if not query:
query = "utc"
dt = dt or datetime.now()
# if the human_tz_loc contains /, assume it's a timezone which could be
# incorrectly written with small letters - need Continent/City
normal_query = query.lower().strip()
@ -301,6 +302,7 @@ def resolve_timezone(query, dt=None):
"normal_query": normal_query,
"tz_offset": local_offset,
"tz_name": local_iana,
'is_local': True,
}
found_from_iana_tz = NORMALIZED_TZ_DICT.get(normal_query, "")
found_from_abbr_tzs = list(NORMALIZED_TZ_ABBR.get(normal_query, set()))
@ -343,10 +345,11 @@ def resolve_timezone(query, dt=None):
except UnknownTimeZoneError:
pytz_result = type('pytz', (), {"zone": ""})
tz_name = pytz_result.zone
tz_dst_seconds = pytz_result.dst(dt.replace(tzinfo=None) or datetime.now()).seconds
pytz_localized = pytz_result.localize(dt.replace(tzinfo=None) or datetime.now())
tz_dst_seconds = pytz_result.dst(dt.replace(tzinfo=None)).seconds
pytz_localized = pytz_result.localize(dt.replace(tzinfo=None))
tz_abbr = 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 {
"query": query,
"normal_query": normal_query,
@ -361,8 +364,10 @@ def resolve_timezone(query, dt=None):
"tz_name": tz_name,
"tz_abbr": tz_abbr,
"tz_offset": tz_offset,
"tz_offset_seconds": tz_offset_seconds,
"tz_dst_seconds": tz_dst_seconds,
"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)
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:
to_shh, to_mm = split_offset(to_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():
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())
if now.tzinfo._isdst(now):
return format_offset_from_timedelta(now.tzinfo._dst_offset)

View File

@ -3,7 +3,8 @@ import json
import locale
import re
import logging
from datetime import datetime
from datetime import datetime, timedelta
import calendar
from pygments import highlight, lexers, formatters
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
custom_locale = resolve_locale()
custom_tz = None
r_generic = re.compile('(.*)', 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_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_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_minus = re.compile('(.*)\s*(?:minus|\-)\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_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_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)
def handler_time(dt_s):
return dateparser_parse_dt(dt_s)
def handler_time_now_local():
return get_local_now()
@ -68,6 +69,15 @@ def dt_normalize(start_dt, end_dt) -> (datetime, datetime):
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:
start_dt, end_dt = dt_normalize(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
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 = "datetime_details"
QUERY_TYPE_TZ = "timezone"
QUERY_TYPE_TD = "timedelta"
QUERY_TYPE_CAL = "calendar"
h_default = ''
h_unix_s = 'dt->unix_s'
@ -196,21 +215,24 @@ 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'
h_cal_year = 'cal->year'
h_cal_month = 'cal->month'
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_utc, QUERY_TYPE_DT, h_unix_s),
(r_time_in_epoch_s2, handler_time, QUERY_TYPE_DT, h_unix_s),
(r_time_in_epoch_s3, 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_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_utc, 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_ms2, handler_generic_parser, 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_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_until, handler_time_since_until, 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_minus, handler_time_minus, 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_2, handler_timezone, QUERY_TYPE_TZ, h_tz_offset),
(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),
]
@ -351,7 +375,7 @@ def resolve_query(query, allowed_queries=None):
}
solutions = resolve_query_type(query)
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):
element = {}
handler, results, query_type, hi = solution
@ -372,6 +396,8 @@ def resolve_query(query, allowed_queries=None):
element["tz"] = results
elif query_type == QUERY_TYPE_TD:
element["timedelta"] = results
elif query_type == QUERY_TYPE_CAL:
element["cal"] = results
rv["solutions"].append(element)
except Exception as e:
continue
@ -409,6 +435,7 @@ def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('query', nargs='*', default="", help="freeform")
parser.add_argument('--locale', dest='locale')
parser.add_argument('--tz', dest='tz', default='local')
parser.add_argument('--handlers', dest='handlers')
parser.add_argument('--show', dest='show')
parser.add_argument('--full', dest='full', action='store_true')
@ -425,7 +452,9 @@ def setup_logging_level(debug=False):
def main(args):
global custom_locale
global custom_tz
custom_locale = resolve_locale(args.locale)
custom_tz = resolve_timezone(args.tz)
if custom_locale:
logger.debug("Locale understood as: {}".format(custom_locale))
query = ' '.join(args.query)