How to operate with dates that dont have a 4-digit year? Is it possible extract this year number and adapt it so that datetime can operate with this?

Question:

I was having a ValueError every time I tried to pass a date whose years are not 4 digits to some function of the datetime module, in this case the operation to be performed is to add or subtract days

import datetime

def add_or_subtract_days(datestr, days, operation):
    if operation == "add" : input_text = (datetime.datetime.strptime(datestr, "%Y-%m-%d") + datetime.timedelta(days=int(days))).strftime('%Y-%m-%d')
    elif operation == "subtract" : input_text = (datetime.datetime.strptime(datestr, "%Y-%m-%d") - datetime.timedelta(days=int(days))).strftime('%Y-%m-%d')

    return input_text


input_text = add_or_subtract_days("2023-01-20", "5", "add")
print(repr(input_text))  # ---> '2023-01-25'

input_text = add_or_subtract_days("999-12-27", "5", "add")
print(repr(input_text))  # ---> ValueError: time data '999-12-27' does not match format '%Y-%m-%d'

input_text = add_or_subtract_days("12023-01-20", "5", "add")
print(repr(input_text))  # ---> ValueError: time data '12023-01-20' does not match format '%Y-%m-%d'

Something that occurred to me is to identify these problem cases with an exception, and I managed to extract the number of years. Perhaps it will help me to operate with it in some way, so that it does not generate problems when adding or subtracting days with datetime. You also have to take into account that when adding or subtracting days, you can also change the number of the month and the number of the year, which is a very important factor to consider and is giving me a lot of problems since I don’t have much idea how to solve it.

import datetime, re

def add_or_subtract_days(datestr, days, operation):

    try:
        if operation == "add" : input_text = (datetime.datetime.strptime(datestr, "%Y-%m-%d") + datetime.timedelta(days=int(days))).strftime('%Y-%m-%d')
        elif operation == "subtract" : input_text = (datetime.datetime.strptime(datestr, "%Y-%m-%d") - datetime.timedelta(days=int(days))).strftime('%Y-%m-%d')

    except ValueError:
        m1 = re.search( r"(?P<year>d*)-(?P<month>d{2})-(?P<startDay>d{2})", datestr, re.IGNORECASE, )
        if m1:
            ref_year = str(m1.groups()[0])
            print(ref_year)

    return input_text

I’ve already managed to extract the year number, however I can’t think of what kind of algorithm I should use to truncate the year to a value with the amount that supports the datetime and then join it (keeping logic) to get the correct date though does not have a 4-digit year

for example…

"212023-12-30" + 2 days –> 21 2023-12-30 + 2 days –> 21 2024-01-01 –> 212024-01-01

"12023-12-30" + 2 days –> 1 2023-12-30 + 2 days –> 1 2024-01-01 –> 12024-01-01

"999-12-30" + 2 days –> 0 999-12-30 + 2 days –> 0 1000-01-01 –> 1000-01-01

"999-11-30" + 5 days –> 0 999-11-30 + 5 days –> 0 999-11-05 –> 999-11-05

"99-12-31" + 5 days –> 00 99-12-31 + 5 days –> 00 100-01-05 –> 100-01-05

Answers:

Having a ’99’ as a year is problematic since Python wont know what date you actually want (2099 or 1999 or 3099 etc).

The %Y is telling python that you want to parse a date that is 4 characters. you can use %y for just 2:

>>> datetime.datetime.strptime('99-12-29', '%y-%m-%d')
datetime.datetime(1999, 12, 29, 0, 0)
>>>

if you want the year 0099 then you need 4 characters:

>>> datetime.datetime.strptime('0099-12-29', '%Y-%m-%d')
datetime.datetime(99, 12, 29, 0, 0)
>>>

From Comments:
Its easier to take all the dates and move them to 4 characters and then parse the time:

def add_or_subtract_days(datestr, days, operation):
    to_add = 4 - len(datestr[:datestr.find('-')])
    datestr = ('0' * to_add) + datestr

    if operation == "add":
        input_text = (datetime.datetime.strptime(datestr, "%Y-%m-%d") + datetime.timedelta(days=int(days))).strftime('%Y-%m-%d')
    elif operation == "subtract":
        input_text = (datetime.datetime.strptime(datestr, "%Y-%m-%d") - datetime.timedelta(days=int(days))).strftime('%Y-%m-%d')

    return input_text

first two lines we calculate how many 0 we need to add to the start of the date. second line is a little known python hackery where we can multiply a string with an int to get a string of repeating characters of n. This obviously doesnt work for dates that are larger than 9999 since python MAXYEAR is 9999.

input_text = add_or_subtract_days("2023-01-20", "5", "add")
print(repr(input_text))  # ---> '2023-01-25'

input_text = add_or_subtract_days("999-12-27", "5", "add")
print(repr(input_text))  # ---> '1000-01-01'

input_text = add_or_subtract_days("99-01-20", "5", "add")
print(repr(input_text))  # ---> '0099-01-25'
Answered By: testfile