From 9294d62daa83802db14ec8a73c23289b571f5c09 Mon Sep 17 00:00:00 2001 From: David Barnett Date: Tue, 1 Oct 2024 17:20:31 -0600 Subject: [PATCH] Adjust "when" value parsing to handle YYYY-MM-DD consistently ISO-8601-like date formats shouldn't depend on system locale by default, only localized formats like DD-MM-YYYY or MM-DD-YYYY. --- gcalcli/cli.py | 5 ++--- gcalcli/utils.py | 9 +++++++-- gcalcli/validators.py | 15 +++++---------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/gcalcli/cli.py b/gcalcli/cli.py index 64be0b1..6e803eb 100755 --- a/gcalcli/cli.py +++ b/gcalcli/cli.py @@ -38,8 +38,8 @@ from .gcal import GoogleCalendarInterface from .printer import Printer, valid_color_name from .validators import ( - get_date_input_description, get_input, + DATE_INPUT_DESCRIPTION, PARSABLE_DATE, PARSABLE_DURATION, REMINDER, @@ -116,12 +116,11 @@ def run_add_prompt(parsed_args, printer): if parsed_args.where is None: parsed_args.where = get_input(printer, 'Location: ', STR_ALLOW_EMPTY) if parsed_args.when is None: - date_format_desc = get_date_input_description() parsed_args.when = get_input( printer, 'When (? for help): ', PARSABLE_DATE, - help=f'Expected format: {date_format_desc}', + help=f'Expected format: {DATE_INPUT_DESCRIPTION}', ) if parsed_args.duration is None and parsed_args.end is None: if parsed_args.allday: diff --git a/gcalcli/utils.py b/gcalcli/utils.py index 37602fa..04ccab9 100644 --- a/gcalcli/utils.py +++ b/gcalcli/utils.py @@ -93,7 +93,7 @@ def get_times_from_duration( return start.isoformat(), stop.isoformat() -def is_dayfirst_locale(): +def _is_dayfirst_locale(): """Detect whether system locale date format has day first. Examples: @@ -121,9 +121,14 @@ def get_time_from_str(when): hour=0, minute=0, second=0, microsecond=0 ) + # Only apply dayfirst=True if date actually starts with "XX-XX-". + # Other forms like YYYY-MM-DD shouldn't rely on locale by default (#792). + dayfirst = ( + _is_dayfirst_locale() if re.match(r'^\d{1,2}-\d{1,2}-', when) else None + ) try: event_time = dateutil_parse( - when, default=zero_oclock_today, dayfirst=is_dayfirst_locale() + when, default=zero_oclock_today, dayfirst=dayfirst ) except ValueError: struct, result = fuzzy_date_parse(when) diff --git a/gcalcli/validators.py b/gcalcli/validators.py index 95a7187..fc855dd 100644 --- a/gcalcli/validators.py +++ b/gcalcli/validators.py @@ -6,7 +6,6 @@ get_time_from_str, get_timedelta_from_str, REMINDER_REGEX, - is_dayfirst_locale, ) # TODO: in the future, pull these from the API @@ -15,6 +14,10 @@ 'banana', 'tangerine', 'peacock', 'graphite', 'blueberry', 'basil', 'tomato'] +DATE_INPUT_DESCRIPTION = '\ +a date (e.g. 2019-12-31, tomorrow 10am, 2nd Jan, Jan 4th, etc) or valid time \ +if today' + def get_override_color_id(color): return str(VALID_OVERRIDE_COLORS.index(color) + 1) @@ -68,13 +71,6 @@ def str_to_int_validator(input_str): ) -def get_date_input_description(): - dayfirst = is_dayfirst_locale() - sample_date = '2019-31-12' if dayfirst else '2019-12-31' - return f'a date (e.g. {sample_date}, tomorrow 10am, 2nd Jan, Jan 4th, etc) \ -or valid time if today' - - def parsable_date_validator(input_str): """ A filter allowing any string which can be parsed @@ -85,9 +81,8 @@ def parsable_date_validator(input_str): get_time_from_str(input_str) return input_str except ValueError: - format_desc = get_date_input_description() raise ValidationError( - f'Expected format: {format_desc}. ' + f'Expected format: {DATE_INPUT_DESCRIPTION}. ' '(Ctrl-C to exit)\n' )