Ashish Prajapati
Ashish Prajapati

Reputation: 36

Input string recognise text and return date parse

I have a string input where text contains data as "monday of next month" or "4 days before new year" need to convert into dates as suppose today is 25/11/2020, so next month monday is on 07/12/2020, so how should i do it in python (i've tried using datetime, dateutil but didn't help')

next week saturday
4 days before new year
3 days after new year
second wednesday of next month

i need output as

05/12/20
28/12/20
03/01/21
09/12/21

tried reading docs but didn't help can anyone shed some light on it.

here's my python code.

from datetime import datetime, timedelta
from dateutil import parser
from dateparser.search import search_dates
# Create your views here.

def converter_view(request):
    form = DateStringForm()
    if request.method == 'POST':
        form = DateStringForm(request.POST)
        if form.is_valid():
            input_string = form.cleaned_data['string_date']
            list_of_dates = []
            if input_string.lower() == "today":
                data = datetime.now()
                list_of_dates.append(data.strftime('%d/%m/%Y'))
            elif input_string.lower() == "tomorrow":
                data = datetime.now() + timedelta(1)
                list_of_dates.append(data.strftime('%d/%m/%Y'))
            elif input_string.lower() == "yesterday":
                data = datetime.now() - timedelta(1)
                list_of_dates.append(data.strftime('%d/%m/%Y'))
            else:
                try:
                    # Using search_dates method we were extracting the keywords related to date, day or month
                    # So search_dates is going to return a "list of tuple" where 0th index is string and 1st is datetime
                    data = search_dates(input_string)
                except Exception as msg:
                    print('Exception :', msg)
                else:
                    try:
                        for i in data:
                            # So as we require to convert that date back in string format, we parse the extracted data in data
                            # where parser.parse() is taking 0th index which is string, and converting it to date and by using
                            # strftime function we get the required format
                            list_of_dates.append(parser.parse(i[0]).strftime('%d/%m/%Y'))
                            print(list_of_dates)
                    except TypeError as msg:
                        print("String does not contain any day or dates")
            values = DateStringConvert(string_date=input_string, date=list_of_dates)
            values.save()
            return HttpResponseRedirect('/dateconverter')
    return render(request, 'DateTimeConverter/index.html', {'form':form})

Upvotes: 0

Views: 177

Answers (1)

Gijs Wobben
Gijs Wobben

Reputation: 2060

It's impossible to facilitate all possible combinations and pieces of text. However, you can cover most cases with a few basic patterns.

import re
import datetime

queries = [
    "next week saturday",
    "4 days before new year",
    "3 days after new year",
    "second wednesday of next month",
]

def parse_relative_string_date(text: str, start_date: datetime.datetime = datetime.datetime.now()) -> datetime.datetime:

    def _next_week(weekday: str):
        weekdays = {
            "monday": 0,
            "tuesday": 1,
            "wednesday": 2,
            "thursday": 3,
            "friday": 4,
            "saturday": 5,
            "sunday": 6,
        }
        next_week = start_date + datetime.timedelta(weeks=1)
        return next_week + datetime.timedelta((weekdays[weekday.lower()] - next_week.weekday()) % 7)

    def _new_year(n_days: str, direction: str):
        new_years = datetime.datetime(year=start_date.year + 1, month=1, day=1)
        directions = {
            "before": -1,
            "after": 1,
        }
        return new_years + datetime.timedelta(directions[direction.lower()] * int(n_days))

    patterns = {
        r"next week (?P<weekday>\w+)": _next_week,
        r"(?P<n_days>\d+) days (?P<direction>\w+) new year": _new_year,
        # Add more patterns here
    }

    for pattern, callback in patterns.items():
        found = re.search(pattern, text)
        if found is not None:
            return callback(**dict(found.groupdict()))


for query in queries:
    print(parse_relative_string_date(query))

Upvotes: 1

Related Questions