Deadline & Birthday Reminders in Python

   

It happens to everyone: your car inspection expires without you noticing, your laptop warranty ended three days ago, or your close friend's birthday gets forgotten right on schedule. To solve this problem once and for all, you don't need to install heavy apps or subscribe to cloud services. All you need is a pinch of Python!

In this article, we will build a lightweight, automated, and customizable script that reads a simple Excel (or CSV) file, checks what will expire in the next 7 days, and displays a desktop notification every morning on your computer, grouping events into:

  • 🔴 Expiring TODAY
  • 🟡 Expiring TOMORROW
  • 🔵 Expiring in the coming days
🔗 Do you like Techelopment? Check out the website for all the details!

🛠️ Requirements

To run the script, we will need Python and a couple of very useful libraries:

  • pandas and openpyxl: to easily read and process Excel/CSV files.
  • plyer: a cross-platform library (Windows, macOS, Linux) for displaying desktop notifications.

Install everything with a single command in your terminal:

pip install pandas openpyxl plyer

📄 The Data File (reminders.xlsx)

Create an Excel file named reminders.xlsx in the same folder as the script. The file must have two columns with these exact names: Event and Date (format YYYY-MM-DD or DD/MM/YYYY).

Here is a practical example:

Event Date
Car Inspection 2026-08-27
Serena's Birthday 2026-08-28
TV Warranty Expiration 2026-08-29
Motorcycle Tax 2026-08-30

(Note: you can also use a .csv file, just change the file extension in the code!)


💻 The Complete Python Code

Here is the reminder.py script. Save it on your computer:

from datetime import datetime, timedelta
import os
import pandas as pd
from plyer import notification

# 1. Path configuration and parameters (absolute path based on the script location)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
FILE_PATH = os.path.join(BASE_DIR, "reminders.xlsx")  # Change to 'reminders.csv' if using a CSV file
ADVANCE_DAYS = 7

def load_data(file_path):
    '''Loads the Excel or CSV file into a Pandas DataFrame.'''
    if not os.path.exists(file_path):
        print(f"Error: The file '{file_path}' does not exist.")
        return None

    try:
        if file_path.endswith('.xlsx') or file_path.endswith('.xls'):
            df = pd.read_excel(file_path)
        elif file_path.endswith('.csv'):
            df = pd.read_csv(file_path)
        else:
            print("Unsupported file format. Use .xlsx or .csv")
            return None

        # Convert the 'Date' column to datetime objects
        df['Date'] = pd.to_datetime(df['Date'], dayfirst=True, errors='coerce')
        # Remove rows with invalid dates
        df = df.dropna(subset=['Date'])
        return df
    except Exception as e:
        print(f"Error reading the file: {e}")
        return None

def check_due_dates():
    df = load_data(FILE_PATH)
    if df is None or df.empty:
        return

    today = datetime.now().date()
    future_limit = today + timedelta(days=ADVANCE_DAYS)

    today_items = []
    tomorrow_items = []
    upcoming_items = []

    # 2. Filtering and grouping upcoming events
    for _, row in df.iterrows():
        due_date = row['Date'].date()
        event = row['Event']

        if today <= due_date <= future_limit:
            days_left = (due_date - today).days

            if days_left == 0:
                today_items.append(f"• {event}")
            elif days_left == 1:
                tomorrow_items.append(f"• {event}")
            else:
                date_str = due_date.strftime('%d/%m/%Y')
                upcoming_items.append(f"• {event} ({date_str})")

    # 3. Building the notification message
    message_parts = []

    if today_items:
        message_parts.append("🔴 DUE TODAY:\n" + "\n".join(today_items))
    if tomorrow_items:
        message_parts.append("🟡 DUE TOMORROW:\n" + "\n".join(tomorrow_items))
    if upcoming_items:
        message_parts.append("🔵 UPCOMING DAYS:\n" + "\n".join(upcoming_items))

    # 4. Sending the notification (if there are due events)
    if message_parts:
        notification_text = "\n\n".join(message_parts)
        
        notification.notify(
            title="📅 Reminders & Birthdays",
            message=notification_text,
            app_name="Reminders",
            timeout=10  # The notification stays visible for 10 seconds
        )
        print("Notification sent successfully:\n")
        print(notification_text)
    else:
        print("No upcoming events in the next 7 days!")

if __name__ == "__main__":
    check_due_dates()

🔍 How the Script Works: Step-by-Step Explanation

  1. Smart data loading: The load_data function identifies the file extension (.xlsx or .csv) and parses the Date column, converting it into standard datetime format using pd.to_datetime. We use os.path.abspath(__file__) to make sure the script always locates the file within its own folder.
  2. Date comparison: We calculate today's date (today) and the 7-day limit date (future_limit). The script loops through each row and calculates the remaining days (days_left).
  3. Dynamic grouping:
    • If days_left == 0 → placed in the TODAY section.
    • If days_left == 1 → placed in the TOMORROW section.
    • If between 2 and 7 → placed in the UPCOMING DAYS section along with the formatted date (e.g., 05/08/2026).
  4. Desktop Notification: Using the plyer library, we send a native operating system alert (Windows, macOS, or Linux) that appears directly in the bottom-right corner of your screen.

⏰ How to Run It Automatically Every Morning

To turn this script into a true personal assistant, we need to make it run automatically every time we turn on the computer in the morning:

On Windows (Task Scheduler)

  1. Search for "Task Scheduler" in the Start menu.
  2. Click on Create Basic Task... in the right-hand panel.
  3. Give it a name (e.g., Due Date Reminders) and set the trigger to "When the computer starts" or "Daily" (e.g., at 09:00 AM).
  4. For the action, select Start a program:
    • Program/script: enter the path to your Python executable (e.g., C:\Python310\python.exe or pythonw.exe to hide the black terminal window).
    • Add arguments: the path to your script (e.g., C:\MyScripts\reminder.py).
    • Start in (optional): the folder containing the script (e.g., C:\MyScripts\, without quotes).

On macOS / Linux (Crontab)

Open the terminal and type crontab -e. Add this line to run it every day at 09:00 AM:

0 9 * * * /usr/bin/python3 /path/to/your/script/reminder.py

⚠️ Troubleshooting: File Not Found with Task Scheduler

When the script is executed by Task Scheduler, Windows sets the default working directory to C:\Windows\System32. As a result, a relative path like FILE_PATH = "reminders.xlsx" will look for the file inside System32 and fail.

In the code above, we integrated the optimal solution by making the path dynamic:

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
FILE_PATH = os.path.join(BASE_DIR, "reminders.xlsx")

This way, regardless of how the script is launched, it will always look for the reminders.xlsx file in the folder where the Python code resides.

💡 Bonus Tip: Using pythonw.exe
If you use python.exe on Windows, you will see a black command prompt window pop up for a second. If you want a completely quiet and invisible background experience (until the notification pops up), set pythonw.exe as the program in Task Scheduler (it is located in the same folder as the standard Python executable).

Have fun customizing the script! You can add custom icons to the notification or even extend the code to send you an email or a Telegram message.

Happy coding! 🚀



Follow me #techelopment

Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment