{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1d32564c",
   "metadata": {},
   "source": "# Datetime basics\n\nPython's `datetime` module gives you four types to represent moments and durations: `date`, `time`, `datetime`, and `timedelta`. This notebook covers all four — how to build them, extract parts from them, do arithmetic with them, and compare them.\n\nEverything here is *naive* — no time zones. Time zones come in the [third notebook](https://agilearn.co.uk/guides/dates-and-times/learn/03-time-zones-with-zoneinfo); the basics first."
  },
  {
   "cell_type": "markdown",
   "id": "a00f067d",
   "metadata": {},
   "source": "## `date` — a calendar date with no time\n\nJust a year, month, and day. Useful when you don't care what time of day something happened."
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a6d3587",
   "metadata": {},
   "outputs": [],
   "source": "from datetime import date\n\nbirthday = date(2026, 4, 21)\nprint(birthday)\nprint(date.today())"
  },
  {
   "cell_type": "markdown",
   "id": "264f1605",
   "metadata": {},
   "source": "`date(year, month, day)` takes integers. `date.today()` returns today's date according to the system clock.\n\nDates expose their parts as attributes:"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f5efcb4",
   "metadata": {},
   "outputs": [],
   "source": "d = date(2026, 4, 21)\nprint(d.year, d.month, d.day)\nprint(d.weekday())          # Monday is 0, Sunday is 6\nprint(d.isoformat())        # canonical YYYY-MM-DD string"
  },
  {
   "cell_type": "markdown",
   "id": "e0140e75",
   "metadata": {},
   "source": "## `time` — a clock time with no date\n\nA time-of-day: hour, minute, second, microsecond. Far less commonly useful than `date` or `datetime`, but occasionally the right shape for \"opening hours\" or \"daily alarm\"."
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "277d60ea",
   "metadata": {},
   "outputs": [],
   "source": "from datetime import time\n\nt = time(14, 30, 0)\nprint(t, t.hour, t.minute)"
  },
  {
   "cell_type": "markdown",
   "id": "23d5fb07",
   "metadata": {},
   "source": "## `datetime` — a date *and* a time\n\nThe one you'll use most. A specific moment, precise to the microsecond."
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d4e0f7c2",
   "metadata": {},
   "outputs": [],
   "source": "from datetime import datetime\n\nmoment = datetime(2026, 4, 21, 14, 30, 0)\nprint(moment)\n\nnow = datetime.now()\nprint(now)"
  },
  {
   "cell_type": "markdown",
   "id": "5e32911f",
   "metadata": {},
   "source": "A `datetime` has everything a `date` has plus everything a `time` has — `.year`, `.month`, `.day`, `.hour`, `.minute`, `.second`, `.microsecond`. You can extract the calendar or clock portion separately:"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa1cdb08",
   "metadata": {},
   "outputs": [],
   "source": "print(moment.date())    # date(2026, 4, 21)\nprint(moment.time())    # time(14, 30)"
  },
  {
   "cell_type": "markdown",
   "id": "4806e04b",
   "metadata": {},
   "source": "## `timedelta` — a duration\n\nA span of time: days, seconds, microseconds (and for your convenience, `hours`, `minutes`, `weeks` on construction). This is what you get back when you subtract two datetimes, and what you add to shift a datetime by an interval."
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dbf602ad",
   "metadata": {},
   "outputs": [],
   "source": "from datetime import timedelta\n\none_week = timedelta(weeks=1)\nninety_minutes = timedelta(minutes=90)\n\nprint(one_week)\nprint(ninety_minutes)\nprint(one_week.total_seconds())"
  },
  {
   "cell_type": "markdown",
   "id": "576c9d87",
   "metadata": {},
   "source": "Arithmetic. A datetime plus a timedelta is a datetime:"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c0b10873",
   "metadata": {},
   "outputs": [],
   "source": "start = datetime(2026, 4, 21, 9, 0)\nprint(start + timedelta(hours=8))\nprint(start + timedelta(days=7))"
  },
  {
   "cell_type": "markdown",
   "id": "681eb6a6",
   "metadata": {},
   "source": "A datetime minus a datetime is a timedelta:"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4c7208d2",
   "metadata": {},
   "outputs": [],
   "source": "a = datetime(2026, 4, 21, 17, 30)\nb = datetime(2026, 4, 21, 9, 0)\ngap = a - b\nprint(gap)\nprint(gap.total_seconds(), \"seconds\")"
  },
  {
   "cell_type": "markdown",
   "id": "7e23c7dc",
   "metadata": {},
   "source": "Two things that *don't* work on `timedelta`:\n\n- **Months and years.** A \"month\" isn't a fixed number of days. `timedelta(months=1)` raises. For calendar-based arithmetic (\"one month from today\") reach for `dateutil.relativedelta` or compute the target date directly.\n- **Comparing a `timedelta` with a number.** `timedelta(hours=1) > 30` raises. Compare to another `timedelta` or use `.total_seconds()`."
  },
  {
   "cell_type": "markdown",
   "id": "aeece0a9",
   "metadata": {},
   "source": "## Comparing dates and datetimes\n\nAll the comparison operators work on same-type values:"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3e44ec29",
   "metadata": {},
   "outputs": [],
   "source": "d1 = date(2026, 4, 21)\nd2 = date(2026, 5, 1)\nprint(d1 < d2)\nprint(d1 == date(2026, 4, 21))\n\ndates = [date(2026, 1, 1), date(2025, 12, 31), date(2026, 4, 21)]\nprint(sorted(dates))"
  },
  {
   "cell_type": "markdown",
   "id": "41a3bd77",
   "metadata": {},
   "source": "Mixing types won't work — `date(2026, 4, 21) < datetime(2026, 4, 21, 0, 0)` raises. Convert one to the other first, or compare dates against dates and datetimes against datetimes."
  },
  {
   "cell_type": "markdown",
   "id": "39e3be58",
   "metadata": {},
   "source": "## Exercise\n\nGiven a list of `datetime`s representing user login times across a week, write code that:\n\n1. Filters to the logins that happened on a Monday.\n2. Finds the time range between the earliest and latest login.\n3. Counts how many logins happened in the afternoon (13:00 onwards).\n\nUse the `logins` list provided below."
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8fd56163",
   "metadata": {},
   "outputs": [],
   "source": "from datetime import datetime\n\nlogins = [\n    datetime(2026, 4, 20, 9, 15),     # Mon\n    datetime(2026, 4, 20, 14, 0),     # Mon\n    datetime(2026, 4, 21, 8, 30),     # Tue\n    datetime(2026, 4, 22, 16, 45),    # Wed\n    datetime(2026, 4, 23, 11, 0),     # Thu\n    datetime(2026, 4, 24, 10, 30),    # Fri\n    datetime(2026, 4, 27, 15, 20),    # Mon\n]\n\n# Your code here\n"
  },
  {
   "cell_type": "markdown",
   "id": "d0add9fe",
   "metadata": {},
   "source": "<details>\n<summary>Solution</summary>\n\n```python\n# 1. Monday-only logins (weekday() == 0)\nmondays = [dt for dt in logins if dt.weekday() == 0]\n\n# 2. Range between earliest and latest\nspan = max(logins) - min(logins)\n\n# 3. Afternoon logins (hour >= 13)\nafternoon = sum(1 for dt in logins if dt.hour >= 13)\n\nprint(f\"Mondays: {len(mondays)}\")\nprint(f\"Span: {span}\")\nprint(f\"Afternoon logins: {afternoon}\")\n```\n</details>"
  },
  {
   "cell_type": "markdown",
   "id": "3fe3a46e",
   "metadata": {},
   "source": "## Recap\n\n- `date` for calendar dates, `time` for clock times, `datetime` for both. `timedelta` for durations.\n- `datetime.now()` and `date.today()` give you the current moment.\n- Datetime arithmetic: `datetime + timedelta` is a datetime; `datetime - datetime` is a timedelta.\n- `timedelta` doesn't understand months or years — they're not fixed durations.\n- You can't mix `date` and `datetime` in comparisons; convert first.\n\nNext: [Parsing and formatting](https://agilearn.co.uk/guides/dates-and-times/learn/02-parsing-and-formatting), turning strings into datetimes and back."
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}