Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes
Sponsored Reserved space — layout preview until AdSense is connected

How to Find Stale GitHub Issues in Python

Filter a list of GitHub issues to find those not updated within a configurable number of days using Python datetime arithmetic.

Easy Python 3.9+ Jun 28, 2026 Automation & scripting 2 views 0 copies

Python code

47 lines
Python 3.9+
import os
from datetime import datetime, timezone, timedelta
import re

# Simulated GitHub issue data structure
SAMPLE_ISSUES = [
    {"number": 101, "title": "Login button not working", "updated_at": "2025-06-01T12:00:00Z", "assignee": "alice"},
    {"number": 102, "title": "Fix database migration error", "updated_at": "2025-10-20T08:30:00Z", "assignee": None},
    {"number": 103, "title": "Update API documentation", "updated_at": "2025-10-15T14:15:00Z", "assignee": "bob"},
    {"number": 104, "title": "Refactor authentication module", "updated_at": "2025-09-01T09:00:00Z", "assignee": None},
]

STALE_DAYS = 30  # Consider issues stale if not updated in this many days

def parse_github_date(date_str):
    """Parse GitHub ISO 8601 date string to datetime object."""
    # Remove trailing Z and add UTC timezone
    if date_str.endswith('Z'):
        date_str = date_str[:-1] + '+00:00'
    return datetime.fromisoformat(date_str)

def is_stale(issue, stale_days):
    """Check if an issue is stale based on last update time."""
    last_updated = parse_github_date(issue["updated_at"])
    now = datetime.now(timezone.utc)
    return now - last_updated > timedelta(days=stale_days)

def find_stale_issues(issues, stale_days=STALE_DAYS):
    """Filter list of issues to find only stale ones."""
    stale_issues = []
    for issue in issues:
        if is_stale(issue, stale_days):
            stale_issues.append(issue)
    return stale_issues

if __name__ == "__main__":
    stale_issues = find_stale_issues(SAMPLE_ISSUES)
    
    print(f"Checking for issues stale more than {STALE_DAYS} days...\n")
    
    if not stale_issues:
        print("No stale issues found.")
    else:
        print(f"Found {len(stale_issues)} stale issue(s):\n")
        for issue in stale_issues:
            assignee = issue.get("assignee", "unassigned")
            print(f"  #{issue['number']}: {issue['title']} (last updated: {issue['updated_at']}, assignee: {assignee})")

Output

stdout
Checking for issues stale more than 30 days...

Found 2 stale issue(s):

  #101: Login button not working (last updated: 2025-06-01T12:00:00Z, assignee: alice)
  #104: Refactor authentication module (last updated: 2025-09-01T09:00:00Z, assignee: unassigned)

How it works

The script parses GitHub's ISO 8601 date strings into datetime objects using datetime.fromisoformat() after converting the trailing 'Z' to '+00:00'. It subtracts the parsed update time from the current UTC time and compares the resulting timedelta to a stale_days threshold. The is_stale helper encapsulates the check, and find_stale_issues builds a filtered list. This approach works entirely with the Python standard library so no third-party packages are needed.

Common mistakes

  • Forgetting to handle the trailing 'Z' in GitHub's date strings before parsing with `fromisoformat`.
  • Comparing naive datetimes without timezone info to aware datetimes, causing a `TypeError`.
  • Hardcoding the stale-days threshold instead of making it a parameter like `stale_days`.

Variations

  1. Use `dateutil.parser.isoparse` from the `python-dateutil` package for more robust date parsing.
  2. Wrap the logic in a class like `StaleIssueDetector` to manage configuration and issue data together.

Real-world use cases

  • Running a weekly cron job to tag issues that haven't been updated in 30 days and assign them to a triage team.
  • Integrating into a CI/CD pipeline that auto-closes stale PRs or issues after a grace period.
  • Building a dashboard widget that highlights inactive items across your repositories for maintainers.

Sponsored

Sponsored Reserved space — layout preview until AdSense is connected

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Automation & scripting

Related tutorials and quizzes for this topic.