datealexa-skills-kitalexa-slot

Custom handling for AMAZON.DATE slot type to find Past Dates only


The Problem

I know in the docs that AMAZON.DATE slot type defaults to look for future dates. As far as I can see there's no way for me to set it to past dates by default.

If that's the case, what can I do within my code to handle this?

Example

A simpler version of my case: fetch news articles from a specific day. With today's date (2021-11-14) a user says the following:

User Input Intended Date input_date diff = (input_date- today).days Handling
Get me news articles from last Wednesday 2021-11-10 2021-11-10 -4 Accept as-is
Get me news articles from November 10th 2021 2021-11-10 2021-11-10 -4 Accept as-is
Get me Wednesday's news 2021-11-10 2021-11-17 3 Subtract 7 days
Get me the news from November 10th 2021-11-10 2022-11-10 361 Returned date is in future: needs 1 year subtracted
Get me the news for next week 2022-11-15 2022-11-15 1 Returned date is in future: user specifically asked for future news (for some reason), should give user friendly error response

Near-Solution I've Tried

Here's a function I mocked up in Python for troubleshooting with some detailed comments:

def getArticleDate(input_date):
    today = datetime.date.today()
    diff = (input_date - today).days

    if diff <= 0:
        # === CASE A ===
        # Condition: input_date is in the past
        # Input: User must have been specific enough or used keyword like "last" or "previous"
        # Example input: "from last Wednesday", or "June 19th 2021", or "in the previous month"
        # Handling: None

        return input_date

    if diff <= 7:
        # === CASE B ===
        # Condition: input_date is up to a week in the future
        # Input: User MIGHT have specified day of week
        # Example input: "Wednesday" on any day but Wednesday
        # Handling: Subtract 7 days

        return input_date - datetime.timedelta(days=7)

    if input_date.month == today.month and input_date.year == today.year:
        # === CASE C ===
        # Condition: input_date is within the same month and year as today, but more than 1 week in the future
        # Input: User MIGHT have specified the day of the month but not the month
        # Example input: "on the 21st"
        # Handling: Get the last occurrance of that day of the month
        # Note: Usually, but not necessarily the previous month, e.g. user says "on the 31st" on October 20th and there is no September 31st so must be July 31st

        end_of_month = today
        while end_of_month.day < input_date.day:
            end_of_month = end_of_month.replace(day=1) - datetime.timedelta(days=1)
        return end_of_month.replace(day=input_date.day)

    if input_date.replace(year=input_date.year - 1) < today:
        # === CASE D ===
        # Condition: input_date is more than a week in the future but no more than 1 year
        # Input: User MIGHT have specified day and a month, but not a year
        # Example: "May 10th", or "on 27th September"
        # Handling: Subtract 1 year
        return input_date.replace(year=input_date.year - 1)

    # === CASE E ===
    # Condition: input_date is more than 1 year in the future
    # Input: User must have specified a date more than 1 year in the future
    # Example: "August 21st, 2022"
    # Handling: Raise error
    raise ValueError(
        f"{input_date.isoformat()} is out of range."
    )

This doesn't work in 2 cases:

  1. The user specifies a date less than a year in the future e.g. "tomorrow", or "next month", or "January 30th, 2022". Instead it is handled by CASE B, CASE C, or CASE D.
  2. The user specifies a day of the month, but not the month, AND the input_date is less than a week in the future e.g. "from the 17th" on November 14th. This should be handled by CASE C but instead is handled by CASE B. Switching the order just reverses the problem, making weekday-specifying inputs handled by CASE C instead of CASE B.

Thanks for any help, I've been really stuck on this!


Solution

  • Unfortunately Amazon forces this own NLU resolving engine and not giving out the raw text user actually said. That makes these kinds of tasks nearly impossible to achieve and puts a lot of “User MIGHT have specified”. This brings you to two, quite opposite approaches you can use here: