{"id":"dates-differences","slug":"differences","title":"Comparing and calculating with dates","text":"Datetimes can be compared and subtracted, and time can be added to them. The `datetime` type takes care of the calendar: month lengths, leap years, the turn of the year.\n\n### Comparing\n\nThe comparison operators work on datetimes. An earlier moment is smaller than a later one:\n\n```python\nfrom datetime import datetime\n\ndeadline = datetime(2026, 12, 14, 9, 0)\nsubmitted = datetime(2026, 12, 14, 8, 45)\n\nif submitted <= deadline:\n    print(\"Submitted in time\")\nelse:\n    print(\"Too late\")\n```\n\n```output\nSubmitted in time\n```\n\n### The difference: timedelta\n\nSubtracting one datetime from another gives a **`timedelta`**: a length of time, rather than a moment. Its attribute `days` holds the whole days, and `seconds` holds the rest, less than a day, in seconds:\n\n```python\nfrom datetime import datetime\n\nstart = datetime(2026, 9, 1)\nend = datetime(2026, 12, 18, 12, 0)\ndifference = end - start\nprint(difference)\nprint(difference.days)\nprint(difference.seconds)\n```\n\n```output\n108 days, 12:00:00\n108\n43200\n```\n\nA timedelta has no attribute for hours, and none for months or years either, because months and years don't all have the same length:\n\n```python\nfrom datetime import datetime\n\ndifference = datetime(2026, 3, 1, 18, 0) - datetime(2026, 3, 1, 9, 0)\nprint(difference.hours)\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 4, in <module>\n    print(difference.hours)\n          ^^^^^^^^^^^^^^^^\nAttributeError: 'datetime.timedelta' object has no attribute 'hours'\n```\n\nCalculate hours from the seconds yourself: `difference.seconds // 3600` is 9 here.\n\n### Adding time\n\nTo move a moment forward or back, add or subtract a timedelta. You make one with `timedelta(...)`, giving the units you want as keyword arguments, like `end=` in `print`: `days`, `weeks`, `hours`, `minutes`. Import `timedelta` from the module too:\n\n```python\nfrom datetime import datetime, timedelta\n\norder = datetime(2026, 11, 27, 16, 0)\nprint(\"Delivery:\", order + timedelta(days=3))\nprint(\"Return by:\", order + timedelta(weeks=4))\nprint(\"Reminder:\", order - timedelta(hours=20))\n```\n\n```output\nDelivery: 2026-11-30 16:00:00\nReturn by: 2026-12-25 16:00:00\nReminder: 2026-11-26 20:00:00\n```\n\nAdding a plain number, as in `order + 3`, is a `TypeError`: Python can't know whether you mean days, hours or seconds.\n","task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"from datetime import datetime, timedelta\n\nstart = datetime(2026, 1, 30)\nprint(start + timedelta(days=3))\nprint((datetime(2026, 3, 1) - start).days)\nprint(start < datetime(2026, 1, 29))\n","solution":"from datetime import datetime, timedelta\n\nstart = datetime(2026, 1, 30)\nprint(start + timedelta(days=3))\nprint((datetime(2026, 3, 1) - start).days)\nprint(start < datetime(2026, 1, 29))\n","hints":["January has 31 days, so three days after January 30 is in February.","From January 30 to March 1 is 2 days of January, all 28 days of February in 2026, and 0 more.","An earlier moment is smaller. Is January 30 earlier than January 29?"],"tests":[{"name":"Output","stdin":"","expect":"2026-02-02 00:00:00\n30\nFalse","hidden":false}],"require":[],"forbid":[],"lines":["2026-02-02 00:00:00","30","False"],"more":[{"task":"A library lends books for a given number of days. Write a function `due_date(borrowed, days)` that gets the day the book was borrowed, as a datetime, and the length of the loan in days, and returns the datetime when the book is due.\n\n`due_date(datetime(2026, 2, 20), 14)` returns the datetime for March 6, 2026.\n","kind":"code","seed":"from datetime import datetime, timedelta\n\n\ndef due_date(borrowed, days):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(due_date(datetime(2026, 2, 20), 14))\n","solution":"from datetime import datetime, timedelta\n\n\ndef due_date(borrowed, days):\n    return borrowed + timedelta(days=days)\n\n\nif __name__ == \"__main__\":\n    print(due_date(datetime(2026, 2, 20), 14))\n","hints":["The due date is the day of borrowing plus a timedelta of that many days.","`timedelta(days=days)`: the name before `=` is the unit, and the one after is your parameter."],"tests":[{"name":"print(due_date(datetime(2026, 2, 20), 14))","stdin":"","call":"print(due_date(datetime(2026, 2, 20), 14))\n","expect":"2026-03-06 00:00:00","hidden":false},{"name":"print(due_date(datetime(2026, 12, 20), 21))","stdin":"","call":"print(due_date(datetime(2026, 12, 20), 21))\n","expect":"2027-01-10 00:00:00","hidden":true},{"name":"print(due_date(datetime(2028, 2, 20), 10))","stdin":"","call":"print(due_date(datetime(2028, 2, 20), 10))\n","expect":"2028-03-01 00:00:00","hidden":true},{"name":"due_date(datetime(2026, 5, 5), 1) == datetime(2026, 5, 6)","stdin":"","call":"due_date(datetime(2026, 5, 5), 1) == datetime(2026, 5, 6)\n","expect":"True","hidden":true,"returns":true}],"require":[],"forbid":[]},{"task":"A shop gives a warranty of 730 days from the day of purchase. Write a program that asks for the date of purchase and prints the last day of the warranty, and then either how many days are left or how many days ago it ended. The program calculates from the day stored in `today` in the starter code (so that its output is the same whatever the date really is). For example:\n\n```\nPurchase year: 2025\nPurchase month: 3\nPurchase day: 14\nWarranty ends 14.3.2027\nDays left: 150\n```\n\nWhen the warranty has ended, the last line is like `The warranty ended 136 days ago`. On the last day itself, there are 0 days left.\n","kind":"code","seed":"from datetime import datetime, timedelta\n\ntoday = datetime(2026, 10, 15)\n","solution":"from datetime import datetime, timedelta\n\ntoday = datetime(2026, 10, 15)\n\nyear = int(input(\"Purchase year: \"))\nmonth = int(input(\"Purchase month: \"))\nday = int(input(\"Purchase day: \"))\nend = datetime(year, month, day) + timedelta(days=730)\nprint(f\"Warranty ends {end.day}.{end.month}.{end.year}\")\nif end >= today:\n    print(\"Days left:\", (end - today).days)\nelse:\n    print(f\"The warranty ended {(today - end).days} days ago\")\n","hints":["Make the purchase date with `datetime(year, month, day)`, and add `timedelta(days=730)` to get the end.","Print the end date from its attributes: `f\"Warranty ends {end.day}.{end.month}.{end.year}\"`.","Compare `end` with `today`. If the end is still ahead, the days left are `(end - today).days`; otherwise subtract the other way round."],"tests":[{"name":"Test 1","stdin":"2025\n3\n14\n","expect":"Purchase year: 2025\nPurchase month: 3\nPurchase day: 14\nWarranty ends 14.3.2027\nDays left: 150","hidden":false},{"name":"Test 2","stdin":"2024\n6\n1\n","expect":"Purchase year: 2024\nPurchase month: 6\nPurchase day: 1\nWarranty ends 1.6.2026\nThe warranty ended 136 days ago","hidden":true},{"name":"Test 3","stdin":"2026\n10\n1\n","expect":"Purchase year: 2026\nPurchase month: 10\nPurchase day: 1\nWarranty ends 30.9.2028\nDays left: 716","hidden":true},{"name":"Test 4","stdin":"2024\n10\n15\n","expect":"Purchase year: 2024\nPurchase month: 10\nPurchase day: 15\nWarranty ends 15.10.2026\nDays left: 0","hidden":true}],"require":[],"forbid":[]}]}